/**
  * Function to actually build the form
  *
  * @return None
  * @access public
  */
 public function buildQuickForm()
 {
     $this->addFormRule(array('CRM_Mailchimp_Form_Setting', 'formRule'), $this);
     CRM_Core_Resources::singleton()->addStyleFile('uk.co.vedaconsulting.mailchimp', 'css/mailchimp.css');
     $webhook_url = CRM_Utils_System::url('civicrm/mailchimp/webhook', 'reset=1', TRUE, NULL, FALSE, TRUE);
     $this->assign('webhook_url', 'Webhook URL - ' . $webhook_url);
     // Add the API Key Element
     $this->addElement('text', 'api_key', ts('API Key'), array('size' => 48));
     // Add the User Security Key Element
     $this->addElement('text', 'security_key', ts('Security Key'), array('size' => 24));
     // Add Enable or Disable Debugging
     $enableOptions = array(1 => ts('Yes'), 0 => ts('No'));
     $this->addRadio('enable_debugging', ts('Enable Debugging'), $enableOptions, NULL);
     // Create the Submit Button.
     $buttons = array(array('type' => 'submit', 'name' => ts('Save & Test')));
     $groups = CRM_Mailchimp_Utils::getGroupsToSync(array(), null, $membership_only = TRUE);
     foreach ($groups as $group_id => $details) {
         $list = new Mailchimp_Lists(CRM_Mailchimp_Utils::mailchimp());
         $webhookoutput = $list->webhooks($details['list_id']);
         if ($webhookoutput[0]['sources']['api'] == 1) {
             CRM_Mailchimp_Utils::checkDebug('CRM_Mailchimp_Form_Setting - API is set in Webhook setting for listID', $details['list_id']);
             $listID = $details['list_id'];
             CRM_Core_Session::setStatus(ts('API is set in Webhook setting for listID %1', array(1 => $listID)), ts('Error'), 'error');
             break;
         }
     }
     // Add the Buttons.
     $this->addButtons($buttons);
 }
 function run()
 {
     $my_key = CRM_Core_BAO_Setting::getItem(self::MC_SETTING_GROUP, 'security_key', NULL, FALSE);
     CRM_Mailchimp_Utils::checkDebug('CRM_Mailchimp_Page_WebHook run $my_key= ', $my_key);
     if (CRM_Core_Config::singleton()->userPermissionClass->isModulePermissionSupported() && !CRM_Mailchimp_Permission::check('allow webhook posts')) {
         CRM_Core_Error::fatal();
     }
     // Check the key
     // @todo is this a DOS attack vector? seems a lot of work for saying 403, go away, to a robot!
     if (!isset($_GET['key']) || $_GET['key'] != $my_key) {
         CRM_Core_Error::fatal();
     }
     if (!empty($_POST['data']['list_id']) && !empty($_POST['type'])) {
         $requestType = $_POST['type'];
         $requestData = $_POST['data'];
         // Return if API is set in webhook setting for lists
         $list = new Mailchimp_Lists(CRM_Mailchimp_Utils::mailchimp());
         $webhookoutput = $list->webhooks($requestData['list_id']);
         if ($webhookoutput[0]['sources']['api'] == 1) {
             CRM_Mailchimp_Utils::checkDebug('CRM_Mailchimp_Page_WebHook run API is set in Webhook setting for listID', $requestData['list_id']);
             return;
         }
         switch ($requestType) {
             case 'subscribe':
             case 'unsubscribe':
             case 'profile':
                 // Create/Update contact details in CiviCRM
                 $delay = $requestType == 'profile';
                 $contactID = CRM_Mailchimp_Utils::updateContactDetails($requestData['merges'], $delay);
                 $contactArray = array($contactID);
                 // Subscribe/Unsubscribe to related CiviCRM groups
                 self::manageCiviCRMGroupSubcription($contactID, $requestData, $requestType);
                 CRM_Mailchimp_Utils::checkDebug('Start - CRM_Mailchimp_Page_WebHook run $_POST= ', $_POST);
                 CRM_Mailchimp_Utils::checkDebug('Start - CRM_Mailchimp_Page_WebHook run $contactID= ', $contactID);
                 CRM_Mailchimp_Utils::checkDebug('Start - CRM_Mailchimp_Page_WebHook run $requestData= ', $requestData);
                 CRM_Mailchimp_Utils::checkDebug('Start - CRM_Mailchimp_Page_WebHook run $requestType= ', $requestType);
                 break;
             case 'upemail':
                 // Mailchimp Email Update event
                 // Try to find the email address
                 $email = new CRM_Core_BAO_Email();
                 $email->get('email', $requestData['old_email']);
                 CRM_Mailchimp_Utils::checkDebug('CRM_Mailchimp_Page_WebHook run- case upemail $requestData[old_email]= ', $requestData['old_email']);
                 // If the Email was found.
                 if (!empty($email->contact_id)) {
                     $email->email = $requestData['new_email'];
                     $email->save();
                     CRM_Mailchimp_Utils::checkDebug('CRM_Mailchimp_Page_WebHook run- case upemail inside condition $requestData[new_email]= ', $requestData['new_email']);
                 }
                 break;
             case 'cleaned':
                 // Try to find the email address
                 $email = new CRM_Core_BAO_Email();
                 $email->get('email', $requestData['email']);
                 CRM_Mailchimp_Utils::checkDebug('CRM_Mailchimp_Page_WebHook run - case cleaned $requestData[new_email]= ', $requestData['email']);
                 // If the Email was found.
                 if (!empty($email->contact_id)) {
                     $email->on_hold = 1;
                     $email->holdEmail($email);
                     $email->save();
                     CRM_Mailchimp_Utils::checkDebug('CRM_Mailchimp_Page_WebHook run - case cleaned inside condition $email= ', $email);
                     CRM_Mailchimp_Utils::checkDebug('CRM_Mailchimp_Page_WebHook run - case cleaned inside condition $requestData[new_email]= ', $requestData['email']);
                 }
                 break;
             default:
                 // unhandled webhook
                 CRM_Mailchimp_Utils::checkDebug('End- CRM_Mailchimp_Page_WebHook run $contactID= ', $contactID);
                 CRM_Mailchimp_Utils::checkDebug('End- CRM_Mailchimp_Page_WebHook run $requestData= ', $requestData);
                 CRM_Mailchimp_Utils::checkDebug('End- CRM_Mailchimp_Page_WebHook run $requestType= ', $requestType);
                 CRM_Mailchimp_Utils::checkDebug('End - CRM_Mailchimp_Page_WebHook run $email= ', $email);
         }
     }
     // Return the JSON output
     header('Content-type: application/json');
     $data = NULL;
     // We should ideally throw some status
     print json_encode($data);
     CRM_Utils_System::civiExit();
 }
 /**
  * Mailchimp in their wisdom changed all the Ids for interests.
  *
  * So we have to map on names and then update our stored Ids.
  *
  * Also change cronjobs.
  */
 public function upgrade_20()
 {
     $this->ctx->log->info('Applying update to v2.0 Updating Mailchimp Interest Ids to fit their new API');
     // New
     $api = CRM_Mailchimp_Utils::getMailchimpApi();
     // Old
     $mcLists = new Mailchimp_Lists(CRM_Mailchimp_Utils::mailchimp());
     // Use new API to get lists. Allow for 10,000 lists so we don't bother
     // batching.
     $lists = [];
     foreach ($api->get("/lists", ['fields' => 'lists.id,lists.name', 'count' => 10000])->data->lists as $list) {
         $lists[$list->id] = ['name' => $list->name];
     }
     $queries = [];
     // Loop lists.
     foreach (array_keys($lists) as $list_id) {
         // Fetch Interest categories.
         $categories = $api->get("/lists/{$list_id}/interest-categories", ['count' => 10000, 'fields' => 'categories.id,categories.title'])->data->categories;
         if (!$categories) {
             continue;
         }
         // Old: fetch all categories (groupings) and interests (groups) in one go:
         $old = $mcLists->interestGroupings($list_id);
         // New: fetch interests for each category.
         foreach ($categories as $category) {
             // $lists[$list_id]['categories'][$category->id] = ['name' => $category->title];
             // Match this category by name with the old 'groupings'
             $matched_old_grouping = FALSE;
             foreach ($old as $old_grouping) {
                 if ($old_grouping['name'] == $category->title) {
                     $matched_old_grouping = $old_grouping;
                     break;
                 }
             }
             if ($matched_old_grouping) {
                 // Found a match.
                 $cat_queries[] = ['list_id' => $list_id, 'old' => $matched_old_grouping['id'], 'new' => $category->id];
                 // Now do interests (old: groups)
                 $interests = $api->get("/lists/{$list_id}/interest-categories/{$category->id}/interests", ['fields' => 'interests.id,interests.name', 'count' => 10000])->data->interests;
                 foreach ($interests as $interest) {
                     // Can we find this interest by name?
                     $matched_old_group = FALSE;
                     foreach ($matched_old_grouping['groups'] as $old_group) {
                         if ($old_group['name'] == $interest->name) {
                             $int_queries[] = ['list_id' => $list_id, 'old' => $old_group['id'], 'new' => $interest->id];
                             break;
                         }
                     }
                 }
             }
         }
     }
     foreach ($cat_queries as $params) {
         CRM_Core_DAO::executeQuery('UPDATE civicrm_value_mailchimp_settings ' . 'SET mc_grouping_id = %1 ' . 'WHERE mc_list_id = %2 AND mc_grouping_id = %3;', [1 => [$params['new'], 'String'], 2 => [$params['list_id'], 'String'], 3 => [$params['old'], 'String']]);
     }
     foreach ($int_queries as $params) {
         CRM_Core_DAO::executeQuery('UPDATE civicrm_value_mailchimp_settings ' . 'SET mc_group_id = %1 ' . 'WHERE mc_list_id = %2 AND mc_group_id = %3;', [1 => [$params['new'], 'String'], 2 => [$params['list_id'], 'String'], 3 => [$params['old'], 'String']]);
     }
     // Now cron jobs. Delete all mailchimp ones.
     $result = civicrm_api3('Job', 'get', array('sequential' => 1, 'api_entity' => "mailchimp"));
     if ($result['count']) {
         // Should only be one, but just in case...
         foreach ($result['values'] as $old) {
             // Double check id exists!
             if (!empty($old['id'])) {
                 civicrm_api3('Job', 'delete', ['id' => $old['id']]);
             }
         }
     }
     // Create Push Sync job.
     $params = array('sequential' => 1, 'name' => 'Mailchimp Push Sync', 'description' => 'Sync contacts between CiviCRM and MailChimp, assuming CiviCRM to be correct. Please understand the implications before using this.', 'run_frequency' => 'Daily', 'api_entity' => 'Mailchimp', 'api_action' => 'pushsync', 'is_active' => 0);
     $result = civicrm_api3('job', 'create', $params);
     // Create Pull Sync job.
     $params = array('sequential' => 1, 'name' => 'Mailchimp Pull Sync', 'description' => 'Sync contacts between CiviCRM and MailChimp, assuming Mailchimp to be correct. Please understand the implications before using this.', 'run_frequency' => 'Daily', 'api_entity' => 'Mailchimp', 'api_action' => 'pullsync', 'is_active' => 0);
     $result = civicrm_api3('job', 'create', $params);
     return TRUE;
 }
 static function subscribeOrUnsubsribeToMailchimpList($groupDetails, $contactID, $action)
 {
     CRM_Mailchimp_Utils::checkDebug('Start-CRM_Mailchimp_Utils subscribeOrUnsubsribeToMailchimpList $groupDetails', $groupDetails);
     CRM_Mailchimp_Utils::checkDebug('Start-CRM_Mailchimp_Utils subscribeOrUnsubsribeToMailchimpList $contactID', $contactID);
     CRM_Mailchimp_Utils::checkDebug('Start-CRM_Mailchimp_Utils subscribeOrUnsubsribeToMailchimpList $action', $action);
     if (empty($groupDetails) || empty($contactID) || empty($action)) {
         return NULL;
     }
     // We need to get contact's email before subscribing in Mailchimp
     $contactParams = array('version' => 3, 'id' => $contactID);
     $contactResult = civicrm_api('Contact', 'get', $contactParams);
     // This is the primary email address of the contact
     $email = $contactResult['values'][$contactID]['email'];
     if (empty($email)) {
         // Its possible to have contacts in CiviCRM without email address
         // and add to group offline
         return;
     }
     // Optional merges for the email (FNAME, LNAME)
     $merge = array('FNAME' => $contactResult['values'][$contactID]['first_name'], 'LNAME' => $contactResult['values'][$contactID]['last_name']);
     $listID = $groupDetails['list_id'];
     $grouping_id = $groupDetails['grouping_id'];
     $group_id = $groupDetails['group_id'];
     if (!empty($grouping_id) and !empty($group_id)) {
         $merge_groups[$grouping_id] = array('id' => $groupDetails['grouping_id'], 'groups' => array());
         $merge_groups[$grouping_id]['groups'][] = CRM_Mailchimp_Utils::getMCGroupName($listID, $grouping_id, $group_id);
         // remove the significant array indexes, in case Mailchimp cares.
         $merge['groupings'] = array_values($merge_groups);
     }
     // Send Mailchimp Lists API Call.
     $list = new Mailchimp_Lists(CRM_Mailchimp_Utils::mailchimp());
     switch ($action) {
         case "subscribe":
             // http://apidocs.mailchimp.com/api/2.0/lists/subscribe.php
             try {
                 $result = $list->subscribe($listID, array('email' => $email), $merge, $email_type = 'html', $double_optin = FALSE, $update_existing = FALSE, $replace_interests = TRUE, $send_welcome = FALSE);
             } catch (Exception $e) {
                 // Don't display if the error is that we're already subscribed.
                 $message = $e->getMessage();
                 if ($message !== $email . ' is already subscribed to the list.') {
                     CRM_Core_Session::setStatus($message);
                 }
             }
             break;
         case "unsubscribe":
             // https://apidocs.mailchimp.com/api/2.0/lists/unsubscribe.php
             try {
                 $result = $list->unsubscribe($listID, array('email' => $email), $delete_member = false, $send_goodbye = false, $send_notify = false);
             } catch (Exception $e) {
                 CRM_Core_Session::setStatus($e->getMessage());
             }
             break;
     }
     CRM_Mailchimp_Utils::checkDebug('End-CRM_Mailchimp_Utils subscribeOrUnsubsribeToMailchimpList $groupDetails', $groupDetails);
     CRM_Mailchimp_Utils::checkDebug('End-CRM_Mailchimp_Utils subscribeOrUnsubsribeToMailchimpList $contactID', $contactID);
     CRM_Mailchimp_Utils::checkDebug('End-CRM_Mailchimp_Utils subscribeOrUnsubsribeToMailchimpList $action', $action);
 }
