/** * 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']; } } } }