diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 53a5344..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/nbproject diff --git a/CRM/Emailamender.php b/CRM/Emailamender.php index 010276f..185ef73 100644 --- a/CRM/Emailamender.php +++ b/CRM/Emailamender.php @@ -2,16 +2,20 @@ class CRM_Emailamender { + /** + * Singleton instance. + * + * @var \CRM_Emailamender + */ + private static $singleton; private $_aTopLevelFilterSettings; private $_aSecondLevelFilterSettings; private $_aCompoundTopLevelDomains; - private $_iCorrectedEmailAddressActivityTypeId; public function __construct() { - $this->_aTopLevelFilterSettings = CRM_Core_BAO_Setting::getItem('uk.org.futurefirst.networks.emailamender', 'emailamender.top_level_domain_corrections'); - $this->_aSecondLevelFilterSettings = CRM_Core_BAO_Setting::getItem('uk.org.futurefirst.networks.emailamender', 'emailamender.second_level_domain_corrections'); - $this->_aCompoundTopLevelDomains = CRM_Core_BAO_Setting::getItem('uk.org.futurefirst.networks.emailamender', 'emailamender.compound_top_level_domains'); - $this->iCorrectedEmailAddressActivityTypeId = CRM_Core_BAO_Setting::getItem('uk.org.futurefirst.networks.emailamender', 'emailamender.email_amended_activity_type_id'); + $this->_aTopLevelFilterSettings = (array) Civi::settings()->get('emailamender.top_level_domain_corrections'); + $this->_aSecondLevelFilterSettings = (array) Civi::settings()->get('emailamender.second_level_domain_corrections'); + $this->_aCompoundTopLevelDomains = (array) Civi::settings()->get('emailamender.compound_top_level_domains'); } /** @@ -78,10 +82,7 @@ private static function reassemble_email($aEmailPieces, $aDomainPartPieces) { * @return bool */ public function is_autocorrect_enabled() { - if ('false' == CRM_Core_BAO_Setting::getItem('uk.org.futurefirst.networks.emailamender', 'emailamender.email_amender_enabled')) { - return FALSE; - } - return TRUE; + return Civi::settings()->get('emailamender.email_amender_enabled'); } /** @@ -90,12 +91,15 @@ public function is_autocorrect_enabled() { * @param int $iEmailId * @param int $iContactId * @param string $sRawEmail + * * @return bool correction took place + * + * @throws \CiviCRM_API3_Exception */ - public function check_for_corrections($iEmailId, $iContactId, $sRawEmail) { + public function fixEmailAddress($iEmailId, $iContactId, $sRawEmail) { // 1. Check that the email address has only one '@' - shouldn't need to do this but just in case. - if (substr_count($sRawEmail, "@") != 1) { + if (substr_count($sRawEmail, '@') !== 1) { return FALSE; } @@ -103,7 +107,7 @@ public function check_for_corrections($iEmailId, $iContactId, $sRawEmail) { self::parse_email_byref($sRawEmail, $aEmailPieces, $aDomainPartPieces); // 3. Load the settings and initialise. - $iSecondLevelDomainFragmentIndex = self::get_second_domain_part_index($aEmailPieces[1]); + $iSecondLevelDomainFragmentIndex = $this->get_second_domain_part_index($aEmailPieces[1]); // 4. Break it up and process it. $bTopLevelChanged = self::perform_replacement($aDomainPartPieces[0], $this->_aTopLevelFilterSettings); @@ -118,28 +122,30 @@ public function check_for_corrections($iEmailId, $iContactId, $sRawEmail) { $sCleanedEmail = self::reassemble_email($aEmailPieces, $aDomainPartPieces); // 7. Update the email address. - $updateParam = array( - 'version' => 3, + $updateParam = [ 'id' => $iEmailId, 'email' => $sCleanedEmail, // Take it off hold, taken from CRM_Core_BAO_Email. 'on_hold' => FALSE, 'hold_date' => NULL, 'reset_date' => date('YmdHis'), - ); - - $updateEmailOutput = civicrm_api('Email', 'update', $updateParam); + ]; - if ($updateEmailOutput['is_error']) { + try { + civicrm_api3('Email', 'create', $updateParam); + // Recalculate display name. + civicrm_api3('Contact', 'create', ['id' => $iContactId]); + } + catch (CiviCRM_API3_Exception $e) { CRM_Core_Session::setStatus(ts("Error when correcting email - contact ID $iContactId"), ts('Email Address Corrector'), 'error'); - return FALSE; + throw $e; } // 8. Record the change by an activity. $createActivityOutput = civicrm_api('Activity', 'create', array( 'version' => '3', 'sequential' => '1', - 'activity_type_id' => $this->iCorrectedEmailAddressActivityTypeId, + 'activity_type_id' => 'corrected_email_address', 'source_contact_id' => $iContactId, 'target_contact_id' => $iContactId, 'assignee_contact_id' => $iContactId, @@ -155,4 +161,17 @@ public function check_for_corrections($iEmailId, $iContactId, $sRawEmail) { return TRUE; } + /** + * Get singleton instance. + * + * @return \CRM_Emailamender + */ + public static function singleton() { + if (self::$singleton) { + return self::$singleton; + } + self::$singleton = new CRM_Emailamender(); + return self::$singleton; + } + } diff --git a/CRM/Emailamender/Equivalentmatcher.php b/CRM/Emailamender/Equivalentmatcher.php index 6399ddf..4d4f0d0 100644 --- a/CRM/Emailamender/Equivalentmatcher.php +++ b/CRM/Emailamender/Equivalentmatcher.php @@ -70,7 +70,7 @@ public static function processHook($email, $contactID, &$result) { $aEmailParts = explode('@', $email); // load settings and init - $aDomainEquivalents = CRM_Core_BAO_Setting::getItem('uk.org.futurefirst.networks.emailamender', 'emailamender.equivalent_domains'); + $aDomainEquivalents = Civi::settings()->get('emailamender.equivalent_domains'); // Try equivalent e-mail domains, if there are any $aEquivalentDomainsToTry = self::getEquivalentDomainsFor($aEmailParts[1], $aDomainEquivalents); diff --git a/CRM/Emailamender/Form/Task/Correctemailaddresses.php b/CRM/Emailamender/Form/Task/Correctemailaddresses.php index 8f240fa..aab6daa 100644 --- a/CRM/Emailamender/Form/Task/Correctemailaddresses.php +++ b/CRM/Emailamender/Form/Task/Correctemailaddresses.php @@ -1,24 +1,23 @@ assign('contactIdCount', count($this->_contactIds)); - $this->addButtons(array( - array( + $this->addButtons([ + [ 'type' => 'submit', 'name' => ts('Correct Email Addresses'), 'isDefault' => TRUE, - ), - )); + ], + ]); // export form elements $this->assign('elementNames', $this->getRenderableElementNames()); @@ -34,15 +33,15 @@ public function postProcess() { foreach ($this->_contactIds as $eachContactId) { $contactCount++; - $updateParam = array( + $updateParam = [ "version" => 3, "contact_id" => $eachContactId, - ); + ]; $emailAddresses = civicrm_api('Email', 'get', $updateParam); foreach ($emailAddresses['values'] as $eachEmailAddress) { - if ($emailAmender->check_for_corrections($eachEmailAddress['id'], $eachEmailAddress['contact_id'], $eachEmailAddress['email'])) { + if ($emailAmender->fixEmailAddress($eachEmailAddress['id'], $eachEmailAddress['contact_id'], $eachEmailAddress['email'])) { $correctionCount++; } } @@ -63,7 +62,7 @@ public function getRenderableElementNames() { // auto-rendered in the loop -- such as "qfKey" and "buttons". These // items don't have labels. We'll identify renderable by filtering on // the 'label'. - $elementNames = array(); + $elementNames = []; foreach ($this->_elements as $element) { /** @var HTML_QuickForm_Element $element */ $label = $element->getLabel(); diff --git a/CRM/Emailamender/Page/EmailAmenderSettings.php b/CRM/Emailamender/Page/EmailAmenderSettings.php index 982a9b2..ec3dbe6 100755 --- a/CRM/Emailamender/Page/EmailAmenderSettings.php +++ b/CRM/Emailamender/Page/EmailAmenderSettings.php @@ -1,20 +1,19 @@ assign('email_amender_enabled', CRM_Core_BAO_Setting::getItem( 'uk.org.futurefirst.networks.emailamender', 'emailamender.email_amender_enabled')); + $this->assign('email_amender_enabled', Civi::settings()->get('emailamender.email_amender_enabled')); + + $this->assign('top_level_filter_settings', Civi::settings()->get('emailamender.top_level_domain_corrections')); + $this->assign('second_level_filter_settings', Civi::settings()->get('emailamender.second_level_domain_corrections')); + $this->assign('compound_top_level_domains', Civi::settings()->get('emailamender.compound_top_level_domains')); - $this->assign('top_level_filter_settings', CRM_Core_BAO_Setting::getItem( 'uk.org.futurefirst.networks.emailamender', 'emailamender.top_level_domain_corrections')); - $this->assign('second_level_filter_settings', CRM_Core_BAO_Setting::getItem( 'uk.org.futurefirst.networks.emailamender', 'emailamender.second_level_domain_corrections')); - $this->assign('compound_top_level_domains', CRM_Core_BAO_Setting::getItem( 'uk.org.futurefirst.networks.emailamender', 'emailamender.compound_top_level_domains')); - - $this->assign('equivalent_domain_settings', CRM_Core_BAO_Setting::getItem( 'uk.org.futurefirst.networks.emailamender', 'emailamender.equivalent_domains')); + $this->assign('equivalent_domain_settings', Civi::settings()->get('emailamender.equivalent_domains')); parent::run(); } diff --git a/CRM/Emailamender/Upgrader.php b/CRM/Emailamender/Upgrader.php index 1cf644c..9994bd5 100644 --- a/CRM/Emailamender/Upgrader.php +++ b/CRM/Emailamender/Upgrader.php @@ -19,7 +19,7 @@ public function upgrade_0001() { $this->ctx->log->info('Applying update 0001'); // Check if the setting is already present - $aDomainEquivalents = CRM_Core_BAO_Setting::getItem('uk.org.futurefirst.networks.emailamender', 'uk.org.futurefirst.networks.emailamender.equivalent_domains'); + $aDomainEquivalents = Civi::settings()->get('emailamender.equivalent_domains'); if ($aDomainEquivalents) { return TRUE; } @@ -31,10 +31,10 @@ public function upgrade_0001() { 'gmail.co.uk' => 'GMail UK', 'googlemail.co.uk' => 'GMail UK', ); - CRM_Core_BAO_Setting::setItem($aDomainEquivalents, 'uk.org.futurefirst.networks.emailamender', 'uk.org.futurefirst.networks.emailamender.equivalent_domains'); + Civi::settings()->set('equivalent_domains', $aDomainEquivalents); // Check if the setting is now present (as setItem returns void) - $aDomainEquivalents = CRM_Core_BAO_Setting::getItem('uk.org.futurefirst.networks.emailamender', 'uk.org.futurefirst.networks.emailamender.equivalent_domains'); + $aDomainEquivalents = Civi::settings()->get('equivalent_domains'); if ($aDomainEquivalents) { return TRUE; } diff --git a/CRM/Emailamender/Upgrader/Base.php b/CRM/Emailamender/Upgrader/Base.php index 5f4dd74..aeb6dd3 100644 --- a/CRM/Emailamender/Upgrader/Base.php +++ b/CRM/Emailamender/Upgrader/Base.php @@ -221,7 +221,7 @@ public function getRevisions() { public function getCurrentRevision() { // return CRM_Core_BAO_Extension::getSchemaVersion($this->extensionName); $key = $this->extensionName . ':version'; - return CRM_Core_BAO_Setting::getItem('Extension', $key); + return Civi::settings()->get($key); } public function setCurrentRevision($revision) { @@ -231,7 +231,7 @@ public function setCurrentRevision($revision) { // CRM_Core_BAO_Extension::setSchemaVersion($this->extensionName, $revision); $key = $this->extensionName . ':version'; - CRM_Core_BAO_Setting::setItem($revision, 'Extension', $key); + Civi::settings()->set($key, $revision); return TRUE; } diff --git a/README.md b/README.md new file mode 100644 index 0000000..365aab6 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Email-Amender +A CiviCRM extension that automatically corrects email addresses as they're added. Includes a handy interface to add new correction settings. diff --git a/api/v3/EmailAmender/BatchUpdate.php b/api/v3/EmailAmender/BatchUpdate.php new file mode 100644 index 0000000..ff6a342 --- /dev/null +++ b/api/v3/EmailAmender/BatchUpdate.php @@ -0,0 +1,33 @@ +get('emailamender.top_level_domain_corrections'); + $secondLevel = Civi::settings()->get('emailamender.second_level_domain_corrections'); + + $options = _civicrm_api3_get_options_from_params($params); + $topLevelDomainList = CRM_Utils_Type::escape(implode('|', array_filter(array_keys($topLevel))), 'String'); + $secondLevelDomainList = CRM_Utils_Type::escape(implode('|', array_filter(array_keys($secondLevel))), 'String'); + // Can't use api due to lack of regex support. + // Also - I'm not hunting out subdomains at this stage - it's great that John handled + // edge cases like gmai@gmai.gmai.com but it feels like it can stay out of scope of this + // api at this stage. + $values = CRM_Core_DAO::executeQuery(" + SELECT id, contact_id, email FROM civicrm_email + WHERE email REGEXP '\.({$topLevelDomainList})$' + OR email REGEXP '@({$secondLevelDomainList})\\\.' + LIMIT " . $options['limit'] + ); + $return = []; + while ($values->fetch()) { + $return[$values->id] = ['email' => $values->email, 'id' => $values->id, 'contact_id' => $values->contact_id]; + } + + return civicrm_api3_create_success($return); +} + diff --git a/api/v3/EmailAmender/FixEmail.php b/api/v3/EmailAmender/FixEmail.php new file mode 100644 index 0000000..aaa8243 --- /dev/null +++ b/api/v3/EmailAmender/FixEmail.php @@ -0,0 +1,34 @@ +fixEmailAddress($params['id'], $params['contact_id'], $params['email'])) { + $return[$params['id']] = ['id' => $params['id'], 'contact_id' => $params['contact_id']]; + } + + return civicrm_api3_create_success($return); +} diff --git a/api/v3/EmailAmender/UpdateCompoundTLDs.php b/api/v3/EmailAmender/UpdateCompoundTLDs.php index 45fcc25..c2ea035 100755 --- a/api/v3/EmailAmender/UpdateCompoundTLDs.php +++ b/api/v3/EmailAmender/UpdateCompoundTLDs.php @@ -21,15 +21,15 @@ function _civicrm_api3_email_amender_update_compound_t_l_ds_spec(&$spec) { * @see civicrm_api3_create_error * @throws API_Exception */ -function civicrm_api3_email_amender_update_compound_t_l_ds($params) { +function civicrm_api3_email_amender_update_compound_t_l_ds($params) { - $aEscapedCorrections = array(); + $aEscapedCorrections = []; foreach( $params['compound_tlds'] as $compoundTLDs ){ $aEscapedCorrections[] = CRM_Core_DAO::escapeString($compoundTLDs); } - CRM_Core_BAO_Setting::setItem($aEscapedCorrections, 'uk.org.futurefirst.networks.emailamender', 'emailamender.compound_top_level_domains'); + Civi::settings()->set('emailamender.compound_top_level_domains', $aEscapedCorrections); return civicrm_api3_create_success(array(), $params, 'EmailAmenderCompoundTLDs', 'Update'); } diff --git a/api/v3/EmailAmender/UpdateCorrections.php b/api/v3/EmailAmender/UpdateCorrections.php index 3a865a6..6134499 100755 --- a/api/v3/EmailAmender/UpdateCorrections.php +++ b/api/v3/EmailAmender/UpdateCorrections.php @@ -23,36 +23,28 @@ function _civicrm_api3_email_amender_update_corrections_spec(&$spec) { * @throws API_Exception */ function civicrm_api3_email_amender_update_corrections($params) { + $aEscapedCorrections = []; - $sCivicrmSettingsKey = ""; - + foreach( $params['correction_keys'] as $index => $correctionKey ){ + $aEscapedCorrections[CRM_Core_DAO::escapeString($correctionKey)] = CRM_Core_DAO::escapeString($params['correction_values'][$index]); + } switch($params['domain_level']){ case 'top_level_domain': - $sCivicrmSettingsKey = 'emailamender.top_level_domain_corrections'; + Civi::settings()->set('emailamender.top_level_domain_corrections', $aEscapedCorrections); break; case 'second_level_domain': - $sCivicrmSettingsKey = 'emailamender.second_level_domain_corrections'; + Civi::settings()->set('emailamender.second_level_domain_corrections', $aEscapedCorrections); break; case 'equivalent_domain': - $sCivicrmSettingsKey = 'emailamender.equivalent_domains'; + Civi::settings()->set('emailamender.equivalent_domains', $aEscapedCorrections); break; default: - return civicrm_api3_create_error(ts("Couldn't update settings - invalid domain level"), - array('error_code' => '1', 'field' => 'domain_level') - ); - } - - $aEscapedCorrections = array(); - - foreach( $params['correction_keys'] as $index => $correctionKey ){ - $aEscapedCorrections[CRM_Core_DAO::escapeString($correctionKey)] = CRM_Core_DAO::escapeString($params['correction_values'][$index]); + throw new API_Exception(ts('Invalid domain amender setting update')); } - CRM_Core_BAO_Setting::setItem($aEscapedCorrections, 'uk.org.futurefirst.networks.emailamender', $sCivicrmSettingsKey); - - return civicrm_api3_create_success(array(), $params, 'EmailAmender', 'UpdateCorrections'); + return civicrm_api3_create_success([], $params, 'EmailAmender', 'UpdateCorrections'); } diff --git a/api/v3/EmailAmender/UpdateSettings.php b/api/v3/EmailAmender/UpdateSettings.php deleted file mode 100755 index cc6437b..0000000 --- a/api/v3/EmailAmender/UpdateSettings.php +++ /dev/null @@ -1,37 +0,0 @@ -getUrl(self::LONG_NAME), '/'); + } + return CRM_Core_Resources::singleton()->getUrl(self::LONG_NAME, $file); + } + + /** + * Get the path of a resource file (in this extension). + * + * @param string|NULL $file + * Ex: NULL. + * Ex: 'css/foo.css'. + * @return string + * Ex: '/var/www/example.org/sites/default/ext/org.example.foo'. + * Ex: '/var/www/example.org/sites/default/ext/org.example.foo/css/foo.css'. + */ + public static function path($file = NULL) { + // return CRM_Core_Resources::singleton()->getPath(self::LONG_NAME, $file); + return __DIR__ . ($file === NULL ? '' : (DIRECTORY_SEPARATOR . $file)); + } + + /** + * Get the name of a class within this extension. + * + * @param string $suffix + * Ex: 'Page_HelloWorld' or 'Page\\HelloWorld'. + * @return string + * Ex: 'CRM_Foo_Page_HelloWorld'. + */ + public static function findClass($suffix) { + return self::CLASS_PREFIX . '_' . str_replace('\\', '_', $suffix); + } + +} + +use CRM_Emailamender_ExtensionUtil as E; + /** * (Delegated) Implements hook_civicrm_config(). * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_config + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config */ function _emailamender_civix_civicrm_config(&$config = NULL) { static $configured = FALSE; @@ -19,14 +96,14 @@ function _emailamender_civix_civicrm_config(&$config = NULL) { $extRoot = dirname(__FILE__) . DIRECTORY_SEPARATOR; $extDir = $extRoot . 'templates'; - if ( is_array( $template->template_dir ) ) { - array_unshift( $template->template_dir, $extDir ); + if (is_array($template->template_dir)) { + array_unshift($template->template_dir, $extDir); } else { - $template->template_dir = array( $extDir, $template->template_dir ); + $template->template_dir = array($extDir, $template->template_dir); } - $include_path = $extRoot . PATH_SEPARATOR . get_include_path( ); + $include_path = $extRoot . PATH_SEPARATOR . get_include_path(); set_include_path($include_path); } @@ -35,7 +112,7 @@ function _emailamender_civix_civicrm_config(&$config = NULL) { * * @param $files array(string) * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_xmlMenu + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_xmlMenu */ function _emailamender_civix_civicrm_xmlMenu(&$files) { foreach (_emailamender_civix_glob(__DIR__ . '/xml/Menu/*.xml') as $file) { @@ -46,7 +123,7 @@ function _emailamender_civix_civicrm_xmlMenu(&$files) { /** * Implements hook_civicrm_install(). * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_install + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_install */ function _emailamender_civix_civicrm_install() { _emailamender_civix_civicrm_config(); @@ -55,10 +132,24 @@ function _emailamender_civix_civicrm_install() { } } +/** + * Implements hook_civicrm_postInstall(). + * + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall + */ +function _emailamender_civix_civicrm_postInstall() { + _emailamender_civix_civicrm_config(); + if ($upgrader = _emailamender_civix_upgrader()) { + if (is_callable(array($upgrader, 'onPostInstall'))) { + $upgrader->onPostInstall(); + } + } +} + /** * Implements hook_civicrm_uninstall(). * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_uninstall + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall */ function _emailamender_civix_civicrm_uninstall() { _emailamender_civix_civicrm_config(); @@ -70,7 +161,7 @@ function _emailamender_civix_civicrm_uninstall() { /** * (Delegated) Implements hook_civicrm_enable(). * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_enable + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_enable */ function _emailamender_civix_civicrm_enable() { _emailamender_civix_civicrm_config(); @@ -84,7 +175,7 @@ function _emailamender_civix_civicrm_enable() { /** * (Delegated) Implements hook_civicrm_disable(). * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_disable + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable * @return mixed */ function _emailamender_civix_civicrm_disable() { @@ -105,7 +196,7 @@ function _emailamender_civix_civicrm_disable() { * @return mixed based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending) * for 'enqueue', returns void * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_upgrade + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_upgrade */ function _emailamender_civix_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) { if ($upgrader = _emailamender_civix_upgrader()) { @@ -117,7 +208,7 @@ function _emailamender_civix_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) * @return CRM_Emailamender_Upgrader */ function _emailamender_civix_upgrader() { - if (!file_exists(__DIR__.'/CRM/Emailamender/Upgrader.php')) { + if (!file_exists(__DIR__ . '/CRM/Emailamender/Upgrader.php')) { return NULL; } else { @@ -153,7 +244,8 @@ function _emailamender_civix_find_files($dir, $pattern) { while (FALSE !== ($entry = readdir($dh))) { $path = $subdir . DIRECTORY_SEPARATOR . $entry; if ($entry{0} == '.') { - } elseif (is_dir($path)) { + } + elseif (is_dir($path)) { $todos[] = $path; } } @@ -167,15 +259,19 @@ function _emailamender_civix_find_files($dir, $pattern) { * * Find any *.mgd.php files, merge their content, and return. * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_managed + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_managed */ function _emailamender_civix_civicrm_managed(&$entities) { $mgdFiles = _emailamender_civix_find_files(__DIR__, '*.mgd.php'); + sort($mgdFiles); foreach ($mgdFiles as $file) { $es = include $file; foreach ($es as $e) { if (empty($e['module'])) { - $e['module'] = 'uk.org.futurefirst.networks.emailamender'; + $e['module'] = E::LONG_NAME; + } + if (empty($e['params']['version'])) { + $e['params']['version'] = '3'; } $entities[] = $e; } @@ -189,7 +285,7 @@ function _emailamender_civix_civicrm_managed(&$entities) { * * Note: This hook only runs in CiviCRM 4.4+. * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_caseTypes + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_caseTypes */ function _emailamender_civix_civicrm_caseTypes(&$caseTypes) { if (!is_dir(__DIR__ . '/xml/case')) { @@ -204,7 +300,7 @@ function _emailamender_civix_civicrm_caseTypes(&$caseTypes) { // throw new CRM_Core_Exception($errorMessage); } $caseTypes[$name] = array( - 'module' => 'uk.org.futurefirst.networks.emailamender', + 'module' => E::LONG_NAME, 'name' => $name, 'file' => $file, ); @@ -212,14 +308,14 @@ function _emailamender_civix_civicrm_caseTypes(&$caseTypes) { } /** -* (Delegated) Implements hook_civicrm_angularModules(). -* -* Find any and return any files matching "ang/*.ang.php" -* -* Note: This hook only runs in CiviCRM 4.5+. -* -* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_angularModules -*/ + * (Delegated) Implements hook_civicrm_angularModules(). + * + * Find any and return any files matching "ang/*.ang.php" + * + * Note: This hook only runs in CiviCRM 4.5+. + * + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_angularModules + */ function _emailamender_civix_civicrm_angularModules(&$angularModules) { if (!is_dir(__DIR__ . '/ang')) { return; @@ -230,12 +326,31 @@ function _emailamender_civix_civicrm_angularModules(&$angularModules) { $name = preg_replace(':\.ang\.php$:', '', basename($file)); $module = include $file; if (empty($module['ext'])) { - $module['ext'] = 'uk.org.futurefirst.networks.emailamender'; + $module['ext'] = E::LONG_NAME; } $angularModules[$name] = $module; } } +/** + * (Delegated) Implements hook_civicrm_themes(). + * + * Find any and return any files matching "*.theme.php" + */ +function _emailamender_civix_civicrm_themes(&$themes) { + $files = _emailamender_civix_glob(__DIR__ . '/*.theme.php'); + foreach ($files as $file) { + $themeMeta = include $file; + if (empty($themeMeta['name'])) { + $themeMeta['name'] = preg_replace(':\.theme\.php$:', '', basename($file)); + } + if (empty($themeMeta['ext'])) { + $themeMeta['ext'] = E::LONG_NAME; + } + $themes[$themeMeta['name']] = $themeMeta; + } +} + /** * Glob wrapper which is guaranteed to return an array. * @@ -257,35 +372,32 @@ function _emailamender_civix_glob($pattern) { * Inserts a navigation menu item at a given place in the hierarchy. * * @param array $menu - menu hierarchy - * @param string $path - path where insertion should happen (ie. Administer/System Settings) - * @param array $item - menu you need to insert (parent/child attributes will be filled for you) - * @param int $parentId - used internally to recurse in the menu structure + * @param string $path - path to parent of this item, e.g. 'my_extension/submenu' + * 'Mailing', or 'Administer/System Settings' + * @param array $item - the item to insert (parent/child attributes will be + * filled for you) */ -function _emailamender_civix_insert_navigation_menu(&$menu, $path, $item, $parentId = NULL) { - static $navId; - +function _emailamender_civix_insert_navigation_menu(&$menu, $path, $item) { // If we are done going down the path, insert menu if (empty($path)) { - if (!$navId) $navId = CRM_Core_DAO::singleValueQuery("SELECT max(id) FROM civicrm_navigation"); - $navId ++; - $menu[$navId] = array ( - 'attributes' => array_merge($item, array( + $menu[] = array( + 'attributes' => array_merge(array( 'label' => CRM_Utils_Array::value('name', $item), 'active' => 1, - 'parentID' => $parentId, - 'navID' => $navId, - )) + ), $item), ); - return true; + return TRUE; } else { // Find an recurse into the next level down - $found = false; + $found = FALSE; $path = explode('/', $path); $first = array_shift($path); foreach ($menu as $key => &$entry) { if ($entry['attributes']['name'] == $first) { - if (!$entry['child']) $entry['child'] = array(); + if (!isset($entry['child'])) { + $entry['child'] = array(); + } $found = _emailamender_civix_insert_navigation_menu($entry['child'], implode('/', $path), $item, $key); } } @@ -293,20 +405,70 @@ function _emailamender_civix_insert_navigation_menu(&$menu, $path, $item, $paren } } +/** + * (Delegated) Implements hook_civicrm_navigationMenu(). + */ +function _emailamender_civix_navigationMenu(&$nodes) { + if (!is_callable(array('CRM_Core_BAO_Navigation', 'fixNavigationMenu'))) { + _emailamender_civix_fixNavigationMenu($nodes); + } +} + +/** + * Given a navigation menu, generate navIDs for any items which are + * missing them. + */ +function _emailamender_civix_fixNavigationMenu(&$nodes) { + $maxNavID = 1; + array_walk_recursive($nodes, function($item, $key) use (&$maxNavID) { + if ($key === 'navID') { + $maxNavID = max($maxNavID, $item); + } + }); + _emailamender_civix_fixNavigationMenuItems($nodes, $maxNavID, NULL); +} + +function _emailamender_civix_fixNavigationMenuItems(&$nodes, &$maxNavID, $parentID) { + $origKeys = array_keys($nodes); + foreach ($origKeys as $origKey) { + if (!isset($nodes[$origKey]['attributes']['parentID']) && $parentID !== NULL) { + $nodes[$origKey]['attributes']['parentID'] = $parentID; + } + // If no navID, then assign navID and fix key. + if (!isset($nodes[$origKey]['attributes']['navID'])) { + $newKey = ++$maxNavID; + $nodes[$origKey]['attributes']['navID'] = $newKey; + $nodes[$newKey] = $nodes[$origKey]; + unset($nodes[$origKey]); + $origKey = $newKey; + } + if (isset($nodes[$origKey]['child']) && is_array($nodes[$origKey]['child'])) { + _emailamender_civix_fixNavigationMenuItems($nodes[$origKey]['child'], $maxNavID, $nodes[$origKey]['attributes']['navID']); + } + } +} + /** * (Delegated) Implements hook_civicrm_alterSettingsFolders(). * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_alterSettingsFolders + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_alterSettingsFolders */ function _emailamender_civix_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) { - static $configured = FALSE; - if ($configured) { - return; - } - $configured = TRUE; - $settingsDir = __DIR__ . DIRECTORY_SEPARATOR . 'settings'; - if(is_dir($settingsDir) && !in_array($settingsDir, $metaDataFolders)) { + if (!in_array($settingsDir, $metaDataFolders) && is_dir($settingsDir)) { $metaDataFolders[] = $settingsDir; } } + +/** + * (Delegated) Implements hook_civicrm_entityTypes(). + * + * Find any *.entityType.php files, merge their content, and return. + * + * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes + */ + +function _emailamender_civix_civicrm_entityTypes(&$entityTypes) { + $entityTypes = array_merge($entityTypes, array ( + )); +} diff --git a/emailamender.php b/emailamender.php index ad08492..0dd200c 100755 --- a/emailamender.php +++ b/emailamender.php @@ -16,89 +16,17 @@ function emailamender_civicrm_xmlMenu(&$files) { _emailamender_civix_civicrm_xmlMenu($files); } -/** - * create_activity_type_if_doesnt_exist - * also updates the civicrm_setting entry - * - */ -function emailamender_create_activity_type_if_doesnt_exist($sActivityTypeLabel, $sActivityTypeName, $sActivityTypeDescription, $sSettingName) { - - $aActivityTypeCheck = civicrm_api("OptionValue", "get", array('version' => '3', 'sequential' => '1', 'name' => $sActivityTypeLabel)); - - if ($aActivityTypeCheck['count'] > 0) { - print_r($aActivityTypeCheck, TRUE); - CRM_Core_BAO_Setting::setItem( - $aActivityTypeCheck['values'][0]['value'], - 'uk.org.futurefirst.networks.emailamender', - $sSettingName - ); - - return; - } - - // create activity types - $aEmailAmendedCreateResults = civicrm_api('ActivityType', 'create', array( - 'version' => '3', - 'sequential' => '1', - 'is_active' => '1', - 'label' => $sActivityTypeLabel, - 'name' => $sActivityTypeName, - 'weight' => '1', - 'description' => $sActivityTypeDescription, - ) - ); - - CRM_Core_BAO_Setting::setItem($aEmailAmendedCreateResults['values'][0]['value'], 'uk.org.futurefirst.networks.emailamender', $sSettingName); -} - /** * Implements hook_civicrm_install(). */ function emailamender_civicrm_install() { - - // initialise data - $aTopLevelDomainCorrections = array( - 'con' => 'com', - 'couk' => 'co.uk', - 'cpm' => 'com', - 'orguk' => 'org.uk', - ); - - $aSecondLevelDomainCorrections = array( - 'gmai' => 'gmail', - 'gamil' => 'gmail', - 'gmial' => 'gmail', - 'hotmai' => 'hotmail', - 'hotmal' => 'hotmail', - 'hotmil' => 'hotmail', - 'hotmial' => 'hotmail', - 'htomail' => 'hotmail', - 'tiscalli' => 'tiscali', - 'yaho' => 'yahoo', - ); - - $aCompoundTopLevelDomains = array( - '.ac.uk', - '.co.uk', - '.org.uk', - ); - - $aDomainEquivalents = array( - 'gmail.com' => 'GMail', - 'googlemail.com' => 'GMail', - 'gmail.co.uk' => 'GMail UK', - 'googlemail.co.uk' => 'GMail UK', - ); - - CRM_Core_BAO_Setting::setItem($aTopLevelDomainCorrections, 'uk.org.futurefirst.networks.emailamender', 'emailamender.top_level_domain_corrections'); - CRM_Core_BAO_Setting::setItem($aSecondLevelDomainCorrections, 'uk.org.futurefirst.networks.emailamender', 'emailamender.second_level_domain_corrections'); - CRM_Core_BAO_Setting::setItem($aCompoundTopLevelDomains, 'uk.org.futurefirst.networks.emailamender', 'emailamender.compound_top_level_domains'); - CRM_Core_BAO_Setting::setItem($aDomainEquivalents, 'uk.org.futurefirst.networks.emailamender', 'emailamender.equivalent_domains'); - CRM_Core_BAO_Setting::setItem('false', 'uk.org.futurefirst.networks.emailamender', 'emailamender.email_amender_enabled'); - - // create activity types - emailamender_create_activity_type_if_doesnt_exist('Corrected Email Address', 'corrected_email_address', 'Automatically corrected emails (by the Email Address Corrector extension).', 'emailamender.email_amended_activity_type_id'); - + CRM_Core_BAO_OptionValue::ensureOptionValueExists([ + 'label' => 'Corrected Email Address', + 'name' => 'corrected_email_address', + 'weight' => '1', + 'description' => 'Automatically corrected emails (by the Email Address Corrector extension).', + 'option_group_id' => 'activity_type', + ]); return _emailamender_civix_civicrm_install(); } @@ -150,18 +78,12 @@ function emailamender_civicrm_managed(&$entities) { */ function emailamender_civicrm_post($op, $objectName, $id, &$params) { // 1. ignore all operations other than adding an email address - if ($objectName != "Email") { - return; - } - - if ($op != "create") { + if ($objectName !== 'Email' || $op !== 'create' || !Civi::settings()->get('emailamender.email_amender_enabled')) { return; } - $emailAmender = new CRM_Emailamender(); - if ($emailAmender->is_autocorrect_enabled()) { - $emailAmender->check_for_corrections($params->id, $params->contact_id, $params->email); - } + $emailAmender = CRM_Emailamender::singleton(); + $emailAmender->fixEmailAddress($params->id, $params->contact_id, $params->email); } /** @@ -171,6 +93,15 @@ function emailamender_civicrm_emailProcessorContact($email, $contactID, &$result CRM_Emailamender_Equivalentmatcher::processHook($email, $contactID, $result); } +/** + * Implements hook_civicrm_alterSettingsFolders(). + * + * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_alterSettingsFolders + */ +function emailamender_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) { + _emailamender_civix_civicrm_alterSettingsFolders($metaDataFolders); +} + /** * civicrm_civicrm_navigationMenu * @@ -203,7 +134,7 @@ function emailamender_civicrm_navigationMenu(&$params) { * Implements hook_civicrm_searchTasks(). */ function emailamender_civicrm_searchTasks($objectType, &$tasks) { - if ($objectType == 'contact') { + if ($objectType === 'contact') { $tasks[] = array( 'title' => ts('Email - correct email addresses'), 'class' => 'CRM_Emailamender_Form_Task_Correctemailaddresses', @@ -211,3 +142,18 @@ function emailamender_civicrm_searchTasks($objectType, &$tasks) { ); } } + +/** + * Implements hook_civicrm_angularModules(). + * + * Generate a list of Angular modules. + * Generate a list of Angular modules. + * + * Note: This hook only runs in CiviCRM 4.5+. It may + * use features only available in v4.6+. + * + * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_angularModules + */ +function emailamender_civicrm_angularModules(&$angularModules) { + _emailamender_civix_civicrm_angularModules($angularModules); +} diff --git a/info.xml b/info.xml index 19dc83a..9f40bcb 100755 --- a/info.xml +++ b/info.xml @@ -16,10 +16,12 @@ john@civifirst.com 2016-11-20 - 2.03 + 3.0.0 stable 4.7 + 5.18 + 5.22 Data Cleaning The email addresses were selected based on Future First's experience of common email errors. diff --git a/settings/EmailAmender.setting.php b/settings/EmailAmender.setting.php new file mode 100644 index 0000000..04f9b84 --- /dev/null +++ b/settings/EmailAmender.setting.php @@ -0,0 +1,111 @@ + [ + 'group_name' => 'Email Amender', + 'group' => 'email_amender', + 'name' => 'emailamender.email_amender_enabled', + 'type' => 'Bool', + 'is_domain' => 1, + 'is_contact' => 0, + 'default' => FALSE, + 'description' => E::ts('Enable realtime email fixing for new emails'), + 'title' => 'Automatic Email amending enabled', + 'help_text' => E::ts('Enable this to allow new emails to be amended on save according to configured rules. Existing updates not amended'), + 'html_type' => 'Checkbox', + 'quick_form_type' => '', + ], + 'emailamender.top_level_domain_corrections' => [ + 'group_name' => 'Email Amender', + 'group' => 'email_amender', + 'name' => 'emailamender.top_level_domain_corrections', + 'type' => 'String', + 'is_domain' => 1, + 'is_contact' => 0, + 'description' => E::ts('List of top level domains to correct'), + 'title' => E::ts('Top level domains'), + 'help_text' => '', + 'html_type' => '', + 'quick_form_type' => '', + 'serialize' => CRM_Core_DAO::SERIALIZE_PHP, + 'default' => [ + 'con' => 'com', + 'couk' => 'co.uk', + 'cpm' => 'com', + 'orguk' => 'org.uk', + ], + ], + 'emailamender.second_level_domain_corrections' => [ + 'group_name' => 'Email Amender', + 'group' => 'email_amender', + 'name' => 'emailamender.second_level_domain_corrections', + 'type' => 'String', + 'is_domain' => 1, + 'is_contact' => 0, + 'description' => E::ts('List of second level domains to correct'), + 'title' => E::ts('Second level domains'), + 'help_text' => '', + 'html_type' => '', + 'quick_form_type' => '', + 'serialize' => CRM_Core_DAO::SERIALIZE_PHP, + 'default' => [ + 'gmai' => 'gmail', + 'gamil' => 'gmail', + 'gmial' => 'gmail', + 'hotmai' => 'hotmail', + 'hotmal' => 'hotmail', + 'hotmil' => 'hotmail', + 'hotmial' => 'hotmail', + 'htomail' => 'hotmail', + 'tiscalli' => 'tiscali', + 'yaho' => 'yahoo', + ], + ], + 'emailamender.compound_top_level_domains' => [ + 'group_name' => 'Email Amender', + 'group' => 'email_amender', + 'name' => 'emailamender.compound_top_level_domains', + 'type' => 'String', + 'is_domain' => 1, + 'is_contact' => 0, + 'description' => E::ts('List of compound top level domains'), + 'title' => E::ts('Compound top level domains'), + 'help_text' => '', + 'html_type' => '', + 'quick_form_type' => '', + 'serialize' => CRM_Core_DAO::SERIALIZE_PHP, + 'default' => [ + '.ac.uk', + '.co.uk', + '.org.uk', + ], + ], + 'emailamender.equivalent_domains' => [ + 'group_name' => 'Email Amender', + 'group' => 'email_amender', + 'name' => 'equivalent_domains', + 'type' => 'String', + 'is_domain' => 1, + 'is_contact' => 0, + 'description' => E::ts('List of equivalent domains'), + 'title' => E::ts('Equivalent domains'), + 'help_text' => '', + 'html_type' => '', + 'quick_form_type' => '', + 'serialize' => CRM_Core_DAO::SERIALIZE_PHP, + 'default' => [ + 'gmail.com' => 'GMail', + 'googlemail.com' => 'GMail', + 'gmail.co.uk' => 'GMail UK', + 'googlemail.co.uk' => 'GMail UK', + ], + ], +]; diff --git a/templates/CRM/Emailamender/Form/Task/Correctemailaddresses.tpl b/templates/CRM/Emailamender/Form/Task/Correctemailaddresses.tpl index 0727d1d..af35da3 100644 --- a/templates/CRM/Emailamender/Form/Task/Correctemailaddresses.tpl +++ b/templates/CRM/Emailamender/Form/Task/Correctemailaddresses.tpl @@ -2,10 +2,10 @@ {* HEADER *} -{ts}Please check your Email Address Corrector settings before continuing{/ts}. +{ts}Please check your Email Address Corrector settings before continuing{/ts}.

-{ts}This will automatically correct incorrect email addresses attached to the contacts you've selected. -{ts}An activity will be added to each contact recording what has changed. +{ts}This will automatically correct incorrect email addresses attached to the contacts you've selected.{/ts} +{ts}An activity will be added to each contact recording what has changed.{/ts}

{$contactIdCount} {ts}contacts are due to be processed.{/ts} @@ -14,4 +14,4 @@ {include file="CRM/common/formButtons.tpl" location="bottom"} - \ No newline at end of file + diff --git a/templates/CRM/Emailamender/Page/EmailAmenderSettings.js b/templates/CRM/Emailamender/Page/EmailAmenderSettings.js index 41611af..409a3fb 100755 --- a/templates/CRM/Emailamender/Page/EmailAmenderSettings.js +++ b/templates/CRM/Emailamender/Page/EmailAmenderSettings.js @@ -1,193 +1,203 @@ var CRM = CRM || {}; -function on_any_change( filter_id ){ - jQuery('#'+filter_id).children('h3').css('background-color', '#98FB98'); - jQuery('#'+filter_id).children('.save_changes_button').fadeIn(); +function on_any_change(filter_id) { + jQuery('#' + filter_id).children('h3').css('background-color', '#98FB98'); + jQuery('#' + filter_id).children('.save_changes_button').fadeIn(); } -function input_box_change(){ - var filter_id = jQuery(this).attr('filter_id'); +function input_box_change() { + var filter_id = jQuery(this).attr('filter_id'); - var allPassedValidation = true; - var thisPassedValidation = true; + var allPassedValidation = true; + var thisPassedValidation = true; // TODO only adjust messages for this one - jQuery('#' + filter_id).find('input').each( function(){ - thisPassedValidation = true; - - // does it contain a full stop? if so bail - if ( jQuery(this).val().indexOf('.') >= 0 && jQuery(this).hasClass('correction_from') && filter_id != 'equivalent_domain' ){ - jQuery(this).siblings('.error_msg').text('Top level domains can\'t have full stops.'); - allPassedValidation = false; - thisPassedValidation = false; - - // input box can't be empty - } else if( jQuery(this).val().length == 0 ){ - jQuery(this).siblings('.error_msg').text('Corrections cannot be empty.'); - allPassedValidation = false; - thisPassedValidation = false; - } - - if ( jQuery(this).siblings('.error_msg').is(':visible') && thisPassedValidation ){ - jQuery(this).siblings('.error_msg').fadeOut(function (){ - jQuery(this).text(''); - }); - - } else if ( !jQuery(this).siblings('.error_msg').is(':visible') && !thisPassedValidation ){ - jQuery(this).siblings('.error_msg').fadeIn(); - } - }); - - if (!allPassedValidation){ - jQuery('#'+filter_id).children('h3').css('background-color', '#FFB6C1'); - jQuery('#'+filter_id).children('.save_changes_button').fadeOut(); - return; - } - - on_any_change( filter_id ); + jQuery('#' + filter_id).find('input').each(function () { + thisPassedValidation = true; + + // does it contain a full stop? if so bail + if (jQuery(this).val().indexOf('.') >= 0 && jQuery(this).hasClass('correction_from') && filter_id != 'equivalent_domain') { + jQuery(this).siblings('.error_msg').text('Top level domains can\'t have full stops.'); + allPassedValidation = false; + thisPassedValidation = false; + + // input box can't be empty + } else if (jQuery(this).val().length == 0) { + jQuery(this).siblings('.error_msg').text('Corrections cannot be empty.'); + allPassedValidation = false; + thisPassedValidation = false; + } + + if (jQuery(this).siblings('.error_msg').is(':visible') && thisPassedValidation) { + jQuery(this).siblings('.error_msg').fadeOut(function () { + jQuery(this).text(''); + }); + + } else if (!jQuery(this).siblings('.error_msg').is(':visible') && !thisPassedValidation) { + jQuery(this).siblings('.error_msg').fadeIn(); + } + }); + + if (!allPassedValidation) { + jQuery('#' + filter_id).children('h3').css('background-color', '#FFB6C1'); + jQuery('#' + filter_id).children('.save_changes_button').fadeOut(); + return; + } + + on_any_change(filter_id); } -function delete_button(){ - var filter_id = jQuery(this).attr('filter_id'); - on_any_change( filter_id ); +function delete_button() { + var filter_id = jQuery(this).attr('filter_id'); + on_any_change(filter_id); - jQuery(this).parent().parent().fadeOut( function(){ - jQuery(this).remove(); - }); + jQuery(this).parent().parent().fadeOut(function () { + jQuery(this).remove(); + }); - return false; + return false; } -function on_save(){ - var filter_id = jQuery(this).attr('filter_id'); - - var aInputValuesFrom = new Array(); - var aInputValuesTo = new Array(); - - jQuery( '#'+ filter_id ).find('.correction_from').each(function (){ - aInputValuesFrom.push(jQuery(this).val()); - }); - - jQuery( '#'+ filter_id ).find('.correction_to').each(function (){ - aInputValuesTo.push(jQuery(this).val()); - }); - - CRM.api3 ('EmailAmender','update_corrections',{ 'sequential' :'1', 'domain_level' : filter_id, 'correction_keys' : aInputValuesFrom, 'correction_values' : aInputValuesTo} - ,{ success:function (data){ - // TODO indicate a successful save - // cj.each(data, function(key, value) {// do something }); - jQuery('#'+filter_id).children('.save_changes_button').fadeOut(); - jQuery('#'+filter_id).find('h3').css('background-color', '#CDE8FE'); - } - }); +function on_save() { + var filter_id = jQuery(this).attr('filter_id'); + + var aInputValuesFrom = new Array(); + var aInputValuesTo = new Array(); + + jQuery('#' + filter_id).find('.correction_from').each(function () { + aInputValuesFrom.push(jQuery(this).val()); + }); + + jQuery('#' + filter_id).find('.correction_to').each(function () { + aInputValuesTo.push(jQuery(this).val()); + }); + + CRM.api3('EmailAmender', 'update_corrections', { + 'sequential': '1', + 'domain_level': filter_id, + 'correction_keys': aInputValuesFrom, + 'correction_values': aInputValuesTo + } + , { + success: function (data) { + // TODO indicate a successful save + // cj.each(data, function(key, value) {// do something }); + jQuery('#' + filter_id).children('.save_changes_button').fadeOut(); + jQuery('#' + filter_id).find('h3').css('background-color', '#CDE8FE'); + } + }); } -function on_tld_save(){ - var aInputValues = new Array(); - jQuery('#compound_tld').find(':text').each(function (){ - aInputValues.push(jQuery(this).val()); - }); - CRM.api3 ('EmailAmender','update_compound_t_l_ds',{ 'sequential' :'1', 'compound_tlds' : aInputValues } - ,{ success:function (data){ - // TODO indicate a successful save - // cj.each(data, function(key, value) {// do something }); - jQuery('#compound_tld').find('.save_tld_changes').fadeOut(); - jQuery('#compound_tld').find('h3').css('background-color', '#CDE8FE'); - } - }); +function on_tld_save() { + var aInputValues = new Array(); + jQuery('#compound_tld').find(':text').each(function () { + aInputValues.push(jQuery(this).val()); + }); + CRM.api3('EmailAmender', 'update_compound_t_l_ds', {'sequential': '1', 'compound_tlds': aInputValues} + , { + success: function (data) { + // TODO indicate a successful save + // cj.each(data, function(key, value) {// do something }); + jQuery('#compound_tld').find('.save_tld_changes').fadeOut(); + jQuery('#compound_tld').find('h3').css('background-color', '#CDE8FE'); + } + }); } -jQuery('.add_new_correction').click( function(){ - var filter = jQuery(this).attr('filter_id'); +jQuery('.add_new_correction').click(function () { + var filter = jQuery(this).attr('filter_id'); + + var newFilterRow = ''; + jQuery('#' + filter + '_table tbody').append(newFilterRow); - var newFilterRow = ''; - jQuery('#'+filter+'_table tbody').append( newFilterRow ); + // Add new input boxes + var newFilterTextBox = ''; + jQuery('#' + filter + '_table tbody').children().last().children(':lt(2)').append(newFilterTextBox); + jQuery('#' + filter + '_table tbody').children().last().children(':lt(2)').append(''); - // Add new input boxes - var newFilterTextBox =''; - jQuery('#'+filter+'_table tbody').children().last().children(':lt(2)').append( newFilterTextBox ); - jQuery('#'+filter+'_table tbody').children().last().children(':lt(2)').append( '' ); - - // add the correction_from and correction_to classes - jQuery('#'+filter+'_table tbody').children().last().children(':eq(0)').find('input').addClass( 'correction_from' ); - jQuery('#'+filter+'_table tbody').children().last().children(':eq(1)').find('input').addClass( 'correction_to' ); + // add the correction_from and correction_to classes + jQuery('#' + filter + '_table tbody').children().last().children(':eq(0)').find('input').addClass('correction_from'); + jQuery('#' + filter + '_table tbody').children().last().children(':eq(1)').find('input').addClass('correction_to'); - // Add change listener to both new input boxes - jQuery('#'+filter+'_table tbody').children().last().find('input').change( input_box_change ); + // Add change listener to both new input boxes + jQuery('#' + filter + '_table tbody').children().last().find('input').change(input_box_change); - // Add new delete button - var newDeleteButton = jQuery('Delete this correction').click( delete_button ); - jQuery('#'+filter+'_table tbody').children().last().children().last().append( newDeleteButton ); + // Add new delete button + var newDeleteButton = jQuery('Delete this correction').click(delete_button); + jQuery('#' + filter + '_table tbody').children().last().children().last().append(newDeleteButton); - jQuery('#' + filter + '_table' ).find('tr:hidden').fadeIn(); + jQuery('#' + filter + '_table').find('tr:hidden').fadeIn(); }); // Very similar to .add_new_correction, except we're switching around the display of the 'key' box and the 'value' box -jQuery('.add_new_equivalent').click( function(){ - var filter = jQuery(this).attr('filter_id'); +jQuery('.add_new_equivalent').click(function () { + var filter = jQuery(this).attr('filter_id'); + + var newFilterRow = ''; + jQuery('#' + filter + '_table tbody').append(newFilterRow); - var newFilterRow = ''; - jQuery('#'+filter+'_table tbody').append( newFilterRow ); + // Add new input boxes + var newFilterTextBox = ''; + jQuery('#' + filter + '_table tbody').children().last().children(':lt(2)').append(newFilterTextBox); + jQuery('#' + filter + '_table tbody').children().last().children(':lt(2)').append(''); - // Add new input boxes - var newFilterTextBox =''; - jQuery('#'+filter+'_table tbody').children().last().children(':lt(2)').append( newFilterTextBox ); - jQuery('#'+filter+'_table tbody').children().last().children(':lt(2)').append( '' ); - - // add the correction_from and correction_to classes - jQuery('#'+filter+'_table tbody').children().last().children(':eq(0)').find('input').addClass( 'correction_to' ); - jQuery('#'+filter+'_table tbody').children().last().children(':eq(1)').find('input').addClass( 'correction_from' ); + // add the correction_from and correction_to classes + jQuery('#' + filter + '_table tbody').children().last().children(':eq(0)').find('input').addClass('correction_to'); + jQuery('#' + filter + '_table tbody').children().last().children(':eq(1)').find('input').addClass('correction_from'); - // Add change listener to both new input boxes - jQuery('#'+filter+'_table tbody').children().last().find('input').change( input_box_change ); + // Add change listener to both new input boxes + jQuery('#' + filter + '_table tbody').children().last().find('input').change(input_box_change); - // Add new delete button - var newDeleteButton = jQuery('Delete this equivalent').click( delete_button ); - jQuery('#'+filter+'_table tbody').children().last().children().last().append( newDeleteButton ); + // Add new delete button + var newDeleteButton = jQuery('Delete this equivalent').click(delete_button); + jQuery('#' + filter + '_table tbody').children().last().children().last().append(newDeleteButton); - jQuery('#' + filter + '_table' ).find('tr:hidden').fadeIn(); + jQuery('#' + filter + '_table').find('tr:hidden').fadeIn(); }); -jQuery('.add_new_compound_tld').click( function(){ - var filter = jQuery(this).attr('filter_id'); +jQuery('.add_new_compound_tld').click(function () { + var filter = jQuery(this).attr('filter_id'); - var newCompoundTLDRow = ''; - jQuery('#compound_tld_table tbody').append( newCompoundTLDRow ); + var newCompoundTLDRow = ''; + jQuery('#compound_tld_table tbody').append(newCompoundTLDRow); - // Add new input boxes - var newCompoundTLDTextBox =''; - jQuery('#compound_tld_table tbody').children().last().children(':lt(1)').append( newCompoundTLDTextBox ); - jQuery('#compound_tld_table tbody').children().last().children(':lt(1)').append( '' ); + // Add new input boxes + var newCompoundTLDTextBox = ''; + jQuery('#compound_tld_table tbody').children().last().children(':lt(1)').append(newCompoundTLDTextBox); + jQuery('#compound_tld_table tbody').children().last().children(':lt(1)').append(''); - // Add change listener to both new input boxes - jQuery('#compound_tld_table tbody').children().last().find('input').change( input_box_change ); + // Add change listener to both new input boxes + jQuery('#compound_tld_table tbody').children().last().find('input').change(input_box_change); - // Add new delete button - var newDeleteButton = jQuery('Delete this compound tld').click( delete_button ); - jQuery('#compound_tld_table tbody').children().last().children().last().append( newDeleteButton ); + // Add new delete button + var newDeleteButton = jQuery('Delete this compound tld').click(delete_button); + jQuery('#compound_tld_table tbody').children().last().children().last().append(newDeleteButton); - jQuery('#compound_tld_table' ).find('tr:hidden').fadeIn(); + jQuery('#compound_tld_table').find('tr:hidden').fadeIn(); }); -jQuery('#email_amender_enabled').click( function (){ - CRM.api3 ('EmailAmender','update_settings',{ 'sequential' :'1', 'email_amender_enabled' : jQuery(this).is(':checked').toString() } - ,{ success:function (data){ +jQuery('#email_amender_enabled').click(function () { + CRM.api3('Setting', 'create', { + 'emailamender.email_amender_enabled': jQuery(this).is(':checked') + } + , { + success: function (data) { - } - }); + } + }); }); // add event listeners -jQuery('.deleteButton').click( delete_button ); -jQuery('input').change( input_box_change ); -jQuery('.save_correction_changes').click( on_save ); -jQuery('.save_tld_changes').click( on_tld_save ); +jQuery('.deleteButton').click(delete_button); +jQuery('input').change(input_box_change); +jQuery('.save_correction_changes').click(on_save); +jQuery('.save_tld_changes').click(on_tld_save); jQuery('h3').css('-webkit-transition', 'background-color 0.4s linear'); jQuery('h3').css('-moz-transition', 'background-color 0.4s linear'); jQuery('h3').css('-ms-transition', 'background-color 0.4s linear'); jQuery('h3').css('-o-transition', 'background-color 0.4s linear'); -jQuery('h3').css('transition', 'background-color 0.4s linear'); +jQuery('h3').css('transition', 'background-color 0.4s linear'); diff --git a/templates/CRM/Emailamender/Page/EmailAmenderSettings.tpl b/templates/CRM/Emailamender/Page/EmailAmenderSettings.tpl index 3a426e6..ad5b67f 100755 --- a/templates/CRM/Emailamender/Page/EmailAmenderSettings.tpl +++ b/templates/CRM/Emailamender/Page/EmailAmenderSettings.tpl @@ -1,15 +1,29 @@ -

{ts}When the Enable Automatic Email Corrections setting below is checked, email addresses are corrected automatically as they are added. So john@hotmai.cpm would be corrected to john@hotmail.com{/ts}


+

{ts}When the Enable Automatic Email Corrections setting below is checked, email addresses are corrected automatically as they are added. So + john@hotmai.cpm + would be corrected to + john@hotmail.com + {/ts}


-{ts}Enable automatic email corrections.{/ts} + {ts}Enable automatic email corrections.{/ts}

-

The Email Amender has been designed not to affect edits made to any email addresses, or to change any email addresses that are already in your system. It will only act when new email addresses are added.

-You can add, remove, and edit the automatic corrections using the forms below.

-There are two types of corrections that can be made. Top Level Domains, such as "com" in "john@hotmail.com", have one set of corrections. Second Level Domains, such as "gmail" in "john@gmail.com" have another set of corrections.

-Incorrect Top Level Domains and Second Level Domains can be corrected in the same email address. So john@hotmai.cpm will be corrected to john@hotmail.com.

-Some Top Level Domains are "compounds", for instance ".co.uk" ".ac.uk" and ".org.uk". They are treated as a Top Level Domain, so john@hotmai.co.uk will be corrected to john@hotmail.co.uk, whereas john@hotmai.hotmai.com would be corrected to john@hotmai.hotmail.com. You can add new compound Top Level Domains using the form below.

-Subdomains are not examined, and neither is anything before the @ sign. So gmai@gmai.gmai.com will be corrected to gmai@gmai.gmail.com

-An activity of type "Amended Email" is recorded every time a correction is made, so you can review the impact that this Email Amender is having on your database.

+

The Email Amender has been designed not to affect edits made to any email addresses, or to change any email addresses + that are already in your system. It will only act when new email addresses are added.

+ You can add, remove, and edit the automatic corrections using the forms below.

+ There are two types of corrections that can be made. Top Level Domains, such as "com" in + "john@hotmail.com", have one set of corrections. Second Level Domains, such as "gmail" in + "john@gmail.com" have another set of corrections.

+ Incorrect Top Level Domains and Second Level Domains can be corrected in the same email address. So john@hotmai.cpm + will be corrected to john@hotmail.com.

+ Some Top Level Domains are "compounds", for instance ".co.uk" ".ac.uk" and ".org.uk". They are treated as a Top Level + Domain, so john@hotmai.co.uk will be corrected to john@hotmail.co.uk, whereas + john@hotmai.hotmai.com would be corrected to john@hotmai.hotmail.com. You can add + new compound Top Level Domains using the form below.

+ Subdomains are not examined, and neither is anything before the @ sign. So gmai@gmai.gmai.com will be + corrected to gmai@gmai.gmail.com

+ An activity of type "Amended Email" is recorded every time a correction is made, so you can review the impact that + this Email Amender is having on your database.

@@ -18,20 +32,21 @@ An activity of type "Amended Email" is recorded every time a correction is made, {include file="CRM/Emailamender/Page/EmailAmenderSettingsTable.tpl" title='Second Level Domain Settings' data=$second_level_filter_settings filter_id="second_level_domain"}

-

{ts}Compound Top Level Domain Names{/ts}

-{ts}"Compound" Top Level Domain Names indicate second level domain names that are usually treated as part of the first. For instance, in the case of the incorrect email address john@gmai.co.uk, we want to repair the 'gmai', not the 'co'.{/ts} - - - - {foreach from=$compound_top_level_domains item=compoundTld} - - - - - {/foreach} -
Compound Domain NameOptions
{ts}Delete this compound tld{/ts}
- - +

{ts}Compound Top Level Domain Names{/ts}

+ {ts}"Compound" Top Level Domain Names indicate second level domain names that are usually treated as part of the first. For instance, in the case of the incorrect email address john@gmai.co.uk, we want to repair the 'gmai', not the 'co'.{/ts} + + + + {foreach from=$compound_top_level_domains item=compoundTld} + + + + + {/foreach} +
Compound Domain NameOptions
{ts}Delete this compound tld{/ts}
+ +


{include file="CRM/Emailamender/Page/EquivalentsTable.tpl" title='Equivalent Domains' data=$equivalent_domain_settings filter_id="equivalent_domain"} diff --git a/tests/phpunit/CRM/Emailamender/BatchUpdateTest.php b/tests/phpunit/CRM/Emailamender/BatchUpdateTest.php new file mode 100644 index 0000000..584e9a0 --- /dev/null +++ b/tests/phpunit/CRM/Emailamender/BatchUpdateTest.php @@ -0,0 +1,106 @@ +installMe(__DIR__) + ->apply(); + } + + public function setUp(): void { + $this->callAPISuccess('Setting', 'create', [ + 'emailamender.email_amender_enabled' => 'true', + ]); + // Cleanup first in case any values are 'hanging around' + $this->callApiSuccess('EmailAmender', 'batch_update', [])['values']; + parent::setUp(); + $activities = $this->callAPISuccess('Activity', 'get', ['return' => 'id', 'activity_type_id' => 'corrected_email_address', 'sequential' => 1, 'options' => ['sort' => 'id DESC', 'limit' => 1]])['values']; + $this->maxExistingActivityID = $activities[0] ?? 0; + } + + public function tearDown(): void { + $this->callApiSuccess('Activity', 'get', ['activity_type_id' => 'corrected_email_address', 'id' => ['>' => $this->maxExistingActivityID], 'api.Activity.delete' => TRUE]); + foreach ($this->ids['Contact'] as $contactID) { + $this->callAPISuccess('Contact', 'delete', ['skip_undelete' => 1, 'id' => $contactID]); + } + parent::tearDown(); + } + + /** + * Test for email addresses on contacts created via the API. + * + * @throws \CRM_Core_Exception + */ + public function testBatchUpdate() { + $this->callApiSuccess('Setting', 'create', ['emailamender.email_amender_enabled' => FALSE]); + $testEmailCorrections = [ + // Test contacts with an incorrect top level domain. + 'john@gmail.cpm' => 'john@gmail.com', + 'john@hotmail.con' => 'john@hotmail.com', + + // Test contacts with an incorrect second level domain. + 'john@gmial.com' => 'john@gmail.com', + 'john@hotmial.com' => 'john@hotmail.com', + 'john@hotmil.com' => 'john@hotmail.com', + 'john@yaho.com' => 'john@yahoo.com', + + // Test contacts with both an incorrect top and second level domain. + 'john@gmial.con' => 'john@gmail.com', + + // Test contacts with a compound top level domain. + 'john@gmial.ac.uk' => 'john@gmail.ac.uk', + + // Test contacts with a three level domain. + 'john@gmial.gmial.com' => 'john@gmial.gmail.com', + // Test contacts with a three level domain and a compound top level domain. + 'john@gmial.gmial.ac.uk' => 'john@gmial.gmail.ac.uk', + ]; + + foreach ($testEmailCorrections as $incorrectEmailAddress => $expectedOutput) { + $this->ids['Contact'][] = $this->callApiSuccess('Contact', 'create', ['contact_type' => 'Individual', 'email' => $incorrectEmailAddress])['id']; + } + + $candidates = $this->callApiSuccess('EmailAmender', 'find_candidates', [])['values']; + $this->assertCount(10, $candidates); + + $clean = $this->callApiSuccess('EmailAmender', 'batch_update', [])['values']; + $this->assertCount(10, $clean); + + $candidates = $this->callApiSuccess('EmailAmender', 'find_candidates', [])['values']; + // Still 2 because we aren't catching the sub domain ones yet. + $this->assertCount(2, $candidates); + + $this->callApiSuccessGetCount('Activity', ['activity_type_id' => 'corrected_email_address', 'id' => ['>' => $this->maxExistingActivityID]], 10); + $this->assertEquals('john@gmail.com', $this->callAPISuccessGetValue('Contact', ['id' => $this->ids['Contact'][0], 'return' => 'display_name'])); + } + +} diff --git a/tests/phpunit/CRM/Emailamender/EquivalentmatcherTest.php b/tests/phpunit/CRM/Emailamender/EquivalentmatcherTest.php index 1335240..76e06c4 100644 --- a/tests/phpunit/CRM/Emailamender/EquivalentmatcherTest.php +++ b/tests/phpunit/CRM/Emailamender/EquivalentmatcherTest.php @@ -19,7 +19,7 @@ * * @group headless */ -class CRM_Emailamender_EquivalentmatcherTest extends \PHPUnit_Framework_TestCase implements HeadlessInterface, HookInterface, TransactionalInterface { +class CRM_Emailamender_EquivalentmatcherTest extends \PHPUnit\Framework\TestCase implements HeadlessInterface, HookInterface, TransactionalInterface { public function setUpHeadless() { // Civi\Test has many helpers, like install(), uninstall(), sql(), and sqlFile(). @@ -29,11 +29,11 @@ public function setUpHeadless() { ->apply(); } - public function setUp() { + public function setUp(): void { parent::setUp(); } - public function tearDown() { + public function tearDown(): void { parent::tearDown(); } @@ -41,7 +41,7 @@ public function tearDown() { * Example: Test that a version is returned. */ public function testEquivalentMatch() { - + // Test contact with gmail address receiving a googlemail email. $gmailContactDetails = civicrm_api3('contact', 'create', array('contact_type' => 'Individual', 'email' => 'gmailtest@gmail.com')); $gmailContactResult = NULL; diff --git a/tests/phpunit/CRM/Emailamender/IntegrationTest.php b/tests/phpunit/CRM/Emailamender/IntegrationTest.php index c263cbc..4efdad9 100644 --- a/tests/phpunit/CRM/Emailamender/IntegrationTest.php +++ b/tests/phpunit/CRM/Emailamender/IntegrationTest.php @@ -18,7 +18,8 @@ * * @group headless */ -class CRM_Emailamender_IntegrationTest extends \PHPUnit_Framework_TestCase implements HeadlessInterface, HookInterface, TransactionalInterface { +class CRM_Emailamender_IntegrationTest extends \PHPUnit\Framework\TestCase implements HeadlessInterface, HookInterface, TransactionalInterface { + use \Civi\Test\Api3TestTrait; public function setUpHeadless() { // Civi\Test has many helpers, like install(), uninstall(), sql(), and sqlFile(). @@ -28,15 +29,26 @@ public function setUpHeadless() { ->apply(); } - public function setUp() { - civicrm_api3('EmailAmender', 'update_settings', array( - 'sequential' => 1, - 'email_amender_enabled' => 'true', - )); + public function setUp(): void { + $this->callApiSuccess('Setting', 'create', [ + 'emailamender.email_amender_enabled' => TRUE, + ]); parent::setUp(); + $activities = $this->callAPISuccess('Activity', 'get', ['return' => 'id', 'activity_type_id' => 'corrected_email_address', 'sequential' => 1, 'options' => ['sort' => 'id DESC', 'limit' => 1]])['values']; + $this->maxExistingActivityID = $activities[0] ?? 0; } - public function tearDown() { + /** + * Ids of entities created. + * @var array + */ + protected $ids = []; + + public function tearDown(): void { + $this->callApiSuccess('Activity', 'get', ['activity_type_id' => 'corrected_email_address', 'id' => ['>' => (int) $this->maxExistingActivityID], 'api.Activity.delete' => TRUE]); + foreach (($this->ids['Contact'] ?? [])as $contactID) { + $this->callAPISuccess('Contact', 'delete', ['skip_undelete' => 1, 'id' => $contactID]); + } parent::tearDown(); } @@ -44,39 +56,40 @@ public function tearDown() { * Utility function that uses the API to create a contact. * * @param string $emailAddress - * @return int created contact id + * + * @return array + * + * @throws \CRM_Core_Exception */ public function createTestContact($emailAddress) { - $createContactResults = civicrm_api('Contact', 'create', array( - 'version' => 3, - 'sequential' => 1, + $createContactResults = $this->callApiSuccess('Contact', 'create', [ 'contact_type' => 'individual', 'email' => $emailAddress, - )); + ]); - $getEmailAddressResults = civicrm_api('Email', 'get', array( - 'version' => 3, - 'sequential' => 1, - 'contact_id' => $createContactResults['id'], - )); - - return $getEmailAddressResults['values'][0]; + return $this->callApiSuccessGetSingle('Email', ['contact_id' => $createContactResults['id']]); } + /** + * @param int $contactId + * + * @return array|int + * @throws \CRM_Core_Exception + */ public function getCorrectedEmailAddressActivityCount($contactId) { - return civicrm_api('Activity', 'getcount', array( - 'version' => 3, - 'sequential' => 1, + return $this->callApiSuccessGetCount('Activity', [ 'contact_id' => $contactId, 'activity_type_id' => 'corrected_email_address', - )); + ]); } /** * Test for email addresses on contacts created via the API. + * + * @throws \CRM_Core_Exception */ public function testContactCreateApi() { - $testEmailCorrections = array( + $testEmailCorrections = [ // Test contacts with an incorrect top level domain. 'john@gmail.cpm' => 'john@gmail.com', 'john@hotmail.con' => 'john@hotmail.com', @@ -97,16 +110,16 @@ public function testContactCreateApi() { 'john@gmial.gmial.com' => 'john@gmial.gmail.com', // Test contacts with a three level domain and a compound top level domain. 'john@gmial.gmial.ac.uk' => 'john@gmial.gmail.ac.uk', - ); + ]; - foreach($testEmailCorrections as $incorrectEmailAddress => $expectedOutput){ - $emailDetails = self::createTestContact($incorrectEmailAddress); + foreach ($testEmailCorrections as $incorrectEmailAddress => $expectedOutput) { + $emailDetails = $this->createTestContact($incorrectEmailAddress); // Test the email is correct. - $this->assertEquals($expectedOutput, $emailDetails['email']); + $this->assertEquals($expectedOutput, $emailDetails['email'], print_r($this->callApiSuccess('Setting', 'get', [])['values'], TRUE)); // Test the expected activity is present. - $this->assertEquals(1, self::getCorrectedEmailAddressActivityCount($emailDetails['contact_id'])); + $this->assertEquals(1, $this->getCorrectedEmailAddressActivityCount($emailDetails['contact_id'])); } } @@ -114,107 +127,102 @@ public function testContactCreateApi() { * Test that email addresses aren't updated if the setting is disabled. */ public function testEnabledSettingOff() { - civicrm_api3('EmailAmender', 'update_settings', array( - 'sequential' => 1, - 'email_amender_enabled' => 0, - )); - $emailDetails = self::createTestContact('john@yaho.com'); + $this->callApiSuccess('Setting', 'create', [ + 'emailamender.email_amender_enabled' => FALSE, + ]); + $emailDetails = $this->createTestContact('john@yaho.com'); $this->assertEquals('john@yaho.com', $emailDetails['email']); - $this->assertEquals(0, self::getCorrectedEmailAddressActivityCount($emailDetails['contact_id']), 'Found: ' . print_r(self::getCorrectedEmailAddressActivityCount($emailDetails['contact_id']), TRUE)); + $this->assertEquals(0, $this->getCorrectedEmailAddressActivityCount($emailDetails['contact_id']), 'Found: ' . print_r(self::getCorrectedEmailAddressActivityCount($emailDetails['contact_id']), TRUE)); } /** * Ensures that two corrections of the same type doesn't cause a problem. */ public function testTwoCorrections() { - $emailDetails = self::createTestContact('john@yaho.com'); - civicrm_api('Email', 'create', array( - 'version' => 3, - 'sequential' => 1, + $emailDetails = $this->createTestContact('john@yaho.com'); + $this->callApiSuccess('Email', 'create', [ 'contact_id' => $emailDetails['contact_id'], 'location_type_id' => 1, 'email' => 'john@yaho.com', - )); + ]); - $getEmailResults = civicrm_api('Email', 'get', array( - 'version' => 3, - 'sequential' => 1, + $getEmailResults = $this->callApiSuccess('Email', 'get', [ 'contact_id' => $emailDetails['contact_id'], 'location_type_id' => 1, 'email' => 'john@yahoo.com', - )); + ]); $this->assertEquals(2, $getEmailResults['count'], 'Wrong number of corrected emails found. Expected 2 found ' . $getEmailResults['count']); - $this->assertEquals(2, self::getCorrectedEmailAddressActivityCount($emailDetails['contact_id'])); - } - - public function testApiEmailAddressUpdateApi(){ - + $this->assertEquals(2, $this->getCorrectedEmailAddressActivityCount($emailDetails['contact_id'])); } - public function testCsvImportCreateSingleContact(){ - $originalValues = array( + /** + * @throws \CRM_Core_Exception + * @throws \CiviCRM_API3_Exception + */ + public function testCsvImportCreateSingleContact() { + $originalValues = [ 'first_name' => 'Bill', 'last_name' => 'Gates', 'email' => 'john@yaho.com', - ); + ]; $fields = array_keys($originalValues); $values = array_values($originalValues); $parser = new CRM_Contact_Import_Parser_Contact($fields); $parser->_contactType = 'Individual'; - $parser->_onDuplicate = CRM_Import_Parser::DUPLICATE_UPDATE; + $parser->_onDuplicate = CRM_Import_Parser::DUPLICATE_NOCHECK; $parser->init(); $this->assertEquals( CRM_Import_Parser::VALID, - $parser->import(CRM_Import_Parser::DUPLICATE_UPDATE, $values), + $parser->import(CRM_Import_Parser::DUPLICATE_NOCHECK, $values), 'Return code from parser import was not as expected' ); // Will assert if contact doesn't exist. - $getContactResult = civicrm_api('Contact', 'getsingle', array('version' => 3, 'sequential' => 1, 'first_name' => 'Bill', 'last_name' => 'Gates')); + $this->ids['Contact'][0] = $this->callApiSuccessGetSingle('Contact', ['first_name' => 'Bill', 'last_name' => 'Gates'])['id']; - $getEmailResults = civicrm_api('Email', 'get', array( - 'version' => 3, - 'sequential' => 1, - 'contact_id' => $getContactResult['id'], + $this->callApiSuccessGetSingle('Email', [ + 'contact_id' => $this->ids['Contact'][0], 'email' => 'john@yahoo.com', - )); - $this->assertEquals(1, $getEmailResults['count']); + ]); } - public function testCsvImportDuplicateActionTypes(){ - $duplicateActionTypes = array( + /** + * @throws \CRM_Core_Exception + * @throws \CiviCRM_API3_Exception + */ + public function testCsvImportDuplicateActionTypes() { + $this->ids['Contact'] = $this->ids['Contact'] ?? []; + $duplicateActionTypes = [ CRM_Import_Parser::DUPLICATE_SKIP, CRM_Import_Parser::DUPLICATE_REPLACE, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::DUPLICATE_FILL, CRM_Import_Parser::DUPLICATE_NOCHECK, - ); + ]; - foreach($duplicateActionTypes as $duplicateActionType) { + foreach ($duplicateActionTypes as $duplicateActionType) { // Initialise the duplicate contact. $firstName = 'Bill ' . $duplicateActionType; $incorrectEmailAddress = 'bill' . $duplicateActionType . '@hotmial.com'; $correctEmailAddress = 'bill' . $duplicateActionType . '@hotmail.com'; // Create the duplicate contact. - $createContactResult = civicrm_api('Contact', 'create', array( - 'version' => 3, - 'sequential' => 1, - 'contact_type' => 'Individual', - 'first_name' => $firstName, - 'last_name' => 'Gates', + $this->callApiSuccess('Contact', 'create', [ + 'contact_type' => 'Individual', + 'first_name' => $firstName, + 'last_name' => 'Gates', 'email' => $correctEmailAddress, - )); + ])['id']; // Perform the import of duplicate contacts. - $importValues = array( + $importValues = [ 'first_name' => $firstName, 'last_name' => 'Gates', 'email' => $incorrectEmailAddress, - ); - + ]; + $fields = array_keys($importValues); $values = array_values($importValues); $parser = new CRM_Contact_Import_Parser_Contact($fields); @@ -230,16 +238,10 @@ public function testCsvImportDuplicateActionTypes(){ // Check the results. // Currently the Email Address Corrector doesn't dedupe after changing the email address. // So we just check that both contacts exist and haven't broken on their way in. - $getTotalContactsResult = civicrm_api('Contact', 'get', array('version' => 3, 'sequential' => 1, 'first_name' => $firstName, 'last_name' => 'Gates', 'email' => $correctEmailAddress)); - $this->assertEquals(2, $getTotalContactsResult['count']); + $getContacts = $this->callApiSuccess('Contact', 'get', ['first_name' => $firstName, 'last_name' => 'Gates', 'email' => $correctEmailAddress])['values']; + $this->ids['Contact'] = array_merge(array_keys($getContacts), $this->ids['Contact']); + $this->assertCount(2, $getContacts); } } - public function testContactCreateEmailProcess(){} - - public function testContactUpdateEmailProcess(){} - - public function testOnDedupe(){ - - } }