/**
 * Mailchimp Get all Mailchimp Lists & Groups API
 *
 * @param array $params
 * @return array API result descriptor
 * @see civicrm_api3_create_success
 * @see civicrm_api3_create_error
 * @throws API_Exception
 */
function civicrm_api3_mailchimp_getlistsandgroups($params)
{
    $mcLists = new Mailchimp_Lists(CRM_Mailchimp_Utils::mailchimp());
    $results = $mcLists->getList();
    $lists = array();
    foreach ($results['data'] as $list) {
        $lists[$list['id']]['name'] = $list['name'];
        $lists[$list['id']]['id'] = $list['id'];
        $params = array('id' => $list['id']);
        $group_results = civicrm_api3_mailchimp_getgroups($params);
        if (!empty($group_results)) {
            $lists[$list['id']]['grouping'] = $group_results['values'];
        }
    }
    return civicrm_api3_create_success($lists);
}
/**
 * CiviCRM to Mailchimp Sync
 *
 * @param array $params
 * @return array API result descriptor
 * @see civicrm_api3_create_success
 * @see civicrm_api3_create_error
 * @throws API_Exception
 */
function civicrm_api3_mailchimp_sync($params)
{
    $groups = CRM_Mailchimp_Utils::getGroupsToSync(array(), null, $membership_only = TRUE);
    foreach ($groups as $group_id => $details) {
        $list = new Mailchimp_Lists(CRM_Mailchimp_Utils::mailchimp());
        $webhookoutput = $list->webhooks($details['list_id']);
        if ($webhookoutput[0]['sources']['api'] == 1) {
            return civicrm_api3_create_error('civicrm_api3_mailchimp_sync -  API is set in Webhook setting for listID ' . $details['list_id'] . ' Please uncheck API');
        }
    }
    $result = $pullResult = array();
    // Do pull first from mailchimp to CiviCRM
    $pullRunner = CRM_Mailchimp_Form_Pull::getRunner($skipEndUrl = TRUE);
    if ($pullRunner) {
        $pullResult = $pullRunner->runAll();
    }
    // Do push from CiviCRM to mailchimp
    $runner = CRM_Mailchimp_Form_Sync::getRunner($skipEndUrl = TRUE);
    if ($runner) {
        $result = $runner->runAll();
    }
    if ($pullResult['is_error'] == 0 && $result['is_error'] == 0) {
        return civicrm_api3_create_success();
    } else {
        return civicrm_api3_create_error();
    }
}
 /**
  * Batch update Mailchimp with new contacts that need to be subscribed, or have changed data.
  *
  * This also does the clean-up tasks of removing the temporary tables.
  */
 static function syncPushAdd(CRM_Queue_TaskContext $ctx, $listID)
 {
     CRM_Mailchimp_Utils::checkDebug('Start-CRM_Mailchimp_Form_Sync syncPushAdd $ctx= ', $ctx);
     CRM_Mailchimp_Utils::checkDebug('Start-CRM_Mailchimp_Form_Sync syncPushAdd $listID= ', $listID);
     // @todo take the remaining details from tmp_mailchimp_push_c
     // and construct a batchUpdate (do they need to be batched into 1000s? I can't recal).
     $dao = CRM_Core_DAO::executeQuery("SELECT * FROM tmp_mailchimp_push_c;");
     $stats = array();
     // Loop the $dao object to make a list of emails to subscribe/update
     $batch = array();
     while ($dao->fetch()) {
         $merge = array('FNAME' => $dao->first_name, 'LNAME' => $dao->last_name);
         // set the groupings.
         $groupings = unserialize($dao->groupings);
         // this is a array(groupingid=>array(groupid=>bool membership))
         $merge_groups = array();
         foreach ($groupings as $grouping_id => $groups) {
             // CRM_Mailchimp_Utils::checkDebug('get groups $groups= ', $groups);
             $merge_groups[$grouping_id] = array('id' => $grouping_id, 'groups' => array());
             CRM_Mailchimp_Utils::checkDebug('End-CRM_Mailchimp_Form_Sync $merge_groups[$grouping_id]', $merge_groups[$grouping_id]);
             foreach ($groups as $group_id => $is_member) {
                 if ($is_member) {
                     $merge_groups[$grouping_id]['groups'][] = CRM_Mailchimp_Utils::getMCGroupName($listID, $grouping_id, $group_id);
                 }
             }
         }
         // remove the significant array indexes, in case Mailchimp cares.
         $merge['groupings'] = array_values($merge_groups);
         $batch[] = array('email' => array('email' => $dao->email), 'email_type' => 'html', 'merge_vars' => $merge);
         $stats[$listID]['added']++;
     }
     if (!$batch) {
         // Nothing to do
         return CRM_Queue_Task::TASK_SUCCESS;
     }
     // Log the batch subscribe details
     CRM_Core_Error::debug_var('Mailchimp  syncPushAdd batchUnsubscribe $listID= ', $listID);
     CRM_Core_Error::debug_var('Mailchimp syncPushAdd batchSubscribe $batch= ', $batch);
     // Send Mailchimp Lists API Call.
     // http://apidocs.mailchimp.com/api/2.0/lists/batch-subscribe.php
     $list = new Mailchimp_Lists(CRM_Mailchimp_Utils::mailchimp());
     $result = $list->batchSubscribe($listID, $batch, $double_optin = FALSE, $update = TRUE, $replace_interests = TRUE);
     // debug: file_put_contents(DRUPAL_ROOT . '/logs/' . date('Y-m-d-His') . '-MC-push.log', print_r($result,1));
     CRM_Mailchimp_Utils::checkDebug('CRM_Mailchimp_Form_Sync syncPushAdd $result= ', $result);
     $get_GroupId = CRM_Mailchimp_Utils::getGroupsToSync(array(), $listID);
     CRM_Mailchimp_Utils::checkDebug('$get_GroupId= ', $get_GroupId);
     // @todo check result (keys: error_count, add_count, update_count)
     $stats[$listID]['group_id'] = array_keys($get_GroupId);
     $stats[$listID]['error_count'] = $result['error_count'];
     $stats[$listID]['error_details'] = $result['errors'];
     static::updatePushStats($stats);
     // Finally, finish up by removing the two temporary tables
     CRM_Core_DAO::executeQuery("DROP TABLE tmp_mailchimp_push_m;");
     CRM_Core_DAO::executeQuery("DROP TABLE tmp_mailchimp_push_c;");
     CRM_Mailchimp_Utils::checkDebug('get groupsss $grouping_id= ', $grouping_id);
     CRM_Mailchimp_Utils::checkDebug('get groupssss $group_id= ', $group_id);
     CRM_Mailchimp_Utils::checkDebug('End-CRM_Mailchimp_Form_Sync syncPushAdd $result= ', $result);
     CRM_Mailchimp_Utils::checkDebug('End-CRM_Mailchimp_Form_Sync syncPushAdd $ctx= ', $ctx);
     CRM_Mailchimp_Utils::checkDebug('End-CRM_Mailchimp_Form_Sync syncPushAdd $listID= ', $listID);
     return CRM_Queue_Task::TASK_SUCCESS;
 }
 /**
  * Get Mailchimp group ID group name
  */
 public static function getMailchimpGroupIdFromName($listID, $groupName)
 {
     CRM_Mailchimp_Utils::checkDebug('Start-CRM_Mailchimp_Utils getMailchimpGroupIdFromName $listID', $listID);
     CRM_Mailchimp_Utils::checkDebug('Start-CRM_Mailchimp_Utils getMailchimpGroupIdFromName $groupName', $groupName);
     if (empty($listID) || empty($groupName)) {
         return NULL;
     }
     $mcLists = new Mailchimp_Lists(CRM_Mailchimp_Utils::mailchimp());
     try {
         $results = $mcLists->interestGroupings($listID);
     } catch (Exception $e) {
         return NULL;
     }
     foreach ($results as $grouping) {
         foreach ($grouping['groups'] as $group) {
             if ($group['name'] == $groupName) {
                 CRM_Mailchimp_Utils::checkDebug('End-CRM_Mailchimp_Utils getMailchimpGroupIdFromName= ', $group['id']);
                 return $group['id'];
             }
         }
     }
 }