Commit | Line | Data |
---|---|---|
6a488035 | 1 | <?php |
6a488035 TO |
2 | /* |
3 | +--------------------------------------------------------------------+ | |
fee14197 | 4 | | CiviCRM version 5 | |
6a488035 | 5 | +--------------------------------------------------------------------+ |
6b83d5bd | 6 | | Copyright CiviCRM LLC (c) 2004-2019 | |
6a488035 TO |
7 | +--------------------------------------------------------------------+ |
8 | | This file is a part of CiviCRM. | | |
9 | | | | |
10 | | CiviCRM is free software; you can copy, modify, and distribute it | | |
11 | | under the terms of the GNU Affero General Public License | | |
12 | | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. | | |
13 | | | | |
14 | | CiviCRM is distributed in the hope that it will be useful, but | | |
15 | | WITHOUT ANY WARRANTY; without even the implied warranty of | | |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | | |
17 | | See the GNU Affero General Public License for more details. | | |
18 | | | | |
19 | | You should have received a copy of the GNU Affero General Public | | |
20 | | License and the CiviCRM Licensing Exception along | | |
21 | | with this program; if not, contact CiviCRM LLC | | |
22 | | at info[AT]civicrm[DOT]org. If you have questions about the | | |
23 | | GNU Affero General Public License or the licensing of CiviCRM, | | |
24 | | see the CiviCRM license FAQ at http://civicrm.org/licensing | | |
25 | +--------------------------------------------------------------------+ | |
26 | */ | |
27 | ||
c490a46a CW |
28 | define('API_V3_EXTENSION_DELIMITER', ','); |
29 | ||
30 | ||
6a488035 | 31 | /** |
244bbdd8 | 32 | * This provides an api interface for CiviCRM extension management. |
6a488035 TO |
33 | * |
34 | * @package CiviCRM_APIv3 | |
6a488035 TO |
35 | */ |
36 | ||
37 | /** | |
dc64d047 | 38 | * Install an extension. |
6a488035 | 39 | * |
cf470720 TO |
40 | * @param array $params |
41 | * Input parameters. | |
e5f24f02 CW |
42 | * - key: string, eg "com.example.myextension" |
43 | * - keys: array of string, eg array("com.example.myextension1", "com.example.myextension2") | |
3b3f6d23 | 44 | * - path: string, e.g. "/var/www/extensions/*" |
e5f24f02 CW |
45 | * |
46 | * Using 'keys' should be more performant than making multiple API calls with 'key' | |
6a488035 | 47 | * |
a6c01b45 | 48 | * @return array |
6a488035 TO |
49 | */ |
50 | function civicrm_api3_extension_install($params) { | |
82b474af | 51 | $keys = _civicrm_api3_getKeys($params); |
dbb0dbe6 | 52 | if (!$keys) { |
6a488035 TO |
53 | return civicrm_api3_create_success(); |
54 | } | |
55 | ||
56 | try { | |
4827c43c TO |
57 | $manager = CRM_Extension_System::singleton()->getManager(); |
58 | $manager->install($manager->findInstallRequirements($keys)); | |
0db6c3e1 TO |
59 | } |
60 | catch (CRM_Extension_Exception $e) { | |
6a488035 TO |
61 | return civicrm_api3_create_error($e->getMessage()); |
62 | } | |
63 | ||
64 | return civicrm_api3_create_success(); | |
65 | } | |
66 | ||
e5f24f02 CW |
67 | /** |
68 | * Spec function for getfields | |
69 | * @param $fields | |
70 | */ | |
71 | function _civicrm_api3_extension_install_spec(&$fields) { | |
72 | $fields['keys'] = array( | |
73 | 'title' => 'Extension Key(s)', | |
e5f24f02 CW |
74 | 'api.aliases' => array('key'), |
75 | 'type' => CRM_Utils_Type::T_STRING, | |
76 | 'description' => 'Fully qualified name of one or more extensions', | |
77 | ); | |
3b3f6d23 TO |
78 | $fields['path'] = array( |
79 | 'title' => 'Extension Path', | |
80 | 'type' => CRM_Utils_Type::T_STRING, | |
81 | 'description' => 'The path to the extension. May use wildcard ("*").', | |
82 | ); | |
e5f24f02 CW |
83 | } |
84 | ||
9a477d10 | 85 | /** |
d1b0d05e | 86 | * Upgrade an extension - runs upgrade_N hooks and system.flush. |
9a477d10 | 87 | * |
a6c01b45 | 88 | * @return array |
72b3a70c | 89 | * API result |
9a477d10 FG |
90 | */ |
91 | function civicrm_api3_extension_upgrade() { | |
92 | CRM_Core_Invoke::rebuildMenuAndCaches(TRUE); | |
93 | $queue = CRM_Extension_Upgrades::createQueue(); | |
94 | $runner = new CRM_Queue_Runner(array( | |
95 | 'title' => 'Extension Upgrades', | |
96 | 'queue' => $queue, | |
97 | 'errorMode' => CRM_Queue_Runner::ERROR_ABORT, | |
98 | )); | |
99 | ||
100 | try { | |
101 | $result = $runner->runAll(); | |
0db6c3e1 TO |
102 | } |
103 | catch (CRM_Extension_Exception $e) { | |
9a477d10 FG |
104 | return civicrm_api3_create_error($e->getMessage()); |
105 | } | |
106 | ||
107 | if ($result === TRUE) { | |
108 | return civicrm_api3_create_success(); | |
0db6c3e1 TO |
109 | } |
110 | else { | |
9a477d10 FG |
111 | return $result; |
112 | } | |
113 | } | |
114 | ||
6a488035 | 115 | /** |
dc64d047 | 116 | * Enable an extension. |
6a488035 | 117 | * |
cf470720 TO |
118 | * @param array $params |
119 | * Input parameters. | |
e5f24f02 CW |
120 | * - key: string, eg "com.example.myextension" |
121 | * - keys: array of string, eg array("com.example.myextension1", "com.example.myextension2") | |
3b3f6d23 | 122 | * - path: string, e.g. "/var/www/vendor/foo/myext" or "/var/www/vendor/*" |
e5f24f02 CW |
123 | * |
124 | * Using 'keys' should be more performant than making multiple API calls with 'key' | |
6a488035 | 125 | * |
a6c01b45 | 126 | * @return array |
6a488035 TO |
127 | */ |
128 | function civicrm_api3_extension_enable($params) { | |
82b474af | 129 | $keys = _civicrm_api3_getKeys($params); |
6a488035 TO |
130 | if (count($keys) == 0) { |
131 | return civicrm_api3_create_success(); | |
132 | } | |
133 | ||
4827c43c TO |
134 | $manager = CRM_Extension_System::singleton()->getManager(); |
135 | $manager->enable($manager->findInstallRequirements($keys)); | |
6a488035 TO |
136 | return civicrm_api3_create_success(); |
137 | } | |
138 | ||
e5f24f02 CW |
139 | /** |
140 | * Spec function for getfields | |
141 | * @param $fields | |
142 | */ | |
143 | function _civicrm_api3_extension_enable_spec(&$fields) { | |
144 | _civicrm_api3_extension_install_spec($fields); | |
145 | } | |
146 | ||
6a488035 | 147 | /** |
9d32e6f7 | 148 | * Disable an extension. |
6a488035 | 149 | * |
cf470720 TO |
150 | * @param array $params |
151 | * Input parameters. | |
e5f24f02 CW |
152 | * - key: string, eg "com.example.myextension" |
153 | * - keys: array of string, eg array("com.example.myextension1", "com.example.myextension2") | |
3b3f6d23 | 154 | * - path: string, e.g. "/var/www/vendor/foo/myext" or "/var/www/vendor/*" |
e5f24f02 CW |
155 | * |
156 | * Using 'keys' should be more performant than making multiple API calls with 'key' | |
6a488035 | 157 | * |
a6c01b45 | 158 | * @return array |
6a488035 TO |
159 | */ |
160 | function civicrm_api3_extension_disable($params) { | |
82b474af | 161 | $keys = _civicrm_api3_getKeys($params); |
6a488035 TO |
162 | if (count($keys) == 0) { |
163 | return civicrm_api3_create_success(); | |
164 | } | |
165 | ||
166 | CRM_Extension_System::singleton()->getManager()->disable($keys); | |
167 | return civicrm_api3_create_success(); | |
168 | } | |
169 | ||
e5f24f02 CW |
170 | /** |
171 | * Spec function for getfields | |
172 | * @param $fields | |
173 | */ | |
174 | function _civicrm_api3_extension_disable_spec(&$fields) { | |
175 | _civicrm_api3_extension_install_spec($fields); | |
176 | } | |
177 | ||
6a488035 | 178 | /** |
dc64d047 | 179 | * Uninstall an extension. |
6a488035 | 180 | * |
cf470720 TO |
181 | * @param array $params |
182 | * Input parameters. | |
e5f24f02 CW |
183 | * - key: string, eg "com.example.myextension" |
184 | * - keys: array of string, eg array("com.example.myextension1", "com.example.myextension2") | |
3b3f6d23 | 185 | * - path: string, e.g. "/var/www/vendor/foo/myext" or "/var/www/vendor/*" |
e5f24f02 CW |
186 | * |
187 | * Using 'keys' should be more performant than making multiple API calls with 'key' | |
188 | * | |
189 | * @todo: removeFiles as optional param | |
6a488035 | 190 | * |
a6c01b45 | 191 | * @return array |
6a488035 TO |
192 | */ |
193 | function civicrm_api3_extension_uninstall($params) { | |
82b474af | 194 | $keys = _civicrm_api3_getKeys($params); |
6a488035 TO |
195 | if (count($keys) == 0) { |
196 | return civicrm_api3_create_success(); | |
197 | } | |
198 | ||
6a488035 TO |
199 | CRM_Extension_System::singleton()->getManager()->uninstall($keys); |
200 | return civicrm_api3_create_success(); | |
201 | } | |
202 | ||
e5f24f02 CW |
203 | /** |
204 | * Spec function for getfields | |
205 | * @param $fields | |
206 | */ | |
207 | function _civicrm_api3_extension_uninstall_spec(&$fields) { | |
208 | _civicrm_api3_extension_install_spec($fields); | |
209 | //$fields['removeFiles'] = array( | |
210 | // 'title' => 'Remove files', | |
211 | // 'description' => 'Whether to remove the source tree. Default FALSE.', | |
212 | // 'type' => CRM_Utils_Type::T_BOOLEAN, | |
213 | //); | |
214 | } | |
215 | ||
6a488035 | 216 | /** |
dc64d047 | 217 | * Download and install an extension. |
6a488035 | 218 | * |
cf470720 TO |
219 | * @param array $params |
220 | * Input parameters. | |
244bbdd8 CW |
221 | * - key: string, eg "com.example.myextension" |
222 | * - url: string eg "http://repo.com/myextension-1.0.zip" | |
6a488035 | 223 | * |
77b97be7 | 224 | * @throws API_Exception |
a6c01b45 | 225 | * @return array |
72b3a70c | 226 | * API result |
6a488035 TO |
227 | */ |
228 | function civicrm_api3_extension_download($params) { | |
6c552737 TO |
229 | if (!array_key_exists('url', $params)) { |
230 | if (!CRM_Extension_System::singleton()->getBrowser()->isEnabled()) { | |
e5f24f02 | 231 | throw new API_Exception('Automatic downloading is disabled. Try adding parameter "url"'); |
6a488035 TO |
232 | } |
233 | if ($reqs = CRM_Extension_System::singleton()->getBrowser()->checkRequirements()) { | |
234 | $first = array_shift($reqs); | |
235 | throw new API_Exception($first['message']); | |
236 | } | |
237 | if ($info = CRM_Extension_System::singleton()->getBrowser()->getExtension($params['key'])) { | |
238 | if ($info->downloadUrl) { | |
239 | $params['url'] = $info->downloadUrl; | |
240 | } | |
241 | } | |
242 | } | |
243 | ||
6c552737 | 244 | if (!array_key_exists('url', $params)) { |
6a488035 TO |
245 | throw new API_Exception('Cannot resolve download url for extension. Try adding parameter "url"'); |
246 | } | |
247 | ||
248 | foreach (CRM_Extension_System::singleton()->getDownloader()->checkRequirements() as $requirement) { | |
249 | return civicrm_api3_create_error($requirement['message']); | |
250 | } | |
251 | ||
6c552737 | 252 | if (!CRM_Extension_System::singleton()->getDownloader()->download($params['key'], $params['url'])) { |
6a488035 TO |
253 | return civicrm_api3_create_error('Download failed - ZIP file is unavailable or malformed'); |
254 | } | |
255 | CRM_Extension_System::singleton()->getCache()->flush(); | |
256 | CRM_Extension_System::singleton(TRUE); | |
c62449ca TO |
257 | if (CRM_Utils_Array::value('install', $params, TRUE)) { |
258 | CRM_Extension_System::singleton()->getManager()->install(array($params['key'])); | |
259 | } | |
6a488035 TO |
260 | |
261 | return civicrm_api3_create_success(); | |
262 | } | |
263 | ||
e5f24f02 CW |
264 | /** |
265 | * Spec function for getfields | |
266 | * @param $fields | |
267 | */ | |
268 | function _civicrm_api3_extension_download_spec(&$fields) { | |
269 | $fields['key'] = array( | |
270 | 'title' => 'Extension Key', | |
271 | 'api.required' => 1, | |
272 | 'type' => CRM_Utils_Type::T_STRING, | |
273 | 'description' => 'Fully qualified name of the extension', | |
274 | ); | |
275 | $fields['url'] = array( | |
276 | 'title' => 'Download URL', | |
277 | 'type' => CRM_Utils_Type::T_STRING, | |
278 | 'description' => 'Optional as the system can determine the url automatically for public extensions', | |
279 | ); | |
c62449ca TO |
280 | $fields['install'] = array( |
281 | 'title' => 'Auto-install', | |
282 | 'type' => CRM_Utils_Type::T_STRING, | |
283 | 'description' => 'Automatically install the downloaded extension', | |
284 | 'api.default' => TRUE, | |
285 | ); | |
e5f24f02 CW |
286 | } |
287 | ||
6a488035 | 288 | /** |
dc64d047 | 289 | * Download and install an extension. |
6a488035 | 290 | * |
cf470720 TO |
291 | * @param array $params |
292 | * Input parameters. | |
244bbdd8 CW |
293 | * - local: bool, whether to rescan local filesystem (default: TRUE) |
294 | * - remote: bool, whether to rescan remote repository (default: TRUE) | |
6a488035 | 295 | * |
a6c01b45 | 296 | * @return array |
72b3a70c | 297 | * API result |
6a488035 TO |
298 | */ |
299 | function civicrm_api3_extension_refresh($params) { | |
6a488035 TO |
300 | $system = CRM_Extension_System::singleton(TRUE); |
301 | ||
302 | if ($params['local']) { | |
303 | $system->getManager()->refresh(); | |
304 | $system->getManager()->getStatuses(); // force immediate scan | |
305 | } | |
306 | ||
307 | if ($params['remote']) { | |
308 | if ($system->getBrowser()->isEnabled() && empty($system->getBrowser()->checkRequirements)) { | |
309 | $system->getBrowser()->refresh(); | |
310 | $system->getBrowser()->getExtensions(); // force immediate download | |
311 | } | |
312 | } | |
313 | ||
314 | return civicrm_api3_create_success(); | |
315 | } | |
316 | ||
e5f24f02 CW |
317 | /** |
318 | * Spec function for getfields | |
319 | * @param $fields | |
320 | */ | |
321 | function _civicrm_api3_extension_refresh_spec(&$fields) { | |
322 | $fields['local'] = array( | |
323 | 'title' => 'Rescan Local', | |
324 | 'api.default' => 1, | |
325 | 'type' => CRM_Utils_Type::T_BOOLEAN, | |
326 | 'description' => 'Whether to rescan the local filesystem (default TRUE)', | |
327 | ); | |
328 | $fields['remote'] = array( | |
329 | 'title' => 'Rescan Remote', | |
330 | 'api.default' => 1, | |
331 | 'type' => CRM_Utils_Type::T_BOOLEAN, | |
332 | 'description' => 'Whether to rescan the remote repository (default TRUE)', | |
333 | ); | |
334 | } | |
335 | ||
6a488035 | 336 | /** |
d1b0d05e | 337 | * Get a list of available extensions. |
6a488035 | 338 | * |
c490a46a | 339 | * @param array $params |
77b97be7 | 340 | * |
a6c01b45 | 341 | * @return array |
72b3a70c | 342 | * API result |
6a488035 TO |
343 | */ |
344 | function civicrm_api3_extension_get($params) { | |
df4848b8 TS |
345 | $full_names = _civicrm_api3_getKeys($params, 'full_name'); |
346 | $keys = _civicrm_api3_getKeys($params, 'key'); | |
347 | $keys = array_merge($full_names, $keys); | |
6a488035 | 348 | $statuses = CRM_Extension_System::singleton()->getManager()->getStatuses(); |
517dfba8 | 349 | $mapper = CRM_Extension_System::singleton()->getMapper(); |
6a488035 | 350 | $result = array(); |
c36fe5b0 | 351 | $id = 0; |
6a488035 | 352 | foreach ($statuses as $key => $status) { |
517dfba8 AS |
353 | try { |
354 | $obj = $mapper->keyToInfo($key); | |
355 | } | |
356 | catch (CRM_Extension_Exception $ex) { | |
357 | CRM_Core_Session::setStatus(ts('Failed to read extension (%1). Please refresh the extension list.', array(1 => $key))); | |
358 | continue; | |
359 | } | |
360 | $info = CRM_Extension_System::createExtendedInfo($obj); | |
c36fe5b0 | 361 | $info['id'] = $id++; // backward compatibility with indexing scheme |
df4848b8 | 362 | if (!empty($keys)) { |
d4c44c70 SL |
363 | if (in_array($key, $keys)) { |
364 | $result[] = $info; | |
365 | } | |
366 | } | |
367 | else { | |
368 | $result[] = $info; | |
369 | } | |
6a488035 | 370 | } |
c3733bf5 TO |
371 | |
372 | // These fields have been filtered already, and they have special semantics. | |
373 | unset($params['key']); | |
374 | unset($params['keys']); | |
375 | unset($params['full_name']); | |
376 | ||
377 | $filterableFields = array('id', 'type', 'status', 'path'); | |
1d470b75 | 378 | return _civicrm_api3_basic_array_get('Extension', $params, $result, 'id', $filterableFields); |
6a488035 TO |
379 | } |
380 | ||
c74a6c8f AS |
381 | /** |
382 | * Get a list of remotely available extensions. | |
383 | * | |
384 | * @param array $params | |
385 | * | |
386 | * @return array | |
387 | * API result | |
388 | */ | |
389 | function civicrm_api3_extension_getremote($params) { | |
390 | $extensions = CRM_Extension_System::singleton()->getBrowser()->getExtensions(); | |
391 | $result = array(); | |
392 | $id = 0; | |
393 | foreach ($extensions as $key => $obj) { | |
394 | $info = array(); | |
395 | $info['id'] = $id++; // backward compatibility with indexing scheme | |
396 | $info = array_merge($info, (array) $obj); | |
397 | $result[] = $info; | |
398 | } | |
399 | return _civicrm_api3_basic_array_get('Extension', $params, $result, 'id', CRM_Utils_Array::value('return', $params, array())); | |
400 | } | |
401 | ||
6a488035 | 402 | /** |
d1b0d05e | 403 | * Determine the list of extension keys. |
6a488035 | 404 | * |
cf470720 | 405 | * @param array $params |
df4848b8 | 406 | * @param string $key |
3b3f6d23 TO |
407 | * API request params with 'keys' or 'path'. |
408 | * - keys: A comma-delimited list of extension names | |
409 | * - path: An absolute directory path. May append '*' to match all sub-directories. | |
d1b0d05e | 410 | * |
a6c01b45 | 411 | * @return array |
6a488035 | 412 | */ |
82b474af | 413 | function _civicrm_api3_getKeys($params, $key = 'keys') { |
3b3f6d23 TO |
414 | if ($key == 'path') { |
415 | return CRM_Extension_System::singleton()->getMapper()->getKeysByPath($params['path']); | |
416 | } | |
83f51f6a TS |
417 | if (isset($params[$key])) { |
418 | if (is_array($params[$key])) { | |
419 | return $params[$key]; | |
420 | } | |
421 | if ($params[$key] == '') { | |
422 | return array(); | |
423 | } | |
424 | return explode(API_V3_EXTENSION_DELIMITER, $params[$key]); | |
6f59c19b | 425 | } |
97488fea JK |
426 | else { |
427 | return array(); | |
428 | } | |
6a488035 | 429 | } |