Merge pull request #15826 from seamuslee001/dev_core_183_dedupe
[civicrm-core.git] / api / v3 / Cxn.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 * The Cxn API allows a Civi site to initiate a connection to a
14 * remote application. There are three primary actions:
15 *
16 * - register: Establish a new connection.
17 * - unregister: Destroy an existing connection.
18 * - get: Get a list of existing connections.
19 */
20
21 /**
22 * Adjust metadata for "register" action.
23 *
24 * @param array $spec
25 * List of fields.
26 */
27 function _civicrm_api3_cxn_register_spec(&$spec) {
28 $daoFields = CRM_Cxn_DAO_Cxn::fields();
29 $spec['app_guid'] = $daoFields['app_guid'];
30 $spec['app_meta_url'] = [
31 'name' => 'app_meta_url',
32 'type' => CRM_Utils_Type::T_STRING,
33 'title' => ts('Application Metadata URL'),
34 'description' => 'Application Metadata URL',
35 'maxlength' => 255,
36 'size' => CRM_Utils_Type::HUGE,
37 ];
38 }
39
40 /**
41 * Register with a remote application and create a new connection.
42 *
43 * One should generally identify an application using the app_guid.
44 * However, if you need to test a new/experimental application, then
45 * disable CIVICRM_CXN_CA and specify app_meta_url.
46 *
47 * @param array $params
48 * Array with keys:
49 * - app_guid: The unique identifer of the target application.
50 * - app_meta_url: The URL for the application's metadata.
51 * @return array
52 * @throws Exception
53 */
54 function civicrm_api3_cxn_register($params) {
55 if (!empty($params['app_meta_url'])) {
56 list ($status, $json) = CRM_Utils_HttpClient::singleton()->get($params['app_meta_url']);
57 if (CRM_Utils_HttpClient::STATUS_OK != $status) {
58 throw new API_Exception("Failed to download appMeta. (Bad HTTP response)");
59 }
60 $appMeta = json_decode($json, TRUE);
61 if (empty($appMeta)) {
62 throw new API_Exception("Failed to download appMeta. (Malformed)");
63 }
64 }
65 elseif (!empty($params['app_guid'])) {
66 $appMeta = civicrm_api3('CxnApp', 'getsingle', [
67 'appId' => $params['app_guid'],
68 ]);
69 }
70
71 if (empty($appMeta) || !is_array($appMeta)) {
72 throw new API_Exception("Missing expected parameter: app_guid");
73 }
74 \Civi\Cxn\Rpc\AppMeta::validate($appMeta);
75
76 try {
77 /** @var \Civi\Cxn\Rpc\RegistrationClient $client */
78 $client = \Civi::service('cxn_reg_client');
79 list($cxnId, $result) = $client->register($appMeta);
80 CRM_Cxn_BAO_Cxn::updateAppMeta($appMeta);
81 }
82 catch (Exception $e) {
83 CRM_Cxn_BAO_Cxn::updateAppMeta($appMeta);
84 throw $e;
85 }
86
87 return $result;
88 }
89
90 /**
91 * Adjust metadata for cxn unregister.
92 *
93 * @param array $spec
94 */
95 function _civicrm_api3_cxn_unregister_spec(&$spec) {
96 $daoFields = CRM_Cxn_DAO_Cxn::fields();
97 $spec['cxn_guid'] = $daoFields['cxn_guid'];
98 $spec['app_guid'] = $daoFields['app_guid'];
99 $spec['force'] = [
100 'name' => 'force',
101 'type' => CRM_Utils_Type::T_BOOLEAN,
102 'title' => ts('Force'),
103 'description' => 'Destroy connection even if the remote application is non-responsive.',
104 'default' => '0',
105 ];
106 }
107
108 /**
109 * Unregister with a remote application; destroy an existing connection.
110 *
111 * Specify app_guid XOR cxn_guid.
112 *
113 * @param array $params
114 * Array with keys:
115 * - cxn_guid: string
116 * - app_guid: string
117 * - force: bool
118 * @return array
119 */
120 function civicrm_api3_cxn_unregister($params) {
121 $cxnId = _civicrm_api3_cxn_parseCxnId($params);
122 $appMeta = CRM_Cxn_BAO_Cxn::getAppMeta($cxnId);
123
124 /** @var \Civi\Cxn\Rpc\RegistrationClient $client */
125 $client = \Civi::service('cxn_reg_client');
126 list($cxnId, $result) = $client->unregister($appMeta, CRM_Utils_Array::value('force', $params, FALSE));
127
128 return $result;
129 }
130
131 /**
132 * @param array $params
133 * An array with cxn_guid and/or app_guid.
134 * @return string
135 * The CxnId. (If not available, then an exception is thrown.)
136 *
137 * @throws API_Exception
138 */
139 function _civicrm_api3_cxn_parseCxnId($params) {
140 $cxnId = NULL;
141
142 if (!empty($params['cxn_guid'])) {
143 $cxnId = $params['cxn_guid'];
144 }
145 elseif (!empty($params['app_guid'])) {
146 $cxnId = CRM_Core_DAO::singleValueQuery('SELECT cxn_guid FROM civicrm_cxn WHERE app_guid = %1', [
147 1 => [$params['app_guid'], 'String'],
148 ]);
149 if (!$cxnId) {
150 throw new API_Exception("The app_guid does not correspond to an active connection.");
151 }
152 }
153 if (!$cxnId) {
154 throw new API_Exception('Missing required parameter: cxn_guid');
155 }
156 return $cxnId;
157 }
158
159 /**
160 * Adjust metadata for cxn get action.
161 *
162 * @param array $spec
163 */
164 function _civicrm_api3_cxn_get_spec(&$spec) {
165 // Don't trust AJAX callers or other external code to modify, filter, or return the secret.
166 unset($spec['secret']);
167 }
168
169 /**
170 * Returns an array of Cxn records.
171 *
172 * @param array $params
173 * Array of one or more valid property_name=>value pairs.
174 *
175 * @return array
176 * API result array.
177 */
178 function civicrm_api3_cxn_get($params) {
179 // Don't trust AJAX callers or other external code to modify, filter, or return the secret.
180 unset($params['secret']);
181
182 $result = _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params);
183 if (is_array($result['values'])) {
184 foreach (array_keys($result['values']) as $i) {
185 if (!empty($result['values'][$i]['app_meta'])) {
186 $result['values'][$i]['app_meta'] = json_decode($result['values'][$i]['app_meta'], TRUE);
187 }
188 if (!empty($result['values'][$i]['perm'])) {
189 $result['values'][$i]['perm'] = json_decode($result['values'][$i]['perm'], TRUE);
190 }
191 // Don't trust AJAX callers or other external code to modify, filter, or return the secret.
192 unset($result['values'][$i]['secret']);
193 }
194 }
195
196 return $result;
197 }
198
199 /**
200 * Adjust metadata for "getlink" action.
201 *
202 * @param array $spec
203 * List of fields.
204 */
205 function _civicrm_api3_cxn_getlink_spec(&$spec) {
206 $daoFields = CRM_Cxn_DAO_Cxn::fields();
207 $spec['app_guid'] = $daoFields['app_guid'];
208 $spec['cxn_guid'] = $daoFields['cxn_guid'];
209 $spec['page_name'] = [
210 'name' => 'page_name',
211 'type' => CRM_Utils_Type::T_STRING,
212 'title' => ts('Page Type'),
213 'description' => 'The type of page (eg "settings")',
214 'maxlength' => 63,
215 'size' => CRM_Utils_Type::HUGE,
216 'api.aliases' => ['page'],
217 ];
218 }
219
220 /**
221 *
222 * @param array $params
223 * Array with keys:
224 * - cxn_guid OR app_guid: string.
225 * - page: string.
226 * @return array
227 * @throws Exception
228 */
229 function civicrm_api3_cxn_getlink($params) {
230 $cxnId = _civicrm_api3_cxn_parseCxnId($params);
231 $appMeta = CRM_Cxn_BAO_Cxn::getAppMeta($cxnId);
232
233 if (empty($params['page_name']) || !is_string($params['page_name'])) {
234 throw new API_Exception("Invalid page");
235 }
236
237 /** @var \Civi\Cxn\Rpc\RegistrationClient $client */
238 $client = \Civi::service('cxn_reg_client');
239 return $client->call($appMeta, 'Cxn', 'getlink', [
240 'page' => $params['page_name'],
241 ]);
242 }
243
244 /**
245 *
246 * @param array $params
247 * @return array
248 * @throws Exception
249 */
250 function civicrm_api3_cxn_getcfg($params) {
251 $result = [
252 'CIVICRM_CXN_CA' => defined('CIVICRM_CXN_CA') ? CIVICRM_CXN_CA : NULL,
253 'CIVICRM_CXN_VIA' => defined('CIVICRM_CXN_VIA') ? CIVICRM_CXN_VIA : NULL,
254 'CIVICRM_CXN_APPS_URL' => defined('CIVICRM_CXN_APPS_URL') ? CIVICRM_CXN_APPS_URL : NULL,
255 'siteCallbackUrl' => CRM_Cxn_BAO_Cxn::getSiteCallbackUrl(),
256 ];
257 return civicrm_api3_create_success($result);
258 }
259
260 /**
261 * Creates or modifies a Cxn row.
262 *
263 * @param array $params
264 * Array with keys:
265 * - id, cxn_guid OR app_guid: string.
266 * - is_active: boolean.
267 * - options: JSON
268 * @return page
269 * @throws Exception
270 */
271 function civicrm_api3_cxn_create($params) {
272 $result = "";
273
274 try {
275 // get the ID
276 if (!empty($params['id'])) {
277 $cxnId = $params['id'];
278 }
279 else {
280 $cxnId = _civicrm_api3_cxn_parseCxnId($params);
281 }
282
283 // see if it's sth to update
284 if (isset($params['options']) || isset($params['is_active'])) {
285
286 $dao = new CRM_Cxn_DAO_Cxn();
287 $dao->id = $cxnId;
288
289 if ($dao->find()) {
290 if (isset($params['is_active'])) {
291 $dao->is_active = (int) $params['is_active'];
292 }
293 if (isset($params['options'])) {
294 $dao->options = $params['options'];
295 }
296
297 $result = $dao->save();
298 }
299
300 }
301 return civicrm_api3_create_success($result, $params, 'Cxn', 'create');
302
303 }
304 catch (Exception $ex) {
305 throw $ex;
306 }
307 }