From b2946d26e506460ed835c3eec963f6c697707a49 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Thu, 6 Apr 2023 14:52:08 -0400 Subject: [PATCH] Mailing - Rename trackable URL entities for consistency and add APIv4 --- CRM/Activity/Form/ActivityView.php | 2 +- CRM/Core/DAO/AllCoreTables.data.php | 12 +- CRM/Mailing/BAO/Mailing.php | 8 +- CRM/Mailing/BAO/MailingTrackableURL.php | 170 +++++++++++++ CRM/Mailing/BAO/TrackableURL.php | 169 +------------ CRM/Mailing/DAO/MailingTrackableURL.php | 238 ++++++++++++++++++ CRM/Mailing/DAO/TrackableURL.php | 236 +---------------- ...h.php => MailingEventTrackableURLOpen.php} | 8 +- CRM/Mailing/Event/BAO/TrackableURLOpen.php | 5 +- ...h.php => MailingEventTrackableURLOpen.php} | 36 +-- CRM/Mailing/Event/DAO/TrackableURLOpen.php | 4 +- CRM/Mailing/Page/Url.php | 2 +- CRM/Mailing/Selector/Event.php | 6 +- CRM/Report/Form/Mailing/Clicks.php | 4 +- Civi/Api4/MailingEventTrackableURLOpen.php | 23 ++ Civi/Api4/MailingTrackableURL.php | 22 ++ api/v3/Mailing.php | 6 +- api/v3/MailingAB.php | 10 +- .../src/ClickTracker/HtmlClickTracker.php | 2 +- .../src/ClickTracker/TextClickTracker.php | 2 +- .../Civi/FlexMailer/ClickTrackerTest.php | 8 +- extern/url.php | 2 +- tests/phpunit/CRM/Mailing/BAO/QueryTest.php | 6 +- tests/phpunit/api/v3/MailingTest.php | 8 +- ...h.xml => MailingEventTrackableURLOpen.xml} | 12 +- xml/schema/Mailing/Event/files.xml | 2 +- ...ackableURL.xml => MailingTrackableURL.xml} | 5 +- xml/schema/Mailing/files.xml | 2 +- 28 files changed, 544 insertions(+), 466 deletions(-) create mode 100644 CRM/Mailing/BAO/MailingTrackableURL.php create mode 100644 CRM/Mailing/DAO/MailingTrackableURL.php rename CRM/Mailing/Event/BAO/{MailingEventClickThrough.php => MailingEventTrackableURLOpen.php} (96%) rename CRM/Mailing/Event/DAO/{MailingEventClickThrough.php => MailingEventTrackableURLOpen.php} (86%) create mode 100644 Civi/Api4/MailingEventTrackableURLOpen.php create mode 100644 Civi/Api4/MailingTrackableURL.php rename xml/schema/Mailing/Event/{MailingEventClickThrough.xml => MailingEventTrackableURLOpen.xml} (83%) rename xml/schema/Mailing/{TrackableURL.xml => MailingTrackableURL.xml} (88%) diff --git a/CRM/Activity/Form/ActivityView.php b/CRM/Activity/Form/ActivityView.php index 310840b366..6ff714c92b 100644 --- a/CRM/Activity/Form/ActivityView.php +++ b/CRM/Activity/Form/ActivityView.php @@ -73,7 +73,7 @@ class CRM_Activity_Form_ActivityView extends CRM_Core_Form { $this->_mailing_id, NULL, FALSE, NULL, NULL, NULL, $cid); $this->assign('openreport', $full_open_report); - $click_thru_report = CRM_Mailing_Event_BAO_MailingEventClickThrough::getRows($this->_mailing_id, NULL, FALSE, NULL, NULL, NULL, NULL, $cid); + $click_thru_report = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getRows($this->_mailing_id, NULL, FALSE, NULL, NULL, NULL, NULL, $cid); $this->assign('clickreport', $click_thru_report); } diff --git a/CRM/Core/DAO/AllCoreTables.data.php b/CRM/Core/DAO/AllCoreTables.data.php index e043d1c0cb..9251e2b752 100644 --- a/CRM/Core/DAO/AllCoreTables.data.php +++ b/CRM/Core/DAO/AllCoreTables.data.php @@ -592,9 +592,9 @@ return [ 'class' => 'CRM_Mailing_DAO_MailingGroup', 'table' => 'civicrm_mailing_group', ], - 'CRM_Mailing_DAO_TrackableURL' => [ - 'name' => 'TrackableURL', - 'class' => 'CRM_Mailing_DAO_TrackableURL', + 'CRM_Mailing_DAO_MailingTrackableURL' => [ + 'name' => 'MailingTrackableURL', + 'class' => 'CRM_Mailing_DAO_MailingTrackableURL', 'table' => 'civicrm_mailing_trackable_url', ], 'CRM_Mailing_DAO_MailingJob' => [ @@ -642,9 +642,9 @@ return [ 'class' => 'CRM_Mailing_Event_DAO_MailingEventReply', 'table' => 'civicrm_mailing_event_reply', ], - 'CRM_Mailing_Event_DAO_MailingEventClickThrough' => [ - 'name' => 'MailingEventClickThrough', - 'class' => 'CRM_Mailing_Event_DAO_MailingEventClickThrough', + 'CRM_Mailing_Event_DAO_MailingEventTrackableURLOpen' => [ + 'name' => 'MailingEventTrackableURLOpen', + 'class' => 'CRM_Mailing_Event_DAO_MailingEventTrackableURLOpen', 'table' => 'civicrm_mailing_event_trackable_url_open', ], 'CRM_Mailing_Event_DAO_MailingEventUnsubscribe' => [ diff --git a/CRM/Mailing/BAO/Mailing.php b/CRM/Mailing/BAO/Mailing.php index 2ca7e67f9c..5967419e09 100644 --- a/CRM/Mailing/BAO/Mailing.php +++ b/CRM/Mailing/BAO/Mailing.php @@ -1366,7 +1366,7 @@ ORDER BY civicrm_email.is_bulkmail DESC if ($this->url_tracking && !empty($this->id)) { // ensure that Google CSS and any .css files are not tracked. if (!(strpos($token, 'css?family') || strpos($token, '.css'))) { - $data = CRM_Mailing_BAO_TrackableURL::getTrackerURL($token, $this->id, $event_queue_id); + $data = CRM_Mailing_BAO_MailingTrackableURL::getTrackerURL($token, $this->id, $event_queue_id); if (!empty($html)) { $data = htmlentities($data, ENT_NOQUOTES); } @@ -1754,8 +1754,8 @@ ORDER BY civicrm_email.is_bulkmail DESC 'unsubscribe' => CRM_Mailing_Event_BAO_MailingEventUnsubscribe::getTableName(), 'bounce' => CRM_Mailing_Event_BAO_MailingEventBounce::getTableName(), 'forward' => CRM_Mailing_Event_BAO_MailingEventForward::getTableName(), - 'url' => CRM_Mailing_BAO_TrackableURL::getTableName(), - 'urlopen' => CRM_Mailing_Event_BAO_MailingEventClickThrough::getTableName(), + 'url' => CRM_Mailing_BAO_MailingTrackableURL::getTableName(), + 'urlopen' => CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getTableName(), 'component' => CRM_Mailing_BAO_MailingComponent::getTableName(), 'spool' => CRM_Mailing_BAO_Spool::getTableName(), ]; @@ -2821,7 +2821,7 @@ ORDER BY civicrm_mailing.name"; //CRM-12814 if (!empty($mailings)) { $openCounts = CRM_Mailing_Event_BAO_MailingEventOpened::getMailingContactCount(array_keys($mailings), $params['contact_id']); - $clickCounts = CRM_Mailing_Event_BAO_MailingEventClickThrough::getMailingContactCount(array_keys($mailings), $params['contact_id']); + $clickCounts = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getMailingContactCount(array_keys($mailings), $params['contact_id']); } // format params and add links diff --git a/CRM/Mailing/BAO/MailingTrackableURL.php b/CRM/Mailing/BAO/MailingTrackableURL.php new file mode 100644 index 0000000000..2ebf1faa89 --- /dev/null +++ b/CRM/Mailing/BAO/MailingTrackableURL.php @@ -0,0 +1,170 @@ +url = $url; + $tracker->mailing_id = $mailing_id; + + if (!$tracker->find(TRUE)) { + $tracker->save(); + } + $id = $tracker->id; + + $redirect = CRM_Utils_System::externUrl('extern/url', "u=$id"); + $urlCache[$mailing_id . $url] = $redirect; + } + + // This looks silly - calling the hook twice. This smells like an accident. Restoring old cache-based lookup. + // $returnUrl = CRM_Utils_System::externUrl('extern/url', "u=$id&qid=$queue_id"); + $returnUrl = "{$urlCache[$mailing_id . $url]}&qid={$queue_id}"; + + if ($hrefExists) { + $returnUrl = "href='{$returnUrl}' rel='nofollow'"; + } + + return $returnUrl; + } + + /** + * Create a trackable URL for a URL with tokens. + * + * @param string $url + * @param int $mailing_id + * @param int|string $queue_id + * + * @return string + */ + private static function getTrackerURLForUrlWithTokens($url, $mailing_id, $queue_id) { + + // Parse the URL. + // (not using parse_url because it's messy to reassemble) + if (!preg_match('/^([^?#]+)([?][^#]*)?(#.*)?$/', $url, $parsed)) { + // Failed to parse it, give up and don't track it. + return $url; + } + + // If we have a token in the URL + path section, we can't tokenise. + if (strpos($parsed[1], '{') !== FALSE) { + return $url; + } + + $trackable_url = $parsed[1]; + + // Process the query parameters, if there are any. + $tokenised_params = []; + $static_params = []; + if (!empty($parsed[2])) { + $query_key_value_pairs = explode('&', substr($parsed[2], 1)); + + // Separate the tokenised from the static parts. + foreach ($query_key_value_pairs as $_) { + if (strpos($_, '{') === FALSE) { + $static_params[] = $_; + } + else { + $tokenised_params[] = $_; + } + } + // Add the static params to the trackable part. + if ($static_params) { + $trackable_url .= '?' . implode('&', $static_params); + } + } + + // Get trackable URL. + $data = self::getBasicTrackerURL($trackable_url, $mailing_id, $queue_id); + + // Append the tokenised bits and the fragment. + if ($tokenised_params) { + // We know the URL will already have the '?' + $data .= '&' . implode('&', $tokenised_params); + } + if (!empty($parsed[3])) { + $data .= $parsed[3]; + } + return $data; + } + + /** + * @param $url + * @param $mailing_id + * + * @return int + * Url id of the given url and mail + */ + public static function getTrackerURLId($url, $mailing_id) { + $tracker = new CRM_Mailing_BAO_MailingTrackableURL(); + $tracker->url = $url; + $tracker->mailing_id = $mailing_id; + if ($tracker->find(TRUE)) { + return $tracker->id; + } + + return NULL; + } + +} diff --git a/CRM/Mailing/BAO/TrackableURL.php b/CRM/Mailing/BAO/TrackableURL.php index f857f6eb9c..583ae4269a 100644 --- a/CRM/Mailing/BAO/TrackableURL.php +++ b/CRM/Mailing/BAO/TrackableURL.php @@ -1,170 +1,7 @@ url = $url; - $tracker->mailing_id = $mailing_id; - - if (!$tracker->find(TRUE)) { - $tracker->save(); - } - $id = $tracker->id; - - $redirect = CRM_Utils_System::externUrl('extern/url', "u=$id"); - $urlCache[$mailing_id . $url] = $redirect; - } - - // This looks silly - calling the hook twice. This smells like an accident. Restoring old cache-based lookup. - // $returnUrl = CRM_Utils_System::externUrl('extern/url', "u=$id&qid=$queue_id"); - $returnUrl = "{$urlCache[$mailing_id . $url]}&qid={$queue_id}"; - - if ($hrefExists) { - $returnUrl = "href='{$returnUrl}' rel='nofollow'"; - } - - return $returnUrl; - } - - /** - * Create a trackable URL for a URL with tokens. - * - * @param string $url - * @param int $mailing_id - * @param int|string $queue_id - * - * @return string - */ - private static function getTrackerURLForUrlWithTokens($url, $mailing_id, $queue_id) { - - // Parse the URL. - // (not using parse_url because it's messy to reassemble) - if (!preg_match('/^([^?#]+)([?][^#]*)?(#.*)?$/', $url, $parsed)) { - // Failed to parse it, give up and don't track it. - return $url; - } - - // If we have a token in the URL + path section, we can't tokenise. - if (strpos($parsed[1], '{') !== FALSE) { - return $url; - } - - $trackable_url = $parsed[1]; - - // Process the query parameters, if there are any. - $tokenised_params = []; - $static_params = []; - if (!empty($parsed[2])) { - $query_key_value_pairs = explode('&', substr($parsed[2], 1)); - - // Separate the tokenised from the static parts. - foreach ($query_key_value_pairs as $_) { - if (strpos($_, '{') === FALSE) { - $static_params[] = $_; - } - else { - $tokenised_params[] = $_; - } - } - // Add the static params to the trackable part. - if ($static_params) { - $trackable_url .= '?' . implode('&', $static_params); - } - } - - // Get trackable URL. - $data = self::getBasicTrackerURL($trackable_url, $mailing_id, $queue_id); - - // Append the tokenised bits and the fragment. - if ($tokenised_params) { - // We know the URL will already have the '?' - $data .= '&' . implode('&', $tokenised_params); - } - if (!empty($parsed[3])) { - $data .= $parsed[3]; - } - return $data; - } - - /** - * @param $url - * @param $mailing_id - * - * @return int - * Url id of the given url and mail - */ - public static function getTrackerURLId($url, $mailing_id) { - $tracker = new CRM_Mailing_BAO_TrackableURL(); - $tracker->url = $url; - $tracker->mailing_id = $mailing_id; - if ($tracker->find(TRUE)) { - return $tracker->id; - } - - return NULL; - } - -} +class_alias('CRM_Mailing_BAO_MailingTrackableURL', 'CRM_Mailing_BAO_TrackableURL'); diff --git a/CRM/Mailing/DAO/MailingTrackableURL.php b/CRM/Mailing/DAO/MailingTrackableURL.php new file mode 100644 index 0000000000..599cda1ef7 --- /dev/null +++ b/CRM/Mailing/DAO/MailingTrackableURL.php @@ -0,0 +1,238 @@ +__table = 'civicrm_mailing_trackable_url'; + parent::__construct(); + } + + /** + * Returns localized title of this entity. + * + * @param bool $plural + * Whether to return the plural version of the title. + */ + public static function getEntityTitle($plural = FALSE) { + return $plural ? ts('Mailing Links') : ts('Mailing Link'); + } + + /** + * Returns foreign keys and entity references. + * + * @return array + * [CRM_Core_Reference_Interface] + */ + public static function getReferenceColumns() { + if (!isset(Civi::$statics[__CLASS__]['links'])) { + Civi::$statics[__CLASS__]['links'] = static::createReferenceColumns(__CLASS__); + Civi::$statics[__CLASS__]['links'][] = new CRM_Core_Reference_Basic(self::getTableName(), 'mailing_id', 'civicrm_mailing', 'id'); + CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'links_callback', Civi::$statics[__CLASS__]['links']); + } + return Civi::$statics[__CLASS__]['links']; + } + + /** + * Returns all the column names of this table + * + * @return array + */ + public static function &fields() { + if (!isset(Civi::$statics[__CLASS__]['fields'])) { + Civi::$statics[__CLASS__]['fields'] = [ + 'id' => [ + 'name' => 'id', + 'type' => CRM_Utils_Type::T_INT, + 'title' => ts('Trackable URL ID'), + 'required' => TRUE, + 'usage' => [ + 'import' => FALSE, + 'export' => FALSE, + 'duplicate_matching' => FALSE, + 'token' => FALSE, + ], + 'where' => 'civicrm_mailing_trackable_url.id', + 'table_name' => 'civicrm_mailing_trackable_url', + 'entity' => 'MailingTrackableURL', + 'bao' => 'CRM_Mailing_BAO_MailingTrackableURL', + 'localizable' => 0, + 'html' => [ + 'type' => 'Number', + ], + 'readonly' => TRUE, + 'add' => NULL, + ], + 'url' => [ + 'name' => 'url', + 'type' => CRM_Utils_Type::T_TEXT, + 'title' => ts('Url'), + 'description' => ts('The URL to be tracked.'), + 'required' => TRUE, + 'usage' => [ + 'import' => FALSE, + 'export' => FALSE, + 'duplicate_matching' => FALSE, + 'token' => FALSE, + ], + 'where' => 'civicrm_mailing_trackable_url.url', + 'table_name' => 'civicrm_mailing_trackable_url', + 'entity' => 'MailingTrackableURL', + 'bao' => 'CRM_Mailing_BAO_MailingTrackableURL', + 'localizable' => 0, + 'add' => NULL, + ], + 'mailing_id' => [ + 'name' => 'mailing_id', + 'type' => CRM_Utils_Type::T_INT, + 'title' => ts('Mailing ID'), + 'description' => ts('FK to the mailing'), + 'required' => TRUE, + 'usage' => [ + 'import' => FALSE, + 'export' => FALSE, + 'duplicate_matching' => FALSE, + 'token' => FALSE, + ], + 'where' => 'civicrm_mailing_trackable_url.mailing_id', + 'table_name' => 'civicrm_mailing_trackable_url', + 'entity' => 'MailingTrackableURL', + 'bao' => 'CRM_Mailing_BAO_MailingTrackableURL', + 'localizable' => 0, + 'FKClassName' => 'CRM_Mailing_DAO_Mailing', + 'html' => [ + 'type' => 'EntityRef', + 'label' => ts("Mailing"), + ], + 'add' => NULL, + ], + ]; + CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'fields_callback', Civi::$statics[__CLASS__]['fields']); + } + return Civi::$statics[__CLASS__]['fields']; + } + + /** + * Return a mapping from field-name to the corresponding key (as used in fields()). + * + * @return array + * Array(string $name => string $uniqueName). + */ + public static function &fieldKeys() { + if (!isset(Civi::$statics[__CLASS__]['fieldKeys'])) { + Civi::$statics[__CLASS__]['fieldKeys'] = array_flip(CRM_Utils_Array::collect('name', self::fields())); + } + return Civi::$statics[__CLASS__]['fieldKeys']; + } + + /** + * Returns the names of this table + * + * @return string + */ + public static function getTableName() { + return self::$_tableName; + } + + /** + * Returns if this table needs to be logged + * + * @return bool + */ + public function getLog() { + return self::$_log; + } + + /** + * Returns the list of fields that can be imported + * + * @param bool $prefix + * + * @return array + */ + public static function &import($prefix = FALSE) { + $r = CRM_Core_DAO_AllCoreTables::getImports(__CLASS__, 'mailing_trackable_url', $prefix, []); + return $r; + } + + /** + * Returns the list of fields that can be exported + * + * @param bool $prefix + * + * @return array + */ + public static function &export($prefix = FALSE) { + $r = CRM_Core_DAO_AllCoreTables::getExports(__CLASS__, 'mailing_trackable_url', $prefix, []); + return $r; + } + + /** + * Returns the list of indices + * + * @param bool $localize + * + * @return array + */ + public static function indices($localize = TRUE) { + $indices = []; + return ($localize && !empty($indices)) ? CRM_Core_DAO_AllCoreTables::multilingualize(__CLASS__, $indices) : $indices; + } + +} diff --git a/CRM/Mailing/DAO/TrackableURL.php b/CRM/Mailing/DAO/TrackableURL.php index bd67cc8182..442cfb89bf 100644 --- a/CRM/Mailing/DAO/TrackableURL.php +++ b/CRM/Mailing/DAO/TrackableURL.php @@ -1,237 +1,7 @@ __table = 'civicrm_mailing_trackable_url'; - parent::__construct(); - } - - /** - * Returns localized title of this entity. - * - * @param bool $plural - * Whether to return the plural version of the title. - */ - public static function getEntityTitle($plural = FALSE) { - return $plural ? ts('Trackable URLs') : ts('Trackable URL'); - } - - /** - * Returns foreign keys and entity references. - * - * @return array - * [CRM_Core_Reference_Interface] - */ - public static function getReferenceColumns() { - if (!isset(Civi::$statics[__CLASS__]['links'])) { - Civi::$statics[__CLASS__]['links'] = static::createReferenceColumns(__CLASS__); - Civi::$statics[__CLASS__]['links'][] = new CRM_Core_Reference_Basic(self::getTableName(), 'mailing_id', 'civicrm_mailing', 'id'); - CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'links_callback', Civi::$statics[__CLASS__]['links']); - } - return Civi::$statics[__CLASS__]['links']; - } - - /** - * Returns all the column names of this table - * - * @return array - */ - public static function &fields() { - if (!isset(Civi::$statics[__CLASS__]['fields'])) { - Civi::$statics[__CLASS__]['fields'] = [ - 'id' => [ - 'name' => 'id', - 'type' => CRM_Utils_Type::T_INT, - 'title' => ts('Trackable URL ID'), - 'required' => TRUE, - 'usage' => [ - 'import' => FALSE, - 'export' => FALSE, - 'duplicate_matching' => FALSE, - 'token' => FALSE, - ], - 'where' => 'civicrm_mailing_trackable_url.id', - 'table_name' => 'civicrm_mailing_trackable_url', - 'entity' => 'TrackableURL', - 'bao' => 'CRM_Mailing_BAO_TrackableURL', - 'localizable' => 0, - 'html' => [ - 'type' => 'Number', - ], - 'readonly' => TRUE, - 'add' => NULL, - ], - 'url' => [ - 'name' => 'url', - 'type' => CRM_Utils_Type::T_TEXT, - 'title' => ts('Url'), - 'description' => ts('The URL to be tracked.'), - 'required' => TRUE, - 'usage' => [ - 'import' => FALSE, - 'export' => FALSE, - 'duplicate_matching' => FALSE, - 'token' => FALSE, - ], - 'where' => 'civicrm_mailing_trackable_url.url', - 'table_name' => 'civicrm_mailing_trackable_url', - 'entity' => 'TrackableURL', - 'bao' => 'CRM_Mailing_BAO_TrackableURL', - 'localizable' => 0, - 'add' => NULL, - ], - 'mailing_id' => [ - 'name' => 'mailing_id', - 'type' => CRM_Utils_Type::T_INT, - 'title' => ts('Mailing ID'), - 'description' => ts('FK to the mailing'), - 'required' => TRUE, - 'usage' => [ - 'import' => FALSE, - 'export' => FALSE, - 'duplicate_matching' => FALSE, - 'token' => FALSE, - ], - 'where' => 'civicrm_mailing_trackable_url.mailing_id', - 'table_name' => 'civicrm_mailing_trackable_url', - 'entity' => 'TrackableURL', - 'bao' => 'CRM_Mailing_BAO_TrackableURL', - 'localizable' => 0, - 'FKClassName' => 'CRM_Mailing_DAO_Mailing', - 'html' => [ - 'label' => ts("Mailing"), - ], - 'add' => NULL, - ], - ]; - CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'fields_callback', Civi::$statics[__CLASS__]['fields']); - } - return Civi::$statics[__CLASS__]['fields']; - } - - /** - * Return a mapping from field-name to the corresponding key (as used in fields()). - * - * @return array - * Array(string $name => string $uniqueName). - */ - public static function &fieldKeys() { - if (!isset(Civi::$statics[__CLASS__]['fieldKeys'])) { - Civi::$statics[__CLASS__]['fieldKeys'] = array_flip(CRM_Utils_Array::collect('name', self::fields())); - } - return Civi::$statics[__CLASS__]['fieldKeys']; - } - - /** - * Returns the names of this table - * - * @return string - */ - public static function getTableName() { - return self::$_tableName; - } - - /** - * Returns if this table needs to be logged - * - * @return bool - */ - public function getLog() { - return self::$_log; - } - - /** - * Returns the list of fields that can be imported - * - * @param bool $prefix - * - * @return array - */ - public static function &import($prefix = FALSE) { - $r = CRM_Core_DAO_AllCoreTables::getImports(__CLASS__, 'mailing_trackable_url', $prefix, []); - return $r; - } - - /** - * Returns the list of fields that can be exported - * - * @param bool $prefix - * - * @return array - */ - public static function &export($prefix = FALSE) { - $r = CRM_Core_DAO_AllCoreTables::getExports(__CLASS__, 'mailing_trackable_url', $prefix, []); - return $r; - } - - /** - * Returns the list of indices - * - * @param bool $localize - * - * @return array - */ - public static function indices($localize = TRUE) { - $indices = []; - return ($localize && !empty($indices)) ? CRM_Core_DAO_AllCoreTables::multilingualize(__CLASS__, $indices) : $indices; - } - -} +class_alias('CRM_Mailing_DAO_MailingTrackableURL', 'CRM_Mailing_DAO_TrackableURL'); diff --git a/CRM/Mailing/Event/BAO/MailingEventClickThrough.php b/CRM/Mailing/Event/BAO/MailingEventTrackableURLOpen.php similarity index 96% rename from CRM/Mailing/Event/BAO/MailingEventClickThrough.php rename to CRM/Mailing/Event/BAO/MailingEventTrackableURLOpen.php index 744276ee78..b77a59a889 100644 --- a/CRM/Mailing/Event/BAO/MailingEventClickThrough.php +++ b/CRM/Mailing/Event/BAO/MailingEventTrackableURLOpen.php @@ -14,7 +14,7 @@ * @package CRM * @copyright CiviCRM LLC https://civicrm.org/licensing */ -class CRM_Mailing_Event_BAO_MailingEventClickThrough extends CRM_Mailing_Event_DAO_MailingEventClickThrough { +class CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen extends CRM_Mailing_Event_DAO_MailingEventTrackableURLOpen { /** * Track a click-through and return the URL to redirect. @@ -34,7 +34,7 @@ class CRM_Mailing_Event_BAO_MailingEventClickThrough extends CRM_Mailing_Event_D // prevents foreign key violations. $job = CRM_Utils_Type::escape(CRM_Mailing_BAO_MailingJob::getTableName(), 'MysqlColumnNameOrAlias'); $eq = CRM_Utils_Type::escape(CRM_Mailing_Event_BAO_MailingEventQueue::getTableName(), 'MysqlColumnNameOrAlias'); - $turl = CRM_Utils_Type::escape(CRM_Mailing_BAO_TrackableURL::getTableName(), 'MysqlColumnNameOrAlias'); + $turl = CRM_Utils_Type::escape(CRM_Mailing_BAO_MailingTrackableURL::getTableName(), 'MysqlColumnNameOrAlias'); if (!$queue_id) { $search = CRM_Core_DAO::executeQuery( @@ -84,7 +84,7 @@ class CRM_Mailing_Event_BAO_MailingEventClickThrough extends CRM_Mailing_Event_D return $search->url; } - $open = new CRM_Mailing_Event_BAO_MailingEventClickThrough(); + $open = new CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen(); $open->event_queue_id = $queue_id; $open->trackable_url_id = $url_id; $open->time_stamp = date('YmdHis'); @@ -272,7 +272,7 @@ class CRM_Mailing_Event_BAO_MailingEventClickThrough extends CRM_Mailing_Event_D $dao = new CRM_Core_DAO(); $click = self::getTableName(); - $url = CRM_Mailing_BAO_TrackableURL::getTableName(); + $url = CRM_Mailing_BAO_MailingTrackableURL::getTableName(); $queue = CRM_Mailing_Event_BAO_MailingEventQueue::getTableName(); $mailing = CRM_Mailing_BAO_Mailing::getTableName(); $job = CRM_Mailing_BAO_MailingJob::getTableName(); diff --git a/CRM/Mailing/Event/BAO/TrackableURLOpen.php b/CRM/Mailing/Event/BAO/TrackableURLOpen.php index 49c982971f..2e8e70e3a1 100644 --- a/CRM/Mailing/Event/BAO/TrackableURLOpen.php +++ b/CRM/Mailing/Event/BAO/TrackableURLOpen.php @@ -1,6 +1,7 @@ 'civicrm_mailing_event_trackable_url_open.id', 'table_name' => 'civicrm_mailing_event_trackable_url_open', - 'entity' => 'MailingEventClickThrough', - 'bao' => 'CRM_Mailing_Event_BAO_MailingEventClickThrough', + 'entity' => 'MailingEventTrackableURLOpen', + 'bao' => 'CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen', 'localizable' => 0, 'html' => [ 'type' => 'Number', @@ -144,11 +144,12 @@ class CRM_Mailing_Event_DAO_MailingEventClickThrough extends CRM_Core_DAO { ], 'where' => 'civicrm_mailing_event_trackable_url_open.event_queue_id', 'table_name' => 'civicrm_mailing_event_trackable_url_open', - 'entity' => 'MailingEventClickThrough', - 'bao' => 'CRM_Mailing_Event_BAO_MailingEventClickThrough', + 'entity' => 'MailingEventTrackableURLOpen', + 'bao' => 'CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen', 'localizable' => 0, 'FKClassName' => 'CRM_Mailing_Event_DAO_MailingEventQueue', 'html' => [ + 'type' => 'EntityRef', 'label' => ts("Recipient"), ], 'add' => NULL, @@ -167,12 +168,13 @@ class CRM_Mailing_Event_DAO_MailingEventClickThrough extends CRM_Core_DAO { ], 'where' => 'civicrm_mailing_event_trackable_url_open.trackable_url_id', 'table_name' => 'civicrm_mailing_event_trackable_url_open', - 'entity' => 'MailingEventClickThrough', - 'bao' => 'CRM_Mailing_Event_BAO_MailingEventClickThrough', + 'entity' => 'MailingEventTrackableURLOpen', + 'bao' => 'CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen', 'localizable' => 0, - 'FKClassName' => 'CRM_Mailing_DAO_TrackableURL', + 'FKClassName' => 'CRM_Mailing_DAO_MailingTrackableURL', 'html' => [ - 'label' => ts("Trackable Url"), + 'type' => 'EntityRef', + 'label' => ts("Mailing Link"), ], 'add' => NULL, ], @@ -191,9 +193,13 @@ class CRM_Mailing_Event_DAO_MailingEventClickThrough extends CRM_Core_DAO { 'where' => 'civicrm_mailing_event_trackable_url_open.time_stamp', 'default' => 'CURRENT_TIMESTAMP', 'table_name' => 'civicrm_mailing_event_trackable_url_open', - 'entity' => 'MailingEventClickThrough', - 'bao' => 'CRM_Mailing_Event_BAO_MailingEventClickThrough', + 'entity' => 'MailingEventTrackableURLOpen', + 'bao' => 'CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen', 'localizable' => 0, + 'html' => [ + 'type' => 'Date', + 'label' => ts("Opened Date"), + ], 'add' => NULL, ], ]; diff --git a/CRM/Mailing/Event/DAO/TrackableURLOpen.php b/CRM/Mailing/Event/DAO/TrackableURLOpen.php index 0ae51d882e..4dc33c7be9 100644 --- a/CRM/Mailing/Event/DAO/TrackableURLOpen.php +++ b/CRM/Mailing/Event/DAO/TrackableURLOpen.php @@ -1,7 +1,7 @@ extractPassthroughParameters(); if (strlen($query_string) > 0) { diff --git a/CRM/Mailing/Selector/Event.php b/CRM/Mailing/Selector/Event.php index 0ef9775140..355ba92d7b 100644 --- a/CRM/Mailing/Selector/Event.php +++ b/CRM/Mailing/Selector/Event.php @@ -217,7 +217,7 @@ class CRM_Mailing_Selector_Event extends CRM_Core_Selector_Base implements CRM_C break; case 'click': - $dateSort = CRM_Mailing_Event_BAO_MailingEventClickThrough::getTableName() . '.time_stamp'; + $dateSort = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getTableName() . '.time_stamp'; $this->_columnHeaders = array_merge($this->_columnHeaders, [ [ 'name' => ts('URL'), @@ -315,7 +315,7 @@ class CRM_Mailing_Selector_Event extends CRM_Core_Selector_Base implements CRM_C return $result; case 'click': - $event = new CRM_Mailing_Event_BAO_MailingEventClickThrough(); + $event = new CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen(); $result = $event->getTotalCount($this->_mailing_id, $this->_job_id, $this->_is_distinct, @@ -403,7 +403,7 @@ class CRM_Mailing_Selector_Event extends CRM_Core_Selector_Base implements CRM_C return $rows; case 'click': - $rows = CRM_Mailing_Event_BAO_MailingEventClickThrough::getRows( + $rows = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getRows( $this->_mailing_id, $this->_job_id, $this->_is_distinct, $this->_url_id, $offset, $rowCount, $sort diff --git a/CRM/Report/Form/Mailing/Clicks.php b/CRM/Report/Form/Mailing/Clicks.php index c7aebb173f..1be8d2ad3f 100644 --- a/CRM/Report/Form/Mailing/Clicks.php +++ b/CRM/Report/Form/Mailing/Clicks.php @@ -148,7 +148,7 @@ class CRM_Report_Form_Mailing_Clicks extends CRM_Report_Form { ]; $this->_columns['civicrm_mailing_trackable_url'] = [ - 'dao' => 'CRM_Mailing_DAO_TrackableURL', + 'dao' => 'CRM_Mailing_DAO_MailingTrackableURL', 'fields' => [ 'url' => [ 'title' => ts('Click through URL'), @@ -171,7 +171,7 @@ class CRM_Report_Form_Mailing_Clicks extends CRM_Report_Form { ]; $this->_columns['civicrm_mailing_event_trackable_url_open'] = [ - 'dao' => 'CRM_Mailing_Event_DAO_MailingEventClickThrough', + 'dao' => 'CRM_Mailing_Event_DAO_MailingEventTrackableURLOpen', 'fields' => [ 'time_stamp' => [ 'title' => ts('Click Date'), diff --git a/Civi/Api4/MailingEventTrackableURLOpen.php b/Civi/Api4/MailingEventTrackableURLOpen.php new file mode 100644 index 0000000000..126caa7f98 --- /dev/null +++ b/Civi/Api4/MailingEventTrackableURLOpen.php @@ -0,0 +1,23 @@ + CRM_Mailing_Event_BAO_MailingEventClickThrough::getTotalCount($params['mailing_id'], $params['job_id'], (bool) $params['is_distinct'], NULL, $params['date']), + $detail => CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getTotalCount($params['mailing_id'], $params['job_id'], (bool) $params['is_distinct'], NULL, $params['date']), ]; break; diff --git a/api/v3/MailingAB.php b/api/v3/MailingAB.php index f238b3c75a..160e9b4625 100644 --- a/api/v3/MailingAB.php +++ b/api/v3/MailingAB.php @@ -289,7 +289,7 @@ function civicrm_api3_mailing_a_b_graph_stats($params) { break; case 'total unique clicks': - $result = CRM_Mailing_Event_BAO_MailingEventClickThrough::getRows($mailingAB['mailing_id_a'], NULL, TRUE, 0, 1, "civicrm_mailing_event_trackable_url_open.time_stamp ASC"); + $result = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getRows($mailingAB['mailing_id_a'], NULL, TRUE, 0, 1, "civicrm_mailing_event_trackable_url_open.time_stamp ASC"); $startDate = CRM_Utils_Date::processDate($result[0]['date']); $targetDate = CRM_Utils_Date::processDate($params['target_date']); $dateDuration = round(abs(strtotime($targetDate) - strtotime($startDate)) / $params['split_count']); @@ -297,7 +297,7 @@ function civicrm_api3_mailing_a_b_graph_stats($params) { $toDate = date('YmdHis', $toDate); $graphStats[$name] = [ $params['split_count_select'] => [ - 'count' => CRM_Mailing_Event_BAO_MailingEventClickThrough::getTotalCount($params['mailing_id'], NULL, FALSE, NULL, $toDate), + 'count' => CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getTotalCount($params['mailing_id'], NULL, FALSE, NULL, $toDate), 'time' => CRM_Utils_Date::customFormat($toDate), ], ]; @@ -308,8 +308,8 @@ function civicrm_api3_mailing_a_b_graph_stats($params) { throw new CRM_Core_Exception("Provide url to get stats result for total clicks on a particular link"); } // FIXME: doesn't make sense to get url_id mailing_id_(a|b) while getting start date in mailing_id_a - $url_id = CRM_Mailing_BAO_TrackableURL::getTrackerURLId($mailingAB[$column], $params['target_url']); - $result = CRM_Mailing_Event_BAO_MailingEventClickThrough::getRows($mailingAB['mailing_id_a'], NULL, FALSE, $url_id, 0, 1, "civicrm_mailing_event_trackable_url_open.time_stamp ASC"); + $url_id = CRM_Mailing_BAO_MailingTrackableURL::getTrackerURLId($mailingAB[$column], $params['target_url']); + $result = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getRows($mailingAB['mailing_id_a'], NULL, FALSE, $url_id, 0, 1, "civicrm_mailing_event_trackable_url_open.time_stamp ASC"); $startDate = CRM_Utils_Date::processDate($result[0]['date']); $targetDate = CRM_Utils_Date::processDate($params['target_date']); $dateDuration = round(abs(strtotime($targetDate) - strtotime($startDate)) / $params['split_count']); @@ -317,7 +317,7 @@ function civicrm_api3_mailing_a_b_graph_stats($params) { $toDate = CRM_Utils_Date::processDate($toDate); $graphStats[$name] = [ $params['split_count_select'] => [ - 'count' => CRM_Mailing_Event_BAO_MailingEventClickThrough::getTotalCount($params['mailing_id'], NULL, FALSE, $url_id, $toDate), + 'count' => CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getTotalCount($params['mailing_id'], NULL, FALSE, $url_id, $toDate), 'time' => CRM_Utils_Date::customFormat($toDate), ], ]; diff --git a/ext/flexmailer/src/ClickTracker/HtmlClickTracker.php b/ext/flexmailer/src/ClickTracker/HtmlClickTracker.php index 9dd3759b37..822ccbd19f 100644 --- a/ext/flexmailer/src/ClickTracker/HtmlClickTracker.php +++ b/ext/flexmailer/src/ClickTracker/HtmlClickTracker.php @@ -15,7 +15,7 @@ class HtmlClickTracker implements ClickTrackerInterface { public function filterContent($msg, $mailing_id, $queue_id) { return self::replaceHrefUrls($msg, function ($url) use ($mailing_id, $queue_id) { - $data = \CRM_Mailing_BAO_TrackableURL::getTrackerURL( + $data = \CRM_Mailing_BAO_MailingTrackableURL::getTrackerURL( html_entity_decode($url), $mailing_id, $queue_id); $data = htmlentities($data, ENT_NOQUOTES); return $data; diff --git a/ext/flexmailer/src/ClickTracker/TextClickTracker.php b/ext/flexmailer/src/ClickTracker/TextClickTracker.php index 1fdea53e8b..e3c12f3d59 100644 --- a/ext/flexmailer/src/ClickTracker/TextClickTracker.php +++ b/ext/flexmailer/src/ClickTracker/TextClickTracker.php @@ -15,7 +15,7 @@ class TextClickTracker implements ClickTrackerInterface { public function filterContent($msg, $mailing_id, $queue_id) { return self::replaceTextUrls($msg, function ($url) use ($mailing_id, $queue_id) { - return \CRM_Mailing_BAO_TrackableURL::getTrackerURL($url, $mailing_id, + return \CRM_Mailing_BAO_MailingTrackableURL::getTrackerURL($url, $mailing_id, $queue_id); } ); diff --git a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTrackerTest.php b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTrackerTest.php index 5ba9c960e8..4bf926f3bb 100644 --- a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTrackerTest.php +++ b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTrackerTest.php @@ -29,15 +29,15 @@ class ClickTrackerTest extends \PHPUnit\Framework\TestCase implements HeadlessIn // Mock the getTrackerURL call; we don't need to test creating a row in a table. // If you want this to work without runkit, then either (a) make the dummy rows or (b) switch this to a hook/event that is runtime-configurable. require_once 'CRM/Mailing/BAO/TrackableURL.php'; - \runkit7_method_rename('\CRM_Mailing_BAO_TrackableURL', 'getBasicTrackerURL', 'orig_getBasicTrackerURL'); - \runkit7_method_add('\CRM_Mailing_BAO_TrackableURL', 'getBasicTrackerURL', '$a, $b, $c', 'return \'http://example.com/extern?u=1&qid=1\';', RUNKIT7_ACC_STATIC | RUNKIT7_ACC_PRIVATE); + \runkit7_method_rename('\CRM_Mailing_BAO_MailingTrackableURL', 'getBasicTrackerURL', 'orig_getBasicTrackerURL'); + \runkit7_method_add('\CRM_Mailing_BAO_MailingTrackableURL', 'getBasicTrackerURL', '$a, $b, $c', 'return \'http://example.com/extern?u=1&qid=1\';', RUNKIT7_ACC_STATIC | RUNKIT7_ACC_PRIVATE); parent::setUp(); } public function tearDown(): void { // Reset the class. - \runkit7_method_remove('\CRM_Mailing_BAO_TrackableURL', 'getBasicTrackerURL'); - \runkit7_method_rename('\CRM_Mailing_BAO_TrackableURL', 'orig_getBasicTrackerURL', 'getBasicTrackerURL'); + \runkit7_method_remove('\CRM_Mailing_BAO_MailingTrackableURL', 'getBasicTrackerURL'); + \runkit7_method_rename('\CRM_Mailing_BAO_MailingTrackableURL', 'orig_getBasicTrackerURL', 'getBasicTrackerURL'); parent::tearDown(); } diff --git a/extern/url.php b/extern/url.php index e9955097cb..27e1c299b7 100644 --- a/extern/url.php +++ b/extern/url.php @@ -18,7 +18,7 @@ if (!$url_id) { } require_once 'CRM/Mailing/Event/BAO/TrackableURLOpen.php'; -$url = CRM_Mailing_Event_BAO_MailingEventClickThrough::track($queue_id, $url_id); +$url = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::track($queue_id, $url_id); // CRM-7103 // Looking for additional query variables and append them when redirecting. diff --git a/tests/phpunit/CRM/Mailing/BAO/QueryTest.php b/tests/phpunit/CRM/Mailing/BAO/QueryTest.php index 4cca21fea7..125f4de936 100644 --- a/tests/phpunit/CRM/Mailing/BAO/QueryTest.php +++ b/tests/phpunit/CRM/Mailing/BAO/QueryTest.php @@ -85,9 +85,9 @@ class CRM_Mailing_BAO_QueryTest extends CiviUnitTestCase { // ensure that total unique clicked mail count is same while // fetching rows and row count for mailing_id = 14 and // trackable_url_id 12 - $totalDistinctTrackableUrlCount = CRM_Mailing_Event_BAO_MailingEventClickThrough::getTotalCount(14, NULL, TRUE, 13); - $totalTrackableUrlCount = CRM_Mailing_Event_BAO_MailingEventClickThrough::getTotalCount(14, NULL, FALSE, 13); - $totalTrackableUrlMail = CRM_Mailing_Event_BAO_MailingEventClickThrough::getRows(14, NULL, TRUE, 13); + $totalDistinctTrackableUrlCount = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getTotalCount(14, NULL, TRUE, 13); + $totalTrackableUrlCount = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getTotalCount(14, NULL, FALSE, 13); + $totalTrackableUrlMail = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::getRows(14, NULL, TRUE, 13); $this->assertEquals(3, $totalDistinctTrackableUrlCount, "Accurately display distinct count of unique trackable URLs"); $this->assertEquals(4, $totalTrackableUrlCount, "Accurately display count of unique trackable URLs"); diff --git a/tests/phpunit/api/v3/MailingTest.php b/tests/phpunit/api/v3/MailingTest.php index b39fd42746..effacdf1c6 100644 --- a/tests/phpunit/api/v3/MailingTest.php +++ b/tests/phpunit/api/v3/MailingTest.php @@ -1020,13 +1020,13 @@ SELECT event_queue_id, time_stamp FROM {$temporaryTableName}"; $dao = CRM_Core_DAO::executeQuery($sql); $this->assertTrue($dao->fetch()); - $url = CRM_Mailing_Event_BAO_MailingEventClickThrough::track($dao->queue_id, $dao->url_id); + $url = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::track($dao->queue_id, $dao->url_id); $this->assertStringContainsString('https://civicrm.org', $url); // Now delete the event queue hashes and see if the tracking still works. CRM_Core_DAO::executeQuery('DELETE FROM civicrm_mailing_event_queue'); - $url = CRM_Mailing_Event_BAO_MailingEventClickThrough::track($dao->queue_id, $dao->url_id); + $url = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::track($dao->queue_id, $dao->url_id); $this->assertStringContainsString('https://civicrm.org', $url); // Ensure that Google CSS link is not tracked. @@ -1056,13 +1056,13 @@ SELECT event_queue_id, time_stamp FROM {$temporaryTableName}"; $dao = CRM_Core_DAO::executeQuery($sql); $this->assertTrue($dao->fetch()); - $url = CRM_Mailing_Event_BAO_MailingEventClickThrough::track($dao->queue_id, $dao->url_id); + $url = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::track($dao->queue_id, $dao->url_id); $this->assertStringContainsString($unicodeURL, $url); // Now delete the event queue hashes and see if the tracking still works. CRM_Core_DAO::executeQuery('DELETE FROM civicrm_mailing_event_queue'); - $url = CRM_Mailing_Event_BAO_MailingEventClickThrough::track($dao->queue_id, $dao->url_id); + $url = CRM_Mailing_Event_BAO_MailingEventTrackableURLOpen::track($dao->queue_id, $dao->url_id); $this->assertStringContainsString($unicodeURL, $url); } diff --git a/xml/schema/Mailing/Event/MailingEventClickThrough.xml b/xml/schema/Mailing/Event/MailingEventTrackableURLOpen.xml similarity index 83% rename from xml/schema/Mailing/Event/MailingEventClickThrough.xml rename to xml/schema/Mailing/Event/MailingEventTrackableURLOpen.xml index 448c4da1b0..bc97ee81d5 100644 --- a/xml/schema/Mailing/Event/MailingEventClickThrough.xml +++ b/xml/schema/Mailing/Event/MailingEventTrackableURLOpen.xml @@ -2,8 +2,10 @@ CRM/Mailing/Event - MailingEventClickThrough + MailingEventTrackableURLOpencivicrm_mailing_event_trackable_url_open + Mailing Link Clickthrough + Mailing Link ClickthroughsTracks when a TrackableURL is clicked by a recipient.trueCiviMail @@ -29,6 +31,7 @@ FK to EventQueue + EntityRef @@ -44,7 +47,8 @@ true FK to TrackableURL - + + EntityRef @@ -59,6 +63,10 @@ timestamp CURRENT_TIMESTAMP true + + + Date + When this trackable URL open occurred.
diff --git a/xml/schema/Mailing/Event/files.xml b/xml/schema/Mailing/Event/files.xml index eac25940e0..0a359a9080 100644 --- a/xml/schema/Mailing/Event/files.xml +++ b/xml/schema/Mailing/Event/files.xml @@ -10,7 +10,7 @@ - + diff --git a/xml/schema/Mailing/TrackableURL.xml b/xml/schema/Mailing/MailingTrackableURL.xml similarity index 88% rename from xml/schema/Mailing/TrackableURL.xml rename to xml/schema/Mailing/MailingTrackableURL.xml index a22a6bc1c1..337e8adbbf 100644 --- a/xml/schema/Mailing/TrackableURL.xml +++ b/xml/schema/Mailing/MailingTrackableURL.xml @@ -2,8 +2,10 @@ CRM/Mailing - TrackableURL + MailingTrackableURLcivicrm_mailing_trackable_url + Mailing Link + Mailing LinksStores URLs for which we should track click-throughs from mailingstrueCiviMail @@ -34,6 +36,7 @@ true + EntityRefFK to the mailing diff --git a/xml/schema/Mailing/files.xml b/xml/schema/Mailing/files.xml index 00c885a810..73217f3a75 100644 --- a/xml/schema/Mailing/files.xml +++ b/xml/schema/Mailing/files.xml @@ -6,7 +6,7 @@ - + -- 2.25.1