CRM-16173 - Cxn API - Add "get". Fix GUID fields and API metadata.
authorTim Otten <totten@civicrm.org>
Fri, 27 Mar 2015 08:10:11 +0000 (01:10 -0700)
committerTim Otten <totten@civicrm.org>
Tue, 14 Jul 2015 04:00:07 +0000 (21:00 -0700)
APIv3 overloads fields like "cxn_id" as aliases for numeric "id". Therefore,
it's problematic to use "cxn_id" and "app_id" as GUID fields.  This commit
renames them to "cxn_guid" and "app_guid".

CRM/Cxn/BAO/Cxn.php
CRM/Cxn/CiviCxnStore.php
api/v3/Cxn.php
xml/schema/Cxn/Cxn.xml

index 76150455a86d372f2143a073427788ab64fd19cd..26a57c70c98a1cfc47577eabd1b3545fe9b7647c 100644 (file)
@@ -65,7 +65,7 @@ class CRM_Cxn_BAO_Cxn extends CRM_Cxn_DAO_Cxn {
    */
   public static function updateAppMeta($appMeta) {
     \Civi\Cxn\Rpc\AppMeta::validate($appMeta);
-    CRM_Core_DAO::executeQuery('UPDATE civicrm_cxn SET app_meta = %1 WHERE app_id = %2', array(
+    CRM_Core_DAO::executeQuery('UPDATE civicrm_cxn SET app_meta = %1 WHERE app_guid = %2', array(
       1 => array(json_encode($appMeta), 'String'),
       2 => array($appMeta['appId'], 'String'),
     ));
@@ -79,7 +79,7 @@ class CRM_Cxn_BAO_Cxn extends CRM_Cxn_DAO_Cxn {
    * @throws \Civi\Cxn\Rpc\Exception\CxnException
    */
   public static function getAppMeta($cxnId) {
-    $appMetaJson = CRM_Core_DAO::getFieldValue('CRM_Cxn_DAO_Cxn', $cxnId, 'app_meta', 'cxn_id', TRUE);
+    $appMetaJson = CRM_Core_DAO::getFieldValue('CRM_Cxn_DAO_Cxn', $cxnId, 'app_meta', 'cxn_guid', TRUE);
     $appMeta = json_decode($appMetaJson, TRUE);
     \Civi\Cxn\Rpc\AppMeta::validate($appMeta);
     return $appMeta;
index 8503fa24abdc8385e2015fb0632fc10f6475181a..eb05f86119fe47499d67c03784d81950df82385b 100644 (file)
@@ -28,7 +28,7 @@ class CRM_Cxn_CiviCxnStore implements Civi\Cxn\Rpc\CxnStore\CxnStoreInterface {
       return $this->cxns[$cxnId];
     }
     $dao = new CRM_Cxn_DAO_Cxn();
-    $dao->cxn_id = $cxnId;
+    $dao->cxn_guid = $cxnId;
     if ($dao->find(TRUE)) {
       $this->cxns[$cxnId] = $this->convertDaoToCxn($dao);
       return $this->cxns[$cxnId];
@@ -43,10 +43,10 @@ class CRM_Cxn_CiviCxnStore implements Civi\Cxn\Rpc\CxnStore\CxnStoreInterface {
    */
   public function getByAppId($appId) {
     $dao = new CRM_Cxn_DAO_Cxn();
-    $dao->app_id = $appId;
+    $dao->app_guid = $appId;
     if ($dao->find(TRUE)) {
-      $this->cxns[$dao->cxn_id] = $this->convertDaoToCxn($dao);
-      return $this->cxns[$dao->cxn_id];
+      $this->cxns[$dao->cxn_guid] = $this->convertDaoToCxn($dao);
+      return $this->cxns[$dao->cxn_guid];
     }
     else {
       return NULL;
@@ -58,7 +58,7 @@ class CRM_Cxn_CiviCxnStore implements Civi\Cxn\Rpc\CxnStore\CxnStoreInterface {
    */
   public function add($cxn) {
     $dao = new CRM_Cxn_DAO_Cxn();
-    $dao->cxn_id = $cxn['cxnId'];
+    $dao->cxn_guid = $cxn['cxnId'];
     $dao->find(TRUE);
     $this->convertCxnToDao($cxn, $dao);
     $dao->save();
@@ -79,7 +79,7 @@ class CRM_Cxn_CiviCxnStore implements Civi\Cxn\Rpc\CxnStore\CxnStoreInterface {
    * @inheritDoc
    */
   public function remove($cxnId) {
-    CRM_Core_DAO::executeQuery('DELETE FROM civicrm_cxn WHERE cxn_id = %1', array(
+    CRM_Core_DAO::executeQuery('DELETE FROM civicrm_cxn WHERE cxn_guid = %1', array(
       1 => array($cxnId, 'String'),
     ));
     unset($this->cxns[$cxnId]);
@@ -93,9 +93,9 @@ class CRM_Cxn_CiviCxnStore implements Civi\Cxn\Rpc\CxnStore\CxnStoreInterface {
   protected function convertDaoToCxn($dao) {
     $appMeta = json_decode($dao->app_meta, TRUE);
     return array(
-      'cxnId' => $dao->cxn_id,
+      'cxnId' => $dao->cxn_guid,
       'secret' => $dao->secret,
-      'appId' => $dao->app_id,
+      'appId' => $dao->app_guid,
       'appUrl' => $appMeta['appUrl'],
       'siteUrl' => CRM_Cxn_BAO_Cxn::getSiteCallbackUrl(),
       'perm' => json_decode($dao->perm, TRUE),
@@ -108,12 +108,13 @@ class CRM_Cxn_CiviCxnStore implements Civi\Cxn\Rpc\CxnStore\CxnStoreInterface {
    * @param CRM_Cxn_DAO_Cxn $dao
    */
   protected function convertCxnToDao($cxn, $dao) {
-    $dao->cxn_id = $cxn['cxnId'];
+    $dao->cxn_guid = $cxn['cxnId'];
     $dao->secret = $cxn['secret'];
-    $dao->app_id = $cxn['appId'];
+    $dao->app_guid = $cxn['appId'];
     $dao->perm = json_encode($cxn['perm']);
 
     // Note: we don't save siteUrl because it's more correct to regenerate on-demand.
     // Note: we don't save appUrl, but other processes will update appMeta.
   }
+
 }
index 29c53b3c9538a8ad2ae5d4f8d7fb3fd776d71504..9d24a3ed32dea02d7bddf253910100b145c511fc 100644 (file)
  */
 
 /**
+ * The Cxn API allows a Civi site to initiate a connection to a
+ * remote application. There are three primary actions:
+ *
+ *  - register: Establish a new connection.
+ *  - unregister: Destroy an existing connection.
+ *  - get: Get a list of existing connections.
+ */
+
+/**
+ * Adjust metadata for "register" action.
+ *
+ * @param array $spec
+ *   List of fields.
+ */
+function _civicrm_api3_cxn_register_spec(&$spec) {
+  $daoFields = CRM_Cxn_DAO_Cxn::fields();
+  $spec['app_guid'] = $daoFields['app_guid'];
+
+  if (!CRM_Cxn_BAO_Cxn::isAppMetaVerified()) {
+    $spec['app_meta_url'] = array(
+      'name' => 'app_meta_url',
+      'type' => CRM_Utils_Type::T_STRING,
+      'title' => ts('Application Metadata URL'),
+      'description' => 'Application Metadata URL',
+      'maxlength' => 255,
+      'size' => CRM_Utils_Type::HUGE,
+    );
+  }
+}
+
+/**
+ * Register with a remote application and create a new connection.
+ *
+ * One should generally identify an application using the app_guid.
+ * However, if you need to test a new/experimental application, then
+ * disable CIVICRM_CXN_CA and specify app_meta_url.
+ *
  * @param array $params
  *   Array with keys:
- *   - appMeta: the application's metadata.
+ *   - app_guid: The unique identifer of the target application.
+ *   - app_meta_url: The URL for the application's metadata.
  * @return array
+ * @throws Exception
  */
 function civicrm_api3_cxn_register($params) {
-  if (empty($params['appMeta']) && !empty($params['appMetaUrl'])) {
+  if (!empty($params['app_meta_url'])) {
     if (!CRM_Cxn_BAO_Cxn::isAppMetaVerified()) {
-      list ($status, $json) = CRM_Utils_HttpClient::singleton()->get($params['appMetaUrl']);
+      list ($status, $json) = CRM_Utils_HttpClient::singleton()->get($params['app_meta_url']);
       if (CRM_Utils_HttpClient::STATUS_OK != $status) {
         throw new API_Exception("Failed to download appMeta.");
       }
-      $params['appMeta'] = json_decode($json, TRUE);
+      $appMeta = json_decode($json, TRUE);
     }
     else {
       // Note: The metadata includes a cert, but the details aren't signed.
@@ -47,38 +86,75 @@ function civicrm_api3_cxn_register($params) {
       throw new API_Exception('This site is configured to only connect to applications with verified metadata.');
     }
   }
+  elseif (!empty($params['app_guid'])) {
+    $appMeta = civicrm_api3('CxnApp', 'getsingle', array(
+      'app_guid' => $params['app_guid'],
+    ));
+  }
 
-  if (empty($params['appMeta']) || !is_array($params['appMeta'])) {
-    throw new API_Exception("Missing expected parameter: appMeta (array)");
+  if (empty($appMeta) || !is_array($appMeta)) {
+    throw new API_Exception("Missing expected parameter: app_guid");
   }
-  \Civi\Cxn\Rpc\AppMeta::validate($params['appMeta']);
+  \Civi\Cxn\Rpc\AppMeta::validate($appMeta);
 
   try {
     /** @var \Civi\Cxn\Rpc\RegistrationClient $client */
     $client = \Civi\Core\Container::singleton()->get('cxn_reg_client');
-    list($cxnId, $result) = $client->register($params['appMeta']);
-    CRM_Cxn_BAO_Cxn::updateAppMeta($params['appMeta']);
+    list($cxnId, $result) = $client->register($appMeta);
+    CRM_Cxn_BAO_Cxn::updateAppMeta($appMeta);
   }
   catch (Exception $e) {
-    CRM_Cxn_BAO_Cxn::updateAppMeta($params['appMeta']);
+    CRM_Cxn_BAO_Cxn::updateAppMeta($appMeta);
     throw $e;
   }
 
   return $result;
 }
 
+function _civicrm_api3_cxn_unregister_spec(&$spec) {
+  $daoFields = CRM_Cxn_DAO_Cxn::fields();
+  $spec['cxn_guid'] = $daoFields['cxn_guid'];
+  $spec['app_guid'] = $daoFields['app_guid'];
+  $spec['force'] = array(
+    'name' => 'force',
+    'type' => CRM_Utils_Type::T_BOOLEAN,
+    'title' => ts('Force'),
+    'description' => 'Destroy connection even if the remote application is non-responsive.',
+    'default' => '0',
+  );
+}
+
 /**
+ * Unregister with a remote application; destroy an existing connection.
+ *
+ * Specify app_guid XOR cxn_guid.
+ *
  * @param array $params
  *   Array with keys:
- *   - cxnId: string
+ *   - cxn_guid: string
+ *   - app_guid: string
+ *   - force: bool
  * @return array
  */
 function civicrm_api3_cxn_unregister($params) {
-  if (empty($params['cxnId'])) {
-    throw new API_Exception('Missing required parameter: cxnId');
+  $cxnId = NULL;
+
+  if (!empty($params['cxn_guid'])) {
+    $cxnId = $params['cxn_guid'];
+  }
+  elseif (!empty($params['app_guid'])) {
+    $cxnId = CRM_Core_DAO::singleValueQuery('SELECT cxn_guid FROM civicrm_cxn WHERE app_guid = %1', array(
+      1 => array($params['app_guid'], 'String'),
+    ));
+    if (!$cxnId) {
+      throw new API_Exception("The app_guid does not correspond to an active connection.");
+    }
+  }
+  if (!$cxnId) {
+    throw new API_Exception('Missing required parameter: cxn_guid');
   }
 
-  $appMeta = CRM_Cxn_BAO_Cxn::getAppMeta($params['cxnId']);
+  $appMeta = CRM_Cxn_BAO_Cxn::getAppMeta($cxnId);
 
   /** @var \Civi\Cxn\Rpc\RegistrationClient $client */
   $client = \Civi\Core\Container::singleton()->get('cxn_reg_client');
@@ -86,3 +162,16 @@ function civicrm_api3_cxn_unregister($params) {
 
   return $result;
 }
+
+/**
+ * Returns an array of Cxn records.
+ *
+ * @param array $params
+ *   Array of one or more valid property_name=>value pairs.
+ *
+ * @return array
+ *   API result array.
+ */
+function civicrm_api3_cxn_get($params) {
+  return _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params);
+}
index 8d945de40264f180ed646d304c80bb35f01c3e67..dc06a3dfc236903c908267e972d641d32c7e636f 100644 (file)
@@ -18,7 +18,7 @@
   <!-- Application identification -->
 
   <field>
-    <name>app_id</name>
+    <name>app_guid</name>
     <title>Application GUID</title>
     <type>varchar</type>
     <length>128</length>
@@ -27,7 +27,7 @@
   </field>
   <index>
     <name>UI_appid</name>
-    <fieldName>app_id</fieldName>
+    <fieldName>app_guid</fieldName>
     <unique>true</unique>
     <add>4.6</add>
   </index>
@@ -42,7 +42,7 @@
   <!-- Connection details -->
   
   <field>
-    <name>cxn_id</name>
+    <name>cxn_guid</name>
     <title>Connection GUID</title>
     <type>varchar</type>
     <length>128</length>
@@ -51,7 +51,7 @@
   </field>
   <index>
     <name>UI_keypair_cxnid</name>
-    <fieldName>cxn_id</fieldName>
+    <fieldName>cxn_guid</fieldName>
     <unique>true</unique>
     <add>4.6</add>
   </index>