From 39a2d376dabd64557476090a1e0677f93c0aa67e Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Tue, 12 Sep 2023 14:52:31 +1200 Subject: [PATCH] Further updates to 5.66rc This includes updates I've worked on to allow us to store Bounced emails as actitivies (we will also need to add is_create_activities to our fetch_bounces job & create an activity type of Bounce - we can do the former manually while testing & update our job when all good) https://github.com/civicrm/civicrm-core/pull/27356 In addition I reverted the 5.66 change to zeta components in 5.66 since it caused the problem Elliott plugged - this isn't the final word but it means we will be running stock https://github.com/civicrm/civicrm-core/pull/27394 Note the commented out upgrade bits can go now we've done the upgrade and there are some other minor patches Bug: T346088 Bug: T345929 Change-Id: I6a27223850b361eacdd76a457963db47b0e9f1f5 --- .../all/modules/civicrm/CRM/ACL/BAO/ACL.php | 117 +++++++++--------- .../civicrm/CRM/Admin/Page/Options.php | 7 +- .../civicrm/CRM/Event/Form/Participant.php | 20 ++- .../all/modules/civicrm/CRM/Event/Tokens.php | 2 +- .../Upgrade/Incremental/php/FiveSixtyFour.php | 2 +- .../Upgrade/Incremental/php/FiveSixtySix.php | 4 +- .../Incremental/sql/5.63.alpha1.mysql.tpl | 8 ++ .../Incremental/sql/5.66.alpha1.mysql.tpl | 3 + .../civicrm/CRM/Utils/Mail/EmailProcessor.php | 61 +++++++-- .../civicrm/CRM/Utils/Mail/Incoming.php | 8 +- .../civicrm/CRM/Utils/Mail/IncomingMail.php | 11 ++ .../civicrm/CRM/Utils/System/WordPress.php | 101 ++++++--------- .../Civi/Api4/Generic/AbstractGetAction.php | 2 +- .../Civi/Api4/Service/Schema/Joiner.php | 1 + .../modules/civicrm/Civi/Test/FormWrapper.php | 62 +++++++++- .../sites/all/modules/civicrm/composer.json | 2 +- .../sites/all/modules/civicrm/composer.lock | 14 +-- .../modules/civicrm/drupal/phpunit.xml.dist | 6 - .../Civi/Api4/Action/SearchDisplay/Run.php | 1 + .../api/v4/SearchDisplay/SearchRunTest.php | 42 +++++++ .../all/modules/civicrm/vendor/autoload.php | 2 +- .../civicrm/vendor/composer/autoload_real.php | 14 +-- .../vendor/composer/autoload_static.php | 12 +- .../civicrm/vendor/composer/installed.json | 14 +-- .../civicrm/vendor/composer/installed.php | 18 +-- .../vendor/zetacomponents/mail/ChangeLog | 7 -- .../vendor/zetacomponents/mail/src/mail.php | 20 ++- .../mail/src/transports/mta/mta_transport.php | 7 +- 28 files changed, 352 insertions(+), 216 deletions(-) diff --git a/drupal/sites/all/modules/civicrm/CRM/ACL/BAO/ACL.php b/drupal/sites/all/modules/civicrm/CRM/ACL/BAO/ACL.php index ab6495a157..be0673a50a 100644 --- a/drupal/sites/all/modules/civicrm/CRM/ACL/BAO/ACL.php +++ b/drupal/sites/all/modules/civicrm/CRM/ACL/BAO/ACL.php @@ -222,31 +222,13 @@ public static function check($str, $contactID) { * @return null|string */ public static function whereClause($type, &$tables, &$whereTables, $contactID = NULL) { - $acls = CRM_ACL_BAO_Cache::build($contactID); $whereClause = NULL; $allInclude = $allExclude = FALSE; $clauses = []; - if (!empty($acls)) { - $aclKeys = array_keys($acls); - $aclKeys = implode(',', $aclKeys); - $orderBy = 'a.object_id'; - if (array_key_exists('priority', CRM_ACL_BAO_ACL::getSupportedFields())) { - $orderBy .= ',a.priority'; - } - $query = " -SELECT a.operation, a.object_id,a.deny - FROM civicrm_acl_cache c, civicrm_acl a - WHERE c.acl_id = a.id - AND a.is_active = 1 - AND a.object_table = 'civicrm_group' - AND a.id IN ( $aclKeys ) -ORDER BY {$orderBy} -"; - - $dao = CRM_Core_DAO::executeQuery($query); - + $dao = self::getOrderedActiveACLs($contactID, 'civicrm_group'); + if ($dao !== NULL) { // do an or of all the where clauses u see $ids = $excludeIds = []; while ($dao->fetch()) { @@ -451,54 +433,73 @@ public static function self_hook_civicrm_pre(\Civi\Core\Event\PreEvent $event) { */ protected static function loadPermittedIDs(int $contactID, string $tableName, int $type, $allGroups): array { $ids = []; - $acls = CRM_ACL_BAO_Cache::build($contactID); - $aclKeys = array_keys($acls); - $aclKeys = implode(',', $aclKeys); - $orderBy = 'a.object_id'; - if (array_key_exists('priority', CRM_ACL_BAO_ACL::getSupportedFields())) { - $orderBy .= ',a.priority'; - } - $query = " -SELECT a.operation,a.object_id,a.deny - FROM civicrm_acl_cache c, civicrm_acl a - WHERE c.acl_id = a.id - AND a.is_active = 1 - AND a.object_table = %1 - AND a.id IN ( $aclKeys ) -ORDER BY {$orderBy} -"; - $params = [1 => [$tableName, 'String']]; - $dao = CRM_Core_DAO::executeQuery($query, $params); - while ($dao->fetch()) { - if ($dao->object_id) { - if (self::matchType($type, $dao->operation)) { - if (!$dao->deny) { - $ids[] = $dao->object_id; - } - else { - $ids = array_diff($ids, [$dao->object_id]); + $dao = self::getOrderedActiveACLs($contactID, $tableName); + if ($dao !== NULL) { + while ($dao->fetch()) { + if ($dao->object_id) { + if (self::matchType($type, $dao->operation)) { + if (!$dao->deny) { + $ids[] = $dao->object_id; + } + else { + $ids = array_diff($ids, [$dao->object_id]); + } } } - } - else { - // this user has got the permission for all objects of this type - // check if the type matches - if (self::matchType($type, $dao->operation)) { - if (!$dao->deny) { - foreach ($allGroups as $id => $dontCare) { - $ids[] = $id; + else { + // this user has got the permission for all objects of this type + // check if the type matches + if (self::matchType($type, $dao->operation)) { + if (!$dao->deny) { + foreach ($allGroups as $id => $dontCare) { + $ids[] = $id; + } + } + else { + $ids = array_diff($ids, array_keys($allGroups)); } - } - else { - $ids = array_diff($ids, array_keys($allGroups)); } } - break; } } return $ids; } + /** + * Execute a query to find active ACLs for a contact, ordered by priority (if supported) and object ID. + * The query returns the 'operation', 'object_id' and 'deny' properties. + * Returns NULL if CRM_ACL_BAO_Cache::build (effectively, CRM_ACL_BAO_ACL::getAllByContact) + * returns no ACLs (active or not) for the contact. + * + * @param string $contactID + * @param string $tableName + * @return NULL|CRM_Core_DAO|object + */ + private static function getOrderedActiveACLs(string $contactID, string $tableName) { + $dao = NULL; + $acls = CRM_ACL_BAO_Cache::build($contactID); + if (!empty($acls)) { + $aclKeys = array_keys($acls); + $aclKeys = implode(',', $aclKeys); + $orderBy = 'a.object_id'; + if (array_key_exists('priority', CRM_ACL_BAO_ACL::getSupportedFields())) { + $orderBy = "a.priority, $orderBy"; + } + $query = " +SELECT a.operation, a.object_id, a.deny + FROM civicrm_acl_cache c, civicrm_acl a + WHERE c.acl_id = a.id + AND a.is_active = 1 + AND a.object_table = %1 + AND a.id IN ({$aclKeys}) +ORDER BY {$orderBy} +"; + $params = [1 => [$tableName, 'String']]; + $dao = CRM_Core_DAO::executeQuery($query, $params); + } + return $dao; + } + private static function getGroupClause(array $groupIDs, string $operation): string { $ids = implode(',', $groupIDs); $query = " diff --git a/drupal/sites/all/modules/civicrm/CRM/Admin/Page/Options.php b/drupal/sites/all/modules/civicrm/CRM/Admin/Page/Options.php index 93f30fc18f..19954130e2 100644 --- a/drupal/sites/all/modules/civicrm/CRM/Admin/Page/Options.php +++ b/drupal/sites/all/modules/civicrm/CRM/Admin/Page/Options.php @@ -157,26 +157,30 @@ public function &links() { 'url' => 'civicrm/admin/options/' . self::$_gName, 'qs' => 'action=update&id=%%id%%&reset=1', 'title' => ts('Edit %1', [1 => self::$_gName]), + 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::UPDATE), ], CRM_Core_Action::DISABLE => [ 'name' => ts('Disable'), 'ref' => 'crm-enable-disable', 'title' => ts('Disable %1', [1 => self::$_gName]), + 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DISABLE), ], CRM_Core_Action::ENABLE => [ 'name' => ts('Enable'), 'ref' => 'crm-enable-disable', 'title' => ts('Enable %1', [1 => self::$_gName]), + 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::ENABLE), ], CRM_Core_Action::DELETE => [ 'name' => ts('Delete'), 'url' => 'civicrm/admin/options/' . self::$_gName, 'qs' => 'action=delete&id=%%id%%', 'title' => ts('Delete %1 Type', [1 => self::$_gName]), + 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DELETE), ], ]; - if (self::$_gName == 'custom_search') { + if (self::$_gName === 'custom_search') { $runLink = [ CRM_Core_Action::FOLLOWUP => [ 'name' => ts('Run'), @@ -184,6 +188,7 @@ public function &links() { 'qs' => 'reset=1&csid=%%value%%', 'title' => ts('Run %1', [1 => self::$_gName]), 'class' => 'no-popup', + 'weight' => 10, ], ]; self::$_links = $runLink + self::$_links; diff --git a/drupal/sites/all/modules/civicrm/CRM/Event/Form/Participant.php b/drupal/sites/all/modules/civicrm/CRM/Event/Form/Participant.php index 9c58ba4d1c..fc8c303ce9 100644 --- a/drupal/sites/all/modules/civicrm/CRM/Event/Form/Participant.php +++ b/drupal/sites/all/modules/civicrm/CRM/Event/Form/Participant.php @@ -1364,7 +1364,7 @@ public function submit($params) { } if (!empty($params['send_receipt'])) { - $result = $this->sendReceipts($params, $contributionParams['total_amount'], $customFields, $participants, $lineItem[0] ?? [], $additionalParticipantDetails); + $result = $this->sendReceipts($params, $customFields, $participants, $lineItem[0] ?? [], $additionalParticipantDetails ?? []); } // set the participant id if it is not set @@ -2129,7 +2129,6 @@ protected function assignUrlPath() { /** * @param $params - * @param $total_amount * @param array $customFields * @param array $participants * @param $lineItem @@ -2138,7 +2137,7 @@ protected function assignUrlPath() { * @return array * @throws \CRM_Core_Exception */ - protected function sendReceipts($params, $total_amount, array $customFields, array $participants, $lineItem, $additionalParticipantDetails): array { + protected function sendReceipts($params, array $customFields, array $participants, $lineItem, $additionalParticipantDetails): array { $sent = []; $notSent = []; $this->assign('module', 'Event Registration'); @@ -2159,10 +2158,9 @@ protected function sendReceipts($params, $total_amount, array $customFields, arr ); } } - - $this->assign('totalAmount', $params['total_amount'] ?? $total_amount); - $this->assign('checkNumber', CRM_Utils_Array::value('check_number', $params)); } + + $this->assign('checkNumber', $params['check_number'] ?? NULL); if ($this->_mode) { $this->assignBillingName($params); $this->assign('address', CRM_Utils_Address::getFormattedBillingAddressFieldsFromParameters( @@ -2210,6 +2208,16 @@ protected function sendReceipts($params, $total_amount, array $customFields, arr $contributionID = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment', $participants[$num]->id, 'contribution_id', 'participant_id' ); + $totalAmount = 0; + if ($contributionID) { + // @todo - this should be temporary - we are looking to remove this variable from the template + // in favour of the {contribution.total_amount} token. + // In case this needs back-porting I have kept it as simple as possible. + $totalAmount = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', + $contributionID, 'id', 'total_amount' + ); + } + $this->assign('totalAmount', $params['total_amount'] ?? $totalAmount); $this->_id = $participants[$num]->id; if ($this->_isPaidEvent) { diff --git a/drupal/sites/all/modules/civicrm/CRM/Event/Tokens.php b/drupal/sites/all/modules/civicrm/CRM/Event/Tokens.php index 7700beac45..286d56cbbf 100644 --- a/drupal/sites/all/modules/civicrm/CRM/Event/Tokens.php +++ b/drupal/sites/all/modules/civicrm/CRM/Event/Tokens.php @@ -205,7 +205,6 @@ protected function getEventTokenValues(int $eventID = NULL): array { 'event_type_id:name', 'pay_later_text', 'pay_later_receipt', - 'fee_label', 'custom.*', ], $this->getExposedFields())) ->execute()->first(); @@ -273,6 +272,7 @@ protected function getExposedFields(): array { 'is_public', 'confirm_email_text', 'is_monetary', + 'fee_label', ]; } diff --git a/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/php/FiveSixtyFour.php b/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/php/FiveSixtyFour.php index 6c7492f65f..949d43886a 100644 --- a/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/php/FiveSixtyFour.php +++ b/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/php/FiveSixtyFour.php @@ -69,7 +69,7 @@ public static function updateLogging($ctx): bool { $dsn = DB::parseDSN($dsn); $table = '`' . $dsn['database'] . '`.`log_civicrm_uf_group`'; CRM_Core_DAO::executeQuery("ALTER TABLE $table CHANGE `post_URL` `post_url` varchar(255) DEFAULT NULL COMMENT 'Redirect to URL on submit.', -CHANGE `cancel_URL` `cancel_url` varchar(255) DEFAULT NULL COMMENT 'Redirect to URL when Cancel button clicked.'"); +CHANGE `cancel_URL` `cancel_url` varchar(255) DEFAULT NULL COMMENT 'Redirect to URL when Cancel button clicked.'", [], TRUE, NULL, FALSE, FALSE); } return TRUE; } diff --git a/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/php/FiveSixtySix.php b/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/php/FiveSixtySix.php index b91a0b90a1..8ee34dd5e2 100644 --- a/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/php/FiveSixtySix.php +++ b/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/php/FiveSixtySix.php @@ -36,8 +36,8 @@ public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NU */ public function upgrade_5_66_alpha1($rev): void { $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev); - // $this->addTask('Make Contribution.tax_amount required', 'alterColumn', 'civicrm_contribution', 'tax_amount', "decimal(20,2) DEFAULT 0 COMMENT 'Total tax amount of this contribution.'"); - // $this->addTask('Make Contribution.tax_amount required', 'alterColumn', 'civicrm_line_item', 'tax_amount', "decimal(20,2) DEFAULT 0 COMMENT 'tax of each item'"); + $this->addTask('Make Contribution.tax_amount required', 'alterColumn', 'civicrm_contribution', 'tax_amount', "decimal(20,2) DEFAULT 0 NOT NULL COMMENT 'Total tax amount of this contribution.'"); + $this->addTask('Make Contribution.tax_amount required', 'alterColumn', 'civicrm_line_item', 'tax_amount', "decimal(20,2) DEFAULT 0 NOT NULL COMMENT 'tax of each item'"); // These run after the sql file $this->addTask('Make Discount.entity_table required', 'alterColumn', 'civicrm_discount', 'entity_table', "varchar(64) NOT NULL COMMENT 'Name of the action(reminder)'"); $this->addTask('Make ActionSchedule.name required', 'alterColumn', 'civicrm_action_schedule', 'name', "varchar(64) NOT NULL COMMENT 'physical tablename for entity being joined to discount, e.g. civicrm_event'"); diff --git a/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/sql/5.63.alpha1.mysql.tpl b/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/sql/5.63.alpha1.mysql.tpl index d96fd227a1..62361f6bb0 100644 --- a/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/sql/5.63.alpha1.mysql.tpl +++ b/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/sql/5.63.alpha1.mysql.tpl @@ -21,11 +21,19 @@ UPDATE civicrm_contribution_page SET `name` = `id`; -- Add name field, make frontend_title required (in conjunction with php function) {if $multilingual} {foreach from=$locales item=locale} + UPDATE `civicrm_contribution_page` + SET `title_{$locale}` = '' + WHERE `title_{$locale}` IS NULL; + UPDATE `civicrm_contribution_page` SET `frontend_title_{$locale}` = `title_{$locale}` WHERE `frontend_title_{$locale}` IS NULL OR `frontend_title_{$locale}` = ''; {/foreach} {else} + UPDATE `civicrm_contribution_page` + SET `title` = '' + WHERE `title` IS NULL; + UPDATE `civicrm_contribution_page` SET `frontend_title` = `title` WHERE `frontend_title` IS NULL OR `frontend_title` = ''; diff --git a/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/sql/5.66.alpha1.mysql.tpl b/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/sql/5.66.alpha1.mysql.tpl index 67e3d868ec..325ab4c919 100644 --- a/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/sql/5.66.alpha1.mysql.tpl +++ b/drupal/sites/all/modules/civicrm/CRM/Upgrade/Incremental/sql/5.66.alpha1.mysql.tpl @@ -8,3 +8,6 @@ WHERE a2.name = a1.name AND a2.id > a1.id; {* Set default value for Discount.entity_table *} UPDATE `civicrm_discount` SET `entity_table` = 'civicrm_event' WHERE `entity_table` IS NULL; + +UPDATE civicrm_contribution SET tax_amount = 0 WHERE tax_amount IS NULL; +UPDATE civicrm_line_item SET tax_amount = 0 WHERE tax_amount IS NULL; diff --git a/drupal/sites/all/modules/civicrm/CRM/Utils/Mail/EmailProcessor.php b/drupal/sites/all/modules/civicrm/CRM/Utils/Mail/EmailProcessor.php index 8904a440b0..0f891fcaf1 100644 --- a/drupal/sites/all/modules/civicrm/CRM/Utils/Mail/EmailProcessor.php +++ b/drupal/sites/all/modules/civicrm/CRM/Utils/Mail/EmailProcessor.php @@ -16,6 +16,8 @@ */ // we should consider moving this to the settings table +use Civi\Api4\Activity; + define('MAIL_BATCH_SIZE', 50); /** @@ -84,6 +86,23 @@ private static function _process($civiMail, $dao, $is_create_activities) { // create an array of all of to, from, cc, bcc that are in use for this Mail Account, so we don't create contacts for emails we aren't adding to the activity. $emailFields = array_merge($targetFields, $assigneeFields, $sourceFields); $createContact = !($dao->is_contact_creation_disabled_if_no_match); + $bounceActivityTypeID = $activityTypeID = (int) $dao->activity_type_id; + $activityTypes = Activity::getFields(TRUE) + ->setLoadOptions(['id', 'name']) + ->addWhere('name', '=', 'activity_type_id') + ->execute()->first()['options']; + foreach ($activityTypes as $activityType) { + if ($activityType['name'] === 'Bounce') { + $bounceActivityTypeID = (int) $activityType['id']; + } + } + $bounceTypes = []; + if ($isBounceProcessing) { + $result = CRM_Core_DAO::executeQuery('SELECT * FROM civicrm_mailing_bounce_type'); + while ($result->fetch()) { + $bounceTypes[$result->id] = ['id' => $result->id, 'name' => $result->name, 'description' => $result->description, 'hold_threshold' => $result->hold_threshold]; + } + } // retrieve the emails try { @@ -116,11 +135,27 @@ private static function _process($civiMail, $dao, $is_create_activities) { continue; } + $bounceString = ''; // if its the activities that needs to be processed .. try { + if ($incomingMail->isBounce()) { + $activityTypeID = $bounceActivityTypeID; + $bounce = CRM_Mailing_BAO_BouncePattern::match($incomingMail->getBody()); + if (!empty($bounce['bounce_type_id'])) { + $bounceType = $bounceTypes[$bounce['bounce_type_id']]; + $bounceString = ts('Bounce type: %1. %2', [1 => $bounceType['name'], 2 => $bounceType['description']]) + . '
' + . ts('Email will be put on hold after %1 of this type of bounce', [1 => $bounceType['hold_threshold']]) + . "\n"; + } + else { + $bounceString = ts('Bounce type not identified, email will not be put on hold') + . "\n"; + } + } $mailParams = CRM_Utils_Mail_Incoming::parseMailingObject($mail, $incomingMail->getAttachments(), $createContact, $emailFields, [$incomingMail->getFrom()]); $activityParams = [ - 'activity_type_id' => (int) $dao->activity_type_id, + 'activity_type_id' => $activityTypeID, 'campaign_id' => $dao->campaign_id ? (int) $dao->campaign_id : NULL, 'status_id' => $dao->activity_status, 'subject' => $incomingMail->getSubject(), @@ -162,18 +197,28 @@ private static function _process($civiMail, $dao, $is_create_activities) { } $result = civicrm_api3('Activity', 'create', $activityParams); + $matches = TRUE; + CRM_Utils_Hook::emailProcessor('activity', $activityParams, $mail, $result); + echo "Processed as Activity: {$mail->subject}\n"; } catch (Exception $e) { - echo "Failed Processing: {$mail->subject}. Reason: " . $e->getMessage() . "\n"; - $store->markIgnored($key); - continue; + // Try again with just the bounceString as the details. + // This allows us to still process even if we hit https://lab.civicrm.org/dev/mail/issues/36 + // as tested in testBounceProcessingInvalidCharacter. + $activityParams['details'] = trim($bounceString); + try { + civicrm_api3('Activity', 'create', $activityParams); + $matches = TRUE; + } + catch (CRM_Core_Exception $e) { + echo "Failed Processing: {$mail->subject}. Reason: " . $e->getMessage() . "\n"; + $store->markIgnored($key); + continue; + } } - $matches = TRUE; - CRM_Utils_Hook::emailProcessor('activity', $activityParams, $mail, $result); - echo "Processed as Activity: {$mail->subject}\n"; } - // if $matches is empty, this email is not CiviMail-bound + // This is an awkward exit when processing is done. It probably needs revisiting if (!$incomingMail->isVerp() && empty($matches)) { $store->markIgnored($key); continue; diff --git a/drupal/sites/all/modules/civicrm/CRM/Utils/Mail/Incoming.php b/drupal/sites/all/modules/civicrm/CRM/Utils/Mail/Incoming.php index 220dc48efe..81bec1dccb 100644 --- a/drupal/sites/all/modules/civicrm/CRM/Utils/Mail/Incoming.php +++ b/drupal/sites/all/modules/civicrm/CRM/Utils/Mail/Incoming.php @@ -356,8 +356,7 @@ private static function parseAddress($address, &$subParam, &$mail, $createContac $contactID = self::getContactID($subParam['email'], $subParam['name'], - $createContact, - $mail + $createContact ); $subParam['id'] = $contactID ?: NULL; } @@ -370,11 +369,12 @@ private static function parseAddress($address, &$subParam, &$mail, $createContac * @param string $email * @param string $name * @param bool $create - * @param string $mail + * + * @internal core use only (only use outside this class is in core unit tests). * * @return int|null */ - public static function getContactID($email, $name, $create, &$mail) { + public static function getContactID($email, $name, $create) { $dao = CRM_Contact_BAO_Contact::matchContactOnEmail($email, 'Individual'); $contactID = NULL; diff --git a/drupal/sites/all/modules/civicrm/CRM/Utils/Mail/IncomingMail.php b/drupal/sites/all/modules/civicrm/CRM/Utils/Mail/IncomingMail.php index c11273a5fa..04eeb841b9 100644 --- a/drupal/sites/all/modules/civicrm/CRM/Utils/Mail/IncomingMail.php +++ b/drupal/sites/all/modules/civicrm/CRM/Utils/Mail/IncomingMail.php @@ -124,6 +124,17 @@ public function isVerp(): bool { return (bool) $this->action; } + /** + * Is this a bounce email. + * + * At the moment we are only able to detect verp bounces but maybe in the future... + * + * @return bool + */ + public function isBounce() : bool { + return $this->getAction() === 'b'; + } + /** * @param \ezcMail $mail * @param string $emailDomain diff --git a/drupal/sites/all/modules/civicrm/CRM/Utils/System/WordPress.php b/drupal/sites/all/modules/civicrm/CRM/Utils/System/WordPress.php index a8ec227893..d4da15e4ad 100644 --- a/drupal/sites/all/modules/civicrm/CRM/Utils/System/WordPress.php +++ b/drupal/sites/all/modules/civicrm/CRM/Utils/System/WordPress.php @@ -300,7 +300,7 @@ public function url( $forceBackend = FALSE ) { $config = CRM_Core_Config::singleton(); - $script = ''; + $frontend_url = ''; $separator = '&'; $fragment = isset($fragment) ? ('#' . $fragment) : ''; $path = CRM_Utils_String::stripPathChars($path); @@ -318,8 +318,8 @@ public function url( // Try and find the "calling" page/post. global $post; if ($post) { - $script = get_permalink($post->ID); - if ($config->wpBasePage == $post->post_name) { + $frontend_url = get_permalink($post->ID); + if (civi_wp()->basepage->is_match($post->ID)) { $basepage = TRUE; } } @@ -329,7 +329,7 @@ public function url( // Get the Base Page URL for building front-end URLs. if ($frontend && !$forceBackend) { - $script = $this->getBasePageUrl(); + $frontend_url = $this->getBasePageUrl(); $basepage = TRUE; } @@ -339,20 +339,30 @@ public function url( $base = $this->getBaseUrl($absolute, $frontend, $forceBackend); // Overwrite base URL if we already have a front-end URL. - if (!$forceBackend && $script != '') { - $base = $script; + if (!$forceBackend && $frontend_url != '') { + $base = $frontend_url; } $queryParts = []; $admin_request = ((is_admin() && !$frontend) || $forceBackend); + /** + * Filter the Base URL. + * + * @since 5.66 + * + * @param str $base The Base URL. + * @param bool $admin_request True if building an admin URL, false otherwise. + */ + $base = apply_filters('civicrm/core/url/base', $base, $admin_request); + if ( // If not using Clean URLs. !$config->cleanURL // Or requesting an admin URL. || $admin_request // Or this is a Shortcode. - || (!$basepage && $script != '') + || (!$basepage && $frontend_url != '') ) { // Build URL according to pre-existing logic. @@ -431,37 +441,7 @@ public function getBaseUrl($absolute, $frontend, $forceBackend) { * The Base Page URL, or false on failure. */ public function getBasePageUrl() { - static $basepage_url = ''; - if ($basepage_url === '') { - - // Get the Base Page config setting. - $config = CRM_Core_Config::singleton(); - $basepage_slug = $config->wpBasePage; - - // Did we get a value? - if (!empty($basepage_slug)) { - - // Query for our Base Page. - $pages = get_posts([ - 'post_type' => 'page', - 'name' => strtolower($basepage_slug), - 'post_status' => 'publish', - 'posts_per_page' => 1, - ]); - - // Find the Base Page object and set the URL. - if (!empty($pages) && is_array($pages)) { - $basepage = array_pop($pages); - if ($basepage instanceof WP_Post) { - $basepage_url = get_permalink($basepage->ID); - } - } - - } - - } - - return $basepage_url; + return civi_wp()->basepage->url_get(); } /** @@ -636,11 +616,14 @@ public function logout() { * @inheritDoc */ public function getUFLocale() { - // Bail early if method is called when WordPress isn't bootstrapped. - // Additionally, the function checked here is located in pluggable.php - // and is required by wp_get_referer() - so this also bails early if it is - // called too early in the request lifecycle. - // @see https://core.trac.wordpress.org/ticket/25294 + /* + * Bail early if method is called when WordPress isn't bootstrapped. + * Additionally, the function checked here is located in pluggable.php + * and is required by wp_get_referer() - so this also bails early if it is + * called too early in the request lifecycle. + * + * @see https://core.trac.wordpress.org/ticket/25294 + */ if (!function_exists('wp_validate_redirect')) { return NULL; } @@ -662,28 +645,16 @@ public function getUFLocale() { // Default to WordPress locale. $locale = get_locale(); - // Maybe override with the locale that Polylang reports. - if (function_exists('pll_current_language')) { - $pll_locale = pll_current_language('locale'); - if (!empty($pll_locale)) { - $locale = $pll_locale; - } - } - - // Maybe override with the locale that WPML reports. - elseif (defined('ICL_LANGUAGE_CODE')) { - $languages = apply_filters('wpml_active_languages', NULL); - foreach ($languages as $language) { - if ($language['active']) { - $locale = $language['default_locale']; - break; - } - } - } - - // TODO: Set locale for other WordPress plugins. - // @see https://wordpress.org/plugins/tags/multilingual/ - // A hook would be nice here. + /** + * Filter the default WordPress locale. + * + * The CiviCRM-WordPress plugin supports Polylang and WPML via this filter. + * + * @since 5.66 + * + * @param str $locale The WordPress locale. + */ + $locale = apply_filters('civicrm/core/locale', $locale); } diff --git a/drupal/sites/all/modules/civicrm/Civi/Api4/Generic/AbstractGetAction.php b/drupal/sites/all/modules/civicrm/Civi/Api4/Generic/AbstractGetAction.php index 41b9c2d818..06af935336 100644 --- a/drupal/sites/all/modules/civicrm/Civi/Api4/Generic/AbstractGetAction.php +++ b/drupal/sites/all/modules/civicrm/Civi/Api4/Generic/AbstractGetAction.php @@ -39,7 +39,7 @@ public function selectRowCount() { * * @throws \CRM_Core_Exception */ - protected function setDefaultWhereClause() { + public function setDefaultWhereClause() { if (!$this->_itemsToGet('id')) { $fields = $this->entityFields(); foreach ($fields as $field) { diff --git a/drupal/sites/all/modules/civicrm/Civi/Api4/Service/Schema/Joiner.php b/drupal/sites/all/modules/civicrm/Civi/Api4/Service/Schema/Joiner.php index 4d96d3461c..d42caa1708 100644 --- a/drupal/sites/all/modules/civicrm/Civi/Api4/Service/Schema/Joiner.php +++ b/drupal/sites/all/modules/civicrm/Civi/Api4/Service/Schema/Joiner.php @@ -78,6 +78,7 @@ public function getPath(string $baseTable, array $joinPath) { */ public static function getExtraJoinSql(array $field, Api4SelectQuery $query): string { $prefix = empty($field['explicit_join']) ? '' : $field['explicit_join'] . '.'; + $prefix .= (empty($field['implicit_join']) ? '' : $field['implicit_join'] . '.'); $idField = $query->getField($prefix . $field['name'] . '.id'); return $idField['sql_name']; } diff --git a/drupal/sites/all/modules/civicrm/Civi/Test/FormWrapper.php b/drupal/sites/all/modules/civicrm/Civi/Test/FormWrapper.php index f9af7110a1..737ebb9389 100644 --- a/drupal/sites/all/modules/civicrm/Civi/Test/FormWrapper.php +++ b/drupal/sites/all/modules/civicrm/Civi/Test/FormWrapper.php @@ -36,10 +36,32 @@ class FormWrapper { private $mail; + /** + * @return null|array + */ + public function getMail(): ?array { + return $this->mail; + } + + /** + * @return array + */ + public function getFirstMail(): array { + return $this->mail ? (array) reset($this->mail) : []; + } + + public function getFirstMailBody() : string { + return $this->getFirstMail()['body'] ?? ''; + } + private $redirects; + private $mailSpoolID; + private $validation; + private $originalMailSetting; + public const CONSTRUCTED = 0; public const PREPROCESSED = 1; public const BUILT = 3; @@ -79,12 +101,7 @@ public function processForm(int $state = self::SUBMITTED): self { $this->validation = $this->form->validate(); } if ($state > self::VALIDATED) { - $this->form->postProcess(); - foreach ($this->subsequentForms as $form) { - $form->preProcess(); - $form->buildForm(); - $form->postProcess(); - } + $this->postProcess(); } return $this; } @@ -138,7 +155,14 @@ public function __call(string $name, array $arguments) { * @return $this */ public function postProcess(): self { + $this->startTrackingMail(); $this->form->postProcess(); + foreach ($this->subsequentForms as $form) { + $form->preProcess(); + $form->buildForm(); + $form->postProcess(); + } + $this->stopTrackingMail(); return $this; } @@ -289,4 +313,30 @@ private function setFormObject(string $class, array $formValues = [], array $url } } + /** + * Start tracking any emails sent by this form. + * + * @noinspection PhpUnhandledExceptionInspection + */ + private function startTrackingMail(): void { + $this->originalMailSetting = \Civi::settings()->get('mailing_backend'); + \Civi::settings() + ->set('mailing_backend', array_merge((array) $this->originalMailSetting, ['outBound_option' => \CRM_Mailing_Config::OUTBOUND_OPTION_REDIRECT_TO_DB])); + $this->mailSpoolID = (int) \CRM_Core_DAO::singleValueQuery('SELECT MAX(id) FROM civicrm_mailing_spool'); + } + + /** + * Store any mails sent & revert to pre-test behaviour. + * + * @noinspection PhpUnhandledExceptionInspection + */ + private function stopTrackingMail(): void { + $dao = \CRM_Core_DAO::executeQuery('SELECT headers, body FROM civicrm_mailing_spool WHERE id > ' . $this->mailSpoolID . ' ORDER BY id'); + \CRM_Core_DAO::executeQuery('DELETE FROM civicrm_mailing_spool WHERE id > ' . $this->mailSpoolID); + while ($dao->fetch()) { + $this->mail[] = ['headers' => $dao->headers, 'body' => $dao->body]; + } + \Civi::settings()->set('mailing_backend', $this->originalMailSetting); + } + } diff --git a/drupal/sites/all/modules/civicrm/composer.json b/drupal/sites/all/modules/civicrm/composer.json index f55578f1c1..dca1defecf 100644 --- a/drupal/sites/all/modules/civicrm/composer.json +++ b/drupal/sites/all/modules/civicrm/composer.json @@ -68,7 +68,7 @@ "tecnickcom/tcpdf" : "6.4.*", "totten/ca-config": "~22.11", "zetacomponents/base": "1.9.*", - "zetacomponents/mail": "~1.9.5", + "zetacomponents/mail": "~1.9.4", "marcj/topsort": "~1.1", "phpoffice/phpword": "^0.18.0", "pear/validate_finance_creditcard": "0.7.0", diff --git a/drupal/sites/all/modules/civicrm/composer.lock b/drupal/sites/all/modules/civicrm/composer.lock index 7b01132eb0..b4a52e6f87 100644 --- a/drupal/sites/all/modules/civicrm/composer.lock +++ b/drupal/sites/all/modules/civicrm/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4a541aad8f31cbb35982d1380c3f1c71", + "content-hash": "d53a256f9748f1facc1312352b5a9acb", "packages": [ { "name": "adrienrn/php-mimetyper", @@ -5491,16 +5491,16 @@ }, { "name": "zetacomponents/mail", - "version": "1.9.5", + "version": "1.9.4", "source": { "type": "git", "url": "https://github.com/zetacomponents/Mail.git", - "reference": "e106e5934a42cd1e37227fa50e79be648d60fa14" + "reference": "83ba646f36f753c0bbc8b2189c88d41ece326ea0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zetacomponents/Mail/zipball/e106e5934a42cd1e37227fa50e79be648d60fa14", - "reference": "e106e5934a42cd1e37227fa50e79be648d60fa14", + "url": "https://api.github.com/repos/zetacomponents/Mail/zipball/83ba646f36f753c0bbc8b2189c88d41ece326ea0", + "reference": "83ba646f36f753c0bbc8b2189c88d41ece326ea0", "shasum": "" }, "require": { @@ -5565,9 +5565,9 @@ "homepage": "https://github.com/zetacomponents", "support": { "issues": "https://github.com/zetacomponents/Mail/issues", - "source": "https://github.com/zetacomponents/Mail/tree/1.9.5" + "source": "https://github.com/zetacomponents/Mail/tree/1.9.4" }, - "time": "2023-09-06T09:15:46+00:00" + "time": "2022-09-14T10:13:21+00:00" } ], "packages-dev": [], diff --git a/drupal/sites/all/modules/civicrm/drupal/phpunit.xml.dist b/drupal/sites/all/modules/civicrm/drupal/phpunit.xml.dist index aa1a901062..a170fbed16 100644 --- a/drupal/sites/all/modules/civicrm/drupal/phpunit.xml.dist +++ b/drupal/sites/all/modules/civicrm/drupal/phpunit.xml.dist @@ -15,10 +15,4 @@ ./tests/phpunit - - - - ./CiviDrupal - - diff --git a/drupal/sites/all/modules/civicrm/ext/search_kit/Civi/Api4/Action/SearchDisplay/Run.php b/drupal/sites/all/modules/civicrm/ext/search_kit/Civi/Api4/Action/SearchDisplay/Run.php index 9eadab8c5e..3a66af498d 100644 --- a/drupal/sites/all/modules/civicrm/ext/search_kit/Civi/Api4/Action/SearchDisplay/Run.php +++ b/drupal/sites/all/modules/civicrm/ext/search_kit/Civi/Api4/Action/SearchDisplay/Run.php @@ -63,6 +63,7 @@ protected function processResult(\Civi\Api4\Result\SearchDisplayRunResult $resul case 'tally': unset($apiParams['orderBy'], $apiParams['limit']); $api = Request::create($entityName, 'get', $apiParams); + $api->setDefaultWhereClause(); $query = new Api4SelectQuery($api); $query->forceSelectId = FALSE; $sql = $query->getSql(); diff --git a/drupal/sites/all/modules/civicrm/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php b/drupal/sites/all/modules/civicrm/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php index ecb890792a..82f33532cc 100644 --- a/drupal/sites/all/modules/civicrm/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php +++ b/drupal/sites/all/modules/civicrm/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php @@ -1697,6 +1697,48 @@ public function testContributionAggregateCurrency():void { $this->assertEquals('$250.00', $result[3]['columns'][0]['val']); } + public function testContributionTotalCountWithTestAndTemplateContributions():void { + // Add a source here for the where below, as if we use id, we get the test and template contributions + $contributions = $this->saveTestRecords('Contribution', [ + 'records' => [ + ['is_test' => TRUE, 'source' => 'TestTemplate'], + ['is_template' => TRUE, 'source' => 'TestTemplate'], + ['source' => 'TestTemplate'], + ], + ]); + + $params = [ + 'checkPermissions' => FALSE, + 'return' => 'page:1', + 'savedSearch' => [ + 'api_entity' => 'Contribution', + 'api_params' => [ + 'version' => 4, + 'select' => ['id'], + 'where' => [['source', '=', 'TestTemplate']], + ], + ], + 'display' => [ + 'settings' => [ + 'columns' => [ + [ + 'type' => 'field', + 'key' => 'id', + 'tally' => [ + 'fn' => 'COUNT', + ], + ], + ], + ], + ], + ]; + + $return = civicrm_api4('SearchDisplay', 'run', $params); + $params['return'] = 'tally'; + $total = civicrm_api4('SearchDisplay', 'run', $params); + $this->assertEquals($return->rowCount, $total[0]['id']); + } + public function testSelectEquations() { $activities = $this->saveTestRecords('Activity', [ 'records' => [ diff --git a/drupal/sites/all/modules/civicrm/vendor/autoload.php b/drupal/sites/all/modules/civicrm/vendor/autoload.php index b34698983c..b405163461 100644 --- a/drupal/sites/all/modules/civicrm/vendor/autoload.php +++ b/drupal/sites/all/modules/civicrm/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit627bea550135a19b0790004d95341b38::getLoader(); +return ComposerAutoloaderInitcd9eff56097bcbfade9a81b1e659e753::getLoader(); diff --git a/drupal/sites/all/modules/civicrm/vendor/composer/autoload_real.php b/drupal/sites/all/modules/civicrm/vendor/composer/autoload_real.php index 969ee4287d..9ba64af673 100644 --- a/drupal/sites/all/modules/civicrm/vendor/composer/autoload_real.php +++ b/drupal/sites/all/modules/civicrm/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit627bea550135a19b0790004d95341b38 +class ComposerAutoloaderInitcd9eff56097bcbfade9a81b1e659e753 { private static $loader; @@ -24,9 +24,9 @@ public static function getLoader() require __DIR__ . '/platform_check.php'; - spl_autoload_register(array('ComposerAutoloaderInit627bea550135a19b0790004d95341b38', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInitcd9eff56097bcbfade9a81b1e659e753', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); - spl_autoload_unregister(array('ComposerAutoloaderInit627bea550135a19b0790004d95341b38', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInitcd9eff56097bcbfade9a81b1e659e753', 'loadClassLoader')); $includePaths = require __DIR__ . '/include_paths.php'; $includePaths[] = get_include_path(); @@ -36,7 +36,7 @@ public static function getLoader() if ($useStaticLoader) { require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit627bea550135a19b0790004d95341b38::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInitcd9eff56097bcbfade9a81b1e659e753::getInitializer($loader)); } else { $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { @@ -57,12 +57,12 @@ public static function getLoader() $loader->register(true); if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit627bea550135a19b0790004d95341b38::$files; + $includeFiles = Composer\Autoload\ComposerStaticInitcd9eff56097bcbfade9a81b1e659e753::$files; } else { $includeFiles = require __DIR__ . '/autoload_files.php'; } foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire627bea550135a19b0790004d95341b38($fileIdentifier, $file); + composerRequirecd9eff56097bcbfade9a81b1e659e753($fileIdentifier, $file); } return $loader; @@ -74,7 +74,7 @@ public static function getLoader() * @param string $file * @return void */ -function composerRequire627bea550135a19b0790004d95341b38($fileIdentifier, $file) +function composerRequirecd9eff56097bcbfade9a81b1e659e753($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; diff --git a/drupal/sites/all/modules/civicrm/vendor/composer/autoload_static.php b/drupal/sites/all/modules/civicrm/vendor/composer/autoload_static.php index 7c3299714e..5fd5f8bc6e 100644 --- a/drupal/sites/all/modules/civicrm/vendor/composer/autoload_static.php +++ b/drupal/sites/all/modules/civicrm/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit627bea550135a19b0790004d95341b38 +class ComposerStaticInitcd9eff56097bcbfade9a81b1e659e753 { public static $files = array ( 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', @@ -729,11 +729,11 @@ class ComposerStaticInit627bea550135a19b0790004d95341b38 public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit627bea550135a19b0790004d95341b38::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit627bea550135a19b0790004d95341b38::$prefixDirsPsr4; - $loader->prefixesPsr0 = ComposerStaticInit627bea550135a19b0790004d95341b38::$prefixesPsr0; - $loader->fallbackDirsPsr0 = ComposerStaticInit627bea550135a19b0790004d95341b38::$fallbackDirsPsr0; - $loader->classMap = ComposerStaticInit627bea550135a19b0790004d95341b38::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInitcd9eff56097bcbfade9a81b1e659e753::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitcd9eff56097bcbfade9a81b1e659e753::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInitcd9eff56097bcbfade9a81b1e659e753::$prefixesPsr0; + $loader->fallbackDirsPsr0 = ComposerStaticInitcd9eff56097bcbfade9a81b1e659e753::$fallbackDirsPsr0; + $loader->classMap = ComposerStaticInitcd9eff56097bcbfade9a81b1e659e753::$classMap; }, null, ClassLoader::class); } diff --git a/drupal/sites/all/modules/civicrm/vendor/composer/installed.json b/drupal/sites/all/modules/civicrm/vendor/composer/installed.json index 06c49ff247..fb3331db3d 100644 --- a/drupal/sites/all/modules/civicrm/vendor/composer/installed.json +++ b/drupal/sites/all/modules/civicrm/vendor/composer/installed.json @@ -5778,17 +5778,17 @@ }, { "name": "zetacomponents/mail", - "version": "1.9.5", - "version_normalized": "1.9.5.0", + "version": "1.9.4", + "version_normalized": "1.9.4.0", "source": { "type": "git", "url": "https://github.com/zetacomponents/Mail.git", - "reference": "e106e5934a42cd1e37227fa50e79be648d60fa14" + "reference": "83ba646f36f753c0bbc8b2189c88d41ece326ea0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zetacomponents/Mail/zipball/e106e5934a42cd1e37227fa50e79be648d60fa14", - "reference": "e106e5934a42cd1e37227fa50e79be648d60fa14", + "url": "https://api.github.com/repos/zetacomponents/Mail/zipball/83ba646f36f753c0bbc8b2189c88d41ece326ea0", + "reference": "83ba646f36f753c0bbc8b2189c88d41ece326ea0", "shasum": "" }, "require": { @@ -5798,7 +5798,7 @@ "phpunit/phpunit": "~9.0", "zetacomponents/unit-test": "*" }, - "time": "2023-09-06T09:15:46+00:00", + "time": "2022-09-14T10:13:21+00:00", "type": "library", "extra": { "patches_applied": { @@ -5861,7 +5861,7 @@ "homepage": "https://github.com/zetacomponents", "support": { "issues": "https://github.com/zetacomponents/Mail/issues", - "source": "https://github.com/zetacomponents/Mail/tree/1.9.5" + "source": "https://github.com/zetacomponents/Mail/tree/1.9.4" }, "install-path": "../zetacomponents/mail" } diff --git a/drupal/sites/all/modules/civicrm/vendor/composer/installed.php b/drupal/sites/all/modules/civicrm/vendor/composer/installed.php index 5950fdb3b0..9632712805 100644 --- a/drupal/sites/all/modules/civicrm/vendor/composer/installed.php +++ b/drupal/sites/all/modules/civicrm/vendor/composer/installed.php @@ -1,11 +1,11 @@ array( - 'pretty_version' => '5.66.x-dev', - 'version' => '5.66.9999999.9999999-dev', + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => 'b6b0249cba65db56f62f4e7da4595ebc9a796080', + 'reference' => '32bf8ff01041e625cc57a36d4c9b0bde5a4ae5e3', 'name' => 'civicrm/civicrm-core', 'dev' => true, ), @@ -38,12 +38,12 @@ 'dev_requirement' => false, ), 'civicrm/civicrm-core' => array( - 'pretty_version' => '5.66.x-dev', - 'version' => '5.66.9999999.9999999-dev', + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => 'b6b0249cba65db56f62f4e7da4595ebc9a796080', + 'reference' => '32bf8ff01041e625cc57a36d4c9b0bde5a4ae5e3', 'dev_requirement' => false, ), 'civicrm/civicrm-cxn-rpc' => array( @@ -824,12 +824,12 @@ 'dev_requirement' => false, ), 'zetacomponents/mail' => array( - 'pretty_version' => '1.9.5', - 'version' => '1.9.5.0', + 'pretty_version' => '1.9.4', + 'version' => '1.9.4.0', 'type' => 'library', 'install_path' => __DIR__ . '/../zetacomponents/mail', 'aliases' => array(), - 'reference' => 'e106e5934a42cd1e37227fa50e79be648d60fa14', + 'reference' => '83ba646f36f753c0bbc8b2189c88d41ece326ea0', 'dev_requirement' => false, ), ), diff --git a/drupal/sites/all/modules/civicrm/vendor/zetacomponents/mail/ChangeLog b/drupal/sites/all/modules/civicrm/vendor/zetacomponents/mail/ChangeLog index a8500264ef..2963294a23 100644 --- a/drupal/sites/all/modules/civicrm/vendor/zetacomponents/mail/ChangeLog +++ b/drupal/sites/all/modules/civicrm/vendor/zetacomponents/mail/ChangeLog @@ -1,10 +1,3 @@ -1.9.5 - Wednesday 06 September 2023 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- Fixed tests. -- Fixed #87: Use filter_var(FILTER_VALIDATE_EMAIL) instead of homegrown - validation for email addresses. - 1.9.4 - Wednesday 14 September 2022 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/drupal/sites/all/modules/civicrm/vendor/zetacomponents/mail/src/mail.php b/drupal/sites/all/modules/civicrm/vendor/zetacomponents/mail/src/mail.php index 093f3d558b..27daa8e065 100644 --- a/drupal/sites/all/modules/civicrm/vendor/zetacomponents/mail/src/mail.php +++ b/drupal/sites/all/modules/civicrm/vendor/zetacomponents/mail/src/mail.php @@ -9,9 +9,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -93,7 +93,7 @@ * address embedded in the * ezcMailAddress object may only * contain letters from the - * function filter_var FILTER_VALIDATE_EMAIL. + * RETURN_PATH_CHARS set. * @property ezcMailOptions $options * Options for generating mail. See {@link ezcMailOptions}. * @@ -130,6 +130,11 @@ class ezcMail extends ezcMailPart */ const BASE64 = "base64"; + /** + * Characters allowed in the returnPath address + */ + const RETURN_PATH_CHARS = 'A-Za-z0-9_.@=/+{}#~\-\''; + /** * Holds the options for this class. * @@ -180,10 +185,13 @@ public function __set( $name, $value ) case 'returnPath': if ( $value !== null && !$value instanceof ezcMailAddress ) { - // return nothing; - } else { - $this->properties[$name] = $value; + throw new ezcBaseValueException( $name, $value, 'ezcMailAddress or null' ); + } + if ( $value !== null && preg_replace( '([' . self::RETURN_PATH_CHARS . '])', '', $value->email ) != '' ) + { + throw new ezcBaseValueException( $name, $value->email, 'the characters \'' . self::RETURN_PATH_CHARS . '\'' ); } + $this->properties[$name] = $value; break; case 'from': diff --git a/drupal/sites/all/modules/civicrm/vendor/zetacomponents/mail/src/transports/mta/mta_transport.php b/drupal/sites/all/modules/civicrm/vendor/zetacomponents/mail/src/transports/mta/mta_transport.php index c31347220f..72f7eabcfd 100644 --- a/drupal/sites/all/modules/civicrm/vendor/zetacomponents/mail/src/transports/mta/mta_transport.php +++ b/drupal/sites/all/modules/civicrm/vendor/zetacomponents/mail/src/transports/mta/mta_transport.php @@ -39,11 +39,6 @@ */ class ezcMailMtaTransport implements ezcMailTransport { - /** - * Characters allowed in the returnPath address - */ - const RETURN_PATH_CHARS = 'A-Za-z0-9_.@=/+{}#~\-\''; - /** * Constructs a new ezcMailMtaTransport. */ @@ -73,7 +68,7 @@ public function send( ezcMail $mail ) $additionalParameters = ""; if ( isset( $mail->returnPath ) ) { - $sanitized = preg_replace( '([^' . self::RETURN_PATH_CHARS . '])', '', $mail->returnPath->email ); + $sanitized = preg_replace( '([^' . ezcMail::RETURN_PATH_CHARS . '])', '', $mail->returnPath->email ); $additionalParameters = "-f{$sanitized}"; } $success = mail( ezcMailTools::composeEmailAddresses( $mail->to ),