CRM-20598 Phone ext in profile edit mode is messing up with address
authorSamuel Vanhove <samuel@symbiotic.coop>
Mon, 16 Apr 2018 04:42:34 +0000 (16:42 +1200)
committereileen <emcnaughton@wikimedia.org>
Mon, 16 Apr 2018 04:42:34 +0000 (16:42 +1200)
CRM/Contact/BAO/Contact.php
tests/phpunit/CRM/Contact/BAO/ContactTest.php

index 51e8f498b2d1c71600cc745684e93a7694d609fa..b3ff125a3f8dcfec299377726d0ccca220307cf8 100644 (file)
@@ -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;
           }
         }
       }
index d7250a6cd0fec9172f06f9819568200ff2ac78e2..2d13628a9780d2c0619f8c4951880b018525bd4f 100644 (file)
@@ -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);
+  }
+
 }