From b795cfc32eae2fa2fae4d8fbac564b9da2b9c331 Mon Sep 17 00:00:00 2001 From: Samuel Vanhove <samuel@symbiotic.coop> Date: Mon, 16 Apr 2018 16:42:34 +1200 Subject: [PATCH] CRM-20598 Phone ext in profile edit mode is messing up with address --- CRM/Contact/BAO/Contact.php | 28 +++++++-- tests/phpunit/CRM/Contact/BAO/ContactTest.php | 60 +++++++++++++++++++ 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/CRM/Contact/BAO/Contact.php b/CRM/Contact/BAO/Contact.php index 51e8f498b2..b3ff125a3f 100644 --- a/CRM/Contact/BAO/Contact.php +++ b/CRM/Contact/BAO/Contact.php @@ -652,6 +652,27 @@ WHERE civicrm_contact.id = " . CRM_Utils_Type::escape($id, 'Integer'); return NULL; } + /** + * Get the relevant location entity for the array key. + * + * Based on the field name we determine which location entity + * we are dealing with. Apart from a few specific ones they + * are mostly 'address' (the default). + * + * @param string $fieldName + * + * @return string + */ + protected static function getLocationEntityForKey($fieldName) { + if (in_array($fieldName, ['email', 'phone', 'im', 'openid'])) { + return $fieldName; + } + if ($fieldName === 'phone_ext') { + return 'phone'; + } + return 'address'; + } + /** * Create last viewed link to recently updated contact. * @@ -2181,7 +2202,7 @@ ORDER BY civicrm_email.is_primary DESC"; $loc = CRM_Utils_Array::key($index, $locationType); - $blockName = in_array($fieldName, $blocks) ? $fieldName : 'address'; + $blockName = self::getLocationEntityForKey($fieldName); $data[$blockName][$loc]['location_type_id'] = $locTypeId; @@ -2219,9 +2240,6 @@ ORDER BY civicrm_email.is_primary DESC"; unset($data['phone'][$loc]['is_primary']); } } - elseif ($fieldName == 'phone_ext') { - $data['phone'][$loc]['phone_ext'] = $value; - } elseif ($fieldName == 'email') { $data['email'][$loc]['email'] = $value; if (empty($contactID)) { @@ -2278,7 +2296,7 @@ ORDER BY civicrm_email.is_primary DESC"; $data['address'][$loc][substr($fieldName, 8)] = $value; } else { - $data['address'][$loc][$fieldName] = $value; + $data[$blockName][$loc][$fieldName] = $value; } } } diff --git a/tests/phpunit/CRM/Contact/BAO/ContactTest.php b/tests/phpunit/CRM/Contact/BAO/ContactTest.php index d7250a6cd0..2d13628a97 100644 --- a/tests/phpunit/CRM/Contact/BAO/ContactTest.php +++ b/tests/phpunit/CRM/Contact/BAO/ContactTest.php @@ -1565,4 +1565,64 @@ class CRM_Contact_BAO_ContactTest extends CiviUnitTestCase { $this->contactDelete($contactId); } + /** + * Test case for UpdateProfileLocationLeak (CRM-20598). + */ + public function testUpdateProfileLocationLeak() { + // create a simple contact with address and phone that share the same location type + $defaults = $this->contactParams(); + $params = array( + 'first_name' => $defaults['first_name'], + 'last_name' => $defaults['last_name'], + 'contact_type' => 'Individual', + 'address' => array(1 => $defaults['address'][1]), + 'phone' => array(1 => $defaults['phone'][1]), + ); + $contact = CRM_Contact_BAO_Contact::create($params); + $contactId = $contact->id; + + // now, update using a profile with phone, email, address... that share the same location type + $updatePfParams = array( + 'first_name' => $params['first_name'], + 'last_name' => $params['first_name'], + 'street_address-Primary' => $params['address'][1]['street_address'], + 'state_province-Primary' => $params['address'][1]['state_province_id'], + 'country-Primary' => $params['address'][1]['country_id'], + 'phone-Primary-1' => $params['phone'][1]['phone'], + 'phone_ext-Primary-1' => '345', + ); + + //create the contact using create profile contact. + $fields = CRM_Contact_BAO_Contact::exportableFields('Individual'); + + // for this test, we need to make CiviCRM think we are logged in + // so that updateBlankLocInfo is set to 1 (erase blank value from the database) + CRM_Core_Session::singleton()->set('authSrc', CRM_Core_Permission::AUTH_SRC_LOGIN); + + // now, emulate the contact update using a profile + $contactID = CRM_Contact_BAO_Contact::createProfileContact($updatePfParams, $fields, $contactId, + NULL, NULL, NULL, TRUE + ); + + //check the contact ids + $this->assertEquals($contactId, $contactID, 'check for Contact ids'); + $phone = $this->callAPISuccess('Phone', 'getsingle', ['contact_id' => $contactID]); + $this->assertEquals('345', $phone['phone_ext']); + $this->assertEquals($params['phone'][1]['phone'], $phone['phone']); + + //check the values in DB. + $searchParams = array( + 'contact_id' => $contactId, + 'location_type_id' => 1, + 'is_primary' => 1, + ); + $compareParams = array( + 'street_address' => CRM_Utils_Array::value('street_address-Primary', $updatePfParams), + ); + $this->assertDBCompareValues('CRM_Core_DAO_Address', $searchParams, $compareParams); + + //cleanup DB by deleting the contact + $this->contactDelete($contactId); + } + } -- 2.25.1