tripal_core.extensions.inc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. <?php
  2. function tripal_core_extensions_form($form, &$form_state = NULL) {
  3. // Get the RSS feed XML from the tripa.info website and save it to
  4. // a temp file so that we don't have to keep pulling the XML
  5. // everythime the page is loaded. If the temp file is older than 1 hours
  6. // then we'll pull it again. The number of seconds in an hour is 3600
  7. $tmp_file = sys_get_temp_dir() . '/tripal_rss_extensions.xml';
  8. if (!file_exists($tmp_file) or time() - filemtime($tmp_file) > 3600) {
  9. $content = file_get_contents("http://tripal.info/rss/extensions.xml");
  10. file_put_contents($tmp_file, $content);
  11. }
  12. else {
  13. $content = file_get_contents($tmp_file);
  14. }
  15. $xml = new SimpleXmlElement($content);
  16. $namespace = "http://tripal.info/rss/extensions/";
  17. $tab = array_key_exists('tab', $_GET) ? $_GET['tab'] : '';
  18. // Get any filters by categories.
  19. $filters = array();
  20. if (array_key_exists('values', $form_state)) {
  21. foreach ($form_state['values'] as $key => $value) {
  22. // Get the category to be filtered on.
  23. $matches = array();
  24. if (preg_match('/^categories-(.*?)$/', $key, $matches)) {
  25. if ($value == 'any') {
  26. continue;
  27. }
  28. $filters[$matches[1]] = $value;
  29. }
  30. }
  31. }
  32. // Parse the items into an array indexed by type and compatible versions.
  33. $extensions = array();
  34. $types = array();
  35. $type_ids = array();
  36. $categories = array();
  37. $cvs = array();
  38. $tvs = array();
  39. foreach ($xml->channel->item as $extension) {
  40. // Get the type of extension, convert that into a machine-readable name,
  41. // and build the array of types.
  42. $type = (string) $extension->category;
  43. $type_id = preg_replace('/[^\w]/','_', strtolower($type));
  44. $type_ids[$type] = $type_id;
  45. if (!in_array($type_id, $types)) {
  46. $types[$type] = 1;
  47. }
  48. // Get the categories list for this item.
  49. $cats = preg_split('/, /', (string) $extension->children($namespace)->categories);
  50. // Get the guid for this extension
  51. $guid = (string) $extension->guid;
  52. // In order to get fields in the 'tripal_extension' name space we must
  53. // pass in the $namespace to the children function. We first get the
  54. // Tripal versions, then the chado versions and organize the elements
  55. // accordintly.
  56. $tvs_temp = preg_split('/, /', (string) $extension->children($namespace)->tripal_version);
  57. foreach($tvs_temp as $tv) {
  58. $tvs[$tv] = 1;
  59. $cvs_temp = preg_split('/, /', (string) $extension->children($namespace)->chado_version);
  60. foreach($cvs_temp as $cv) {
  61. $cvs[$cv] = 1;
  62. // Keep track of the categories this item has been assigned.
  63. foreach ($cats as $cat) {
  64. $categories[$tv][$cv][$type][$cat] = 1;
  65. $categories['any'][$cv][$type][$cat] = 1;
  66. $categories[$tv]['any'][$type][$cat] = 1;
  67. $categories['any']['any'][$type][$cat] = 1;
  68. }
  69. // If there are filters then only include extensions that match the filters.
  70. if (array_key_exists($type_id, $filters) and !in_array($filters[$type_id], $cats)) {
  71. continue;
  72. }
  73. // Index the items by type, tripal version and chado version.
  74. $item = array();
  75. foreach ($extension->children() as $child) {
  76. $item[$child->getName()] = (string) $child;
  77. }
  78. foreach ($extension->children($namespace) as $child) {
  79. $item[$namespace][$child->getName()] = (string) $child;
  80. }
  81. $extensions[$tv][$cv][$type][$guid] = $item;
  82. $extensions['any'][$cv][$type][$guid] = $item;
  83. $extensions[$tv]['any'][$type][$guid] = $item;
  84. $extensions['any']['any'][$type][$guid] = $item;
  85. }
  86. }
  87. }
  88. // Convert the arrays from an associative array into a normal array, and sort.
  89. $types = array_keys($types);
  90. sort($types);
  91. $cvs = array_keys($cvs);
  92. sort($cvs);
  93. $tvs = array_keys($tvs);
  94. sort($tvs);
  95. // Get the Chado version and convert to the expected format
  96. $chado_version = chado_get_version(TRUE);
  97. $chado_version = preg_replace('/^(\d\.\d).*$/', "v$1x", $chado_version);
  98. $my_chado_version = $chado_version;
  99. // The default value can come from the pager links (thus via $_GET) or
  100. // via ajax call (thus via $form_state).
  101. if (array_key_exists('cv', $_GET)) {
  102. $chado_version = $_GET['cv'];
  103. }
  104. if (array_key_exists('values', $form_state) and array_key_exists('cv', $form_state['values'])) {
  105. $chado_version = $form_state['values']['cv'];
  106. }
  107. // Get the Tripal version. This is the version set in the tripal_core.info
  108. $info = system_get_info('module', 'tripal_core');
  109. $tripal_version = $info['version'];
  110. $tripal_version = preg_replace('/^.*?-(\d\.\d+).*$/', "v$1", $tripal_version);
  111. $my_tripal_version = $tripal_version;
  112. if (array_key_exists('tv', $_GET)) {
  113. $tripal_version = $_GET['tv'];
  114. }
  115. if (array_key_exists('values', $form_state) and array_key_exists('tv', $form_state['values'])) {
  116. $tripal_version = $form_state['values']['tv'];
  117. }
  118. // Add the instructions.
  119. $form['instructions'] = array(
  120. '#type' => 'item',
  121. '#markup' => t('This page will help you find extensions that are available
  122. for Tripal. Select an extension type from the vertical tabs. The content
  123. of this page is constructed from an RSS feed provided by tripal.info.
  124. There may be no content if the tripal.info site is unavailable. The RSS
  125. feed will be cached for one hour.')
  126. );
  127. // Add the filters fieldset.
  128. $form['filters'] = array(
  129. '#type' => 'fieldset',
  130. '#title' => 'Filters',
  131. '#description' => t('You can filter which extensions are visible by
  132. changing the Tripal ahd Chado versions. By default only those
  133. extensions that are compatible with the currently installed Tripal
  134. and Chado verions are shown.'),
  135. '#collapsible' => TRUE,
  136. '#collapsed' => TRUE,
  137. );
  138. $summary_message = 'Currently showing extensions compatible with ';
  139. if ($tripal_version != 'any' and $chado_version != 'any') {
  140. $summary_message .= "<strong>Tripal $tripal_version</strong> and <strong>Chado $chado_version</strong>.";
  141. }
  142. elseif ($tripal_version == 'any' and $chado_version != 'any') {
  143. $summary_message .= "<strong>any Tripal</strong> version and <strong>Chado $chado_version</strong>.";
  144. }
  145. elseif ($tripal_version != 'any' and $chado_version == 'any') {
  146. $summary_message .= "<strong>Tripal $tripal_version</strong> and <strong>any Chado</strong> version.";
  147. }
  148. elseif ($tripal_version == 'any' and $chado_version == 'any') {
  149. $summary_message .= "<strong>any Tripal</strong> version and <strong>any Chado</strong> version.";
  150. }
  151. $form['filter_summary'] = array(
  152. '#type' => 'item',
  153. '#markup' => $summary_message,
  154. );
  155. // Add the Tripal version select box.
  156. $options = array();
  157. $options['any'] = '--Any--';
  158. foreach ($tvs as $tv) {
  159. $options[$tv] = $tv;
  160. }
  161. $form['filters']['tv'] = array(
  162. '#type' => 'select',
  163. '#title' => 'Tripal',
  164. '#options' => $options,
  165. '#default_value' => $tripal_version,
  166. '#ajax' => array(
  167. 'callback' => "tripal_core_extensions_form_ajax_callback",
  168. 'wrapper' => 'tripal_core_extensions',
  169. 'effect' => 'fade',
  170. 'method' => 'replace',
  171. ),
  172. '#prefix' => '<div style="float: left;">',
  173. '#suffix' => '</div>'
  174. );
  175. // Add the Chado version select box.
  176. $options = array();
  177. $options['any'] = '--Any--';
  178. foreach ($cvs as $cv) {
  179. $options[$cv] = $cv;
  180. }
  181. $form['filters']['cv'] = array(
  182. '#type' => 'select',
  183. '#title' => 'Chado',
  184. '#options' => $options,
  185. '#default_value' => $chado_version,
  186. '#ajax' => array(
  187. 'callback' => "tripal_core_extensions_form_ajax_callback",
  188. 'wrapper' => 'tripal_core_extensions',
  189. 'effect' => 'fade',
  190. 'method' => 'replace',
  191. ),
  192. '#prefix' => '<div style="float: left; padding-left: 10px">',
  193. '#suffix' => '</div>'
  194. );
  195. // Add the vertical tabs
  196. $form['extensions'] = array(
  197. '#type' => 'vertical_tabs',
  198. '#default_tab' => $tab,
  199. );
  200. // Add the fieldsets for each type
  201. foreach ($types as $type) {
  202. $form[$type] = array(
  203. '#id' => $type_ids[$type],
  204. '#type' => 'fieldset',
  205. '#title' => $type . 's',
  206. '#collapsed' => TRUE,
  207. '#collapsible' => TRUE,
  208. '#group' => 'extensions',
  209. );
  210. }
  211. // Iterate through all of the extensions and add them to the form.
  212. tripal_core_extension_form_add_extensions($form, $form_state,
  213. $extensions[$tripal_version][$chado_version], $categories, $tripal_version,
  214. $chado_version, $my_tripal_version, $my_chado_version, $type_ids,
  215. $namespace, $filters);
  216. foreach ($types as $type) {
  217. if (count(element_children($form[$type])) == 0) {
  218. $form[$type]['empty'] = array(
  219. '#type' => 'item',
  220. '#markup' => '<strong>There are no matching ' . strtolower($type) . '(s).</strong>',
  221. );
  222. }
  223. }
  224. $form['#prefix'] = '<div id="tripal_core_extensions">';
  225. $form['#suffix'] = '</div>';
  226. $form['#submit'][] = 'tripal_core_extensions_form_submit';
  227. return $form;
  228. }
  229. /**
  230. * Adds each extension to the form.
  231. *
  232. * This function exits to simplify the the tripal_core_extension_form()
  233. * function.
  234. */
  235. function tripal_core_extension_form_add_extensions(&$form, $form_state, $extensions,
  236. $categories, $tripal_version, $chado_version, $my_tripal_version,
  237. $my_chado_version, $type_ids, $namespace, $filters) {
  238. // Iterate through the extensions. We will add a pager for
  239. // each type of extension, and display only those that should appear
  240. // on the page.
  241. $type_index = 0;
  242. foreach ($extensions as $type => $extensions) {
  243. $total_items = count($extensions);
  244. // Indicate how many matching extensions were found
  245. $form[$type]['total_found'] = array(
  246. '#type' => 'item',
  247. '#markup' => '<strong>Found ' . $total_items . ' matching ' . strtolower($type) . '(s)</strong>',
  248. );
  249. // Add the category select box;
  250. $cats = array_keys($categories[$tripal_version][$chado_version][$type]);
  251. sort($cats);
  252. $options = array();
  253. $options['any'] = '--Any--';
  254. foreach ($cats as $cat) {
  255. $options[$cat] = $cat;
  256. }
  257. // The default value can come from the pager links (thus via $_GET) or
  258. // via ajax call (thus via $form_state).
  259. $default_filter = '';
  260. if (array_key_exists('categories-' . $type_ids[$type], $_GET)) {
  261. $default_filter = $_GET['categories-' . $type_ids[$type]];
  262. }
  263. if (array_key_exists('values', $form_state) and array_key_exists('categories-' . $type_ids[$type], $form_state['values'])) {
  264. $default_filter = $form_state['values']['categories-' . $type_ids[$type]];
  265. }
  266. $form[$type]['filters']['categories-' . $type_ids[$type]] = array(
  267. '#type' => 'select',
  268. '#title' => 'Filter by Category',
  269. '#options' => $options,
  270. '#default_value' => $default_filter,
  271. '#ajax' => array(
  272. 'callback' => "tripal_core_extensions_form_ajax_callback",
  273. 'wrapper' => 'tripal_core_extensions',
  274. 'effect' => 'fade',
  275. 'method' => 'replace',
  276. ),
  277. );
  278. // Initialize pager and gets current page
  279. $num_per_page = 5;
  280. $page = pager_default_initialize($total_items, $num_per_page, $type_index);
  281. // Gets first record and last record to show
  282. $start = ($page) * $num_per_page;
  283. $end = ($start + $num_per_page < $total_items)? $start + $num_per_page : $total_items;
  284. // Iterate through each of the elements and add them to the form if
  285. // they are within the page
  286. $extension_index = 0;
  287. foreach ($extensions as $guid => $extension) {
  288. // Skip items that aren't on our current page.
  289. if ($extension_index < $start or $extension_index >= $end) {
  290. $extension_index++;
  291. continue;
  292. }
  293. // If this is an extension module then there will be a home page for it
  294. $home_page = '';
  295. if (array_key_exists('home_page', $extension[$namespace])) {
  296. $home_page = "<strong>Project Home: </strong>" . $extension[$namespace]['home_page'] . "</br>";
  297. }
  298. // Determine if this extension is compatible with this site.
  299. $incompatible = '';
  300. $tvs_temp = preg_split('/, /', $extension[$namespace]['tripal_version']);
  301. $cvs_temp = preg_split('/, /', $extension[$namespace]['chado_version']);
  302. if (!in_array($my_tripal_version, $tvs_temp)) {
  303. $incompatible .= "<li>This extensions is not compatible with this version of Tripal.</li>";
  304. }
  305. if (!in_array($my_chado_version, $cvs_temp)) {
  306. $incompatible .= "<li>This extensions is not compatible with the installed Chado version.</li>";
  307. }
  308. $incompatible = t($incompatible);
  309. // Determine if this extension is already installed.
  310. $is_installed = '';
  311. switch ($type) {
  312. case 'Bulk Loader Template':
  313. $blk_id = db_select('tripal_bulk_loader_template' ,'tblt')
  314. ->fields('tblt', array('template_id'))
  315. ->condition('name', $extension['title'])
  316. ->execute()
  317. ->fetchField();
  318. if ($blk_id) {
  319. $is_installed = '<li>A bulk loader tempalte with this name is already installed.</li>';
  320. }
  321. break;
  322. case 'Materialized View':
  323. $mview_id = tripal_get_mview_id($extension[$namespace]['mview_name']);
  324. if ($mview_id) {
  325. $is_installed = '<li>A materialized view with this name is already installed.</li>';
  326. }
  327. break;
  328. case 'Extension Module':
  329. if (module_exists($extension[$namespace]['module_name'])) {
  330. $is_installed = '<li>A module with this name is already installed.</li>';
  331. }
  332. break;
  333. default:
  334. break;
  335. }
  336. $is_installed = t($is_installed);
  337. // Does this module appear to be available on Drupal.org?
  338. $project = '';
  339. if ($type == 'Extension Module') {
  340. // Does it have a drupal project name?
  341. if (!array_key_exists('drupal_project', $extension[$namespace])) {
  342. // Since it doesn't have a drupal project name is it in a sandbox?
  343. if (!preg_match('/www.drupal.org\/sandbox/', $extension[$namespace]['home_page'])) {
  344. $project = t("<li>This module does not appear to be available as a " .
  345. "full Drupal project or within a Drupal sandbox and thus cannot ".
  346. "be downloaded here. You may have to manually download it.</li>");
  347. }
  348. else {
  349. $project = ("<li>This module is still in a Sandbox on Drupal.org, and
  350. cannot be downloaded from here. You will have to manually download
  351. this module.</li>");
  352. }
  353. }
  354. }
  355. // Make sure the bulk loader module is installed, or we cannot provide
  356. // the bulk loader import button.
  357. $other = '';
  358. if ($type == 'Bulk Loader Template' and !module_exists('tripal_bulk_loader')) {
  359. $other = t('<li>The bulk loader
  360. module is not enabled. If you would like to import a loading template
  361. please enable it.</li>');
  362. }
  363. // If the user click's the button to import the extension then we
  364. // need the item in the submit function so we can process the import.
  365. $form[$type]['extension-' . $guid] = array(
  366. '#type' => 'value',
  367. '#value' => $extension,
  368. );
  369. $warnings = '';
  370. if ($incompatible or $is_installed or $project or $other) {
  371. $warnings = '<div class="messages warning"><ul>' .
  372. $incompatible . ' ' .
  373. $is_installed . ' ' .
  374. $project . ' ' .
  375. $other . '</ul></div>';
  376. }
  377. // Create the form elements that we'll later theme into tables.
  378. $form[$type][$guid]['header'] = array(
  379. '#markup' => l($extension['title'], $extension['link']),
  380. );
  381. $form[$type][$guid]['details'] = array(
  382. '#markup' => "" .
  383. "<strong>Type:</strong> " . $type . "</br>" .
  384. "<strong>Categories: </strong>" . $extension[$namespace]['categories'] . "</br>" .
  385. "<strong>Authors: </strong>" . $extension[$namespace]['authors'] . "</br>" .
  386. "<strong>Chado compatible versions: </strong>" . $extension[$namespace]['chado_version'] . "</br>" .
  387. "<strong>Tripal compatible versions: </strong>" . $extension[$namespace]['tripal_version'] . "</br>" .
  388. $home_page .
  389. "<strong>tripal.info Page: </strong>" . l($extension['link'], $extension['link']) . "</br>" .
  390. $warnings .
  391. "<p>" . $extension['description'] . "</p>",
  392. );
  393. // Add an import button to each of types that can support import.
  394. switch ($type) {
  395. case 'Bulk Loader Template':
  396. if (!$incompatible and !$is_installed and !$project) {
  397. $form[$type][$guid]['import'] = array(
  398. '#type' => 'submit',
  399. '#value' => "Import Loader",
  400. '#name' => "import-" . $guid,
  401. );
  402. }
  403. break;
  404. case 'Materialized View':
  405. if (!$incompatible and !$is_installed and !$project) {
  406. $form[$type][$guid]['import'] = array(
  407. '#type' => 'submit',
  408. '#value' => "Import MView",
  409. '#name' => "import-" . $guid,
  410. );
  411. }
  412. break;
  413. case 'Extension Module':
  414. if (!$incompatible and !$is_installed and !$project) {
  415. $form[$type][$guid]['import'] = array(
  416. '#type' => 'submit',
  417. '#value' => "Download Module",
  418. '#name' => "import-" . $guid,
  419. );
  420. }
  421. break;
  422. default:
  423. break;
  424. }
  425. $form[$type][$guid]['#theme'] = 'tripal_core_extensions_form_tables';
  426. $extension_index++;
  427. }
  428. // Now create and theme the pager.
  429. $pager = array(
  430. 'tags' => array(),
  431. 'element' => $type_index,
  432. 'parameters' => array(
  433. 'tab' => $type_ids[$type],
  434. 'cv' => $chado_version,
  435. 'tv' => $tripal_version,
  436. ),
  437. 'quantity' => $num_per_page,
  438. );
  439. // now add the category filters to the params array
  440. foreach ($filters as $filter_id => $value) {
  441. $pager['parameters']['categories-' . $filter_id] = $value;
  442. }
  443. // because this may be an ajax callback, the theme_pager will set the URL to be
  444. // "system/ajax", so we need to reset that
  445. $pager = theme('pager', $pager);
  446. global $base_path;
  447. $pager = str_replace($base_path . "system/ajax", "", $pager) ;
  448. $form[$type]['pager'] = array(
  449. '#type' => 'item',
  450. '#markup' => $pager,
  451. );
  452. $type_index++;
  453. }
  454. }
  455. /**
  456. * Process the import buttons.
  457. *
  458. * @param $form
  459. * @param $form_state
  460. */
  461. function tripal_core_extensions_form_submit($form, &$form_state) {
  462. // get the guid
  463. $clicked_button = $form_state['clicked_button']['#name'];
  464. $guid = preg_replace('/^import-(\d+)$/', "$1", $clicked_button);
  465. if ($guid) {
  466. $namespace = "http://tripal.info/rss/extensions/";
  467. $extension = $form_state['values']['extension-' . $guid];
  468. $type = $extension['category'];
  469. switch ($type) {
  470. case 'Bulk Loader Template':
  471. // TODO: we need an API function for adding a bulk loader
  472. $id = db_insert('tripal_bulk_loader_template')
  473. ->fields(array(
  474. 'name' => $extension['title'],
  475. 'template_array' => $extension[$namespace]['bulkldr_export'],
  476. 'created' => time(),
  477. 'changed' => time()
  478. ))
  479. ->execute();
  480. if (!$id) {
  481. drupal_set_message("Cannot import this bulk loader. Please view the 'Recent log messages' report for more details.", 'error');
  482. }
  483. else {
  484. drupal_set_message("Bulk loader succesfully added.");
  485. }
  486. break;
  487. case 'Materialized View':
  488. $module_name = 'tripal_core';
  489. $mview_name = $extension[$namespace]['mview_name'];
  490. $mview_schema = $extension[$namespace]['mview_schema'];
  491. $mview_sql = $extension[$namespace]['mview_sql'];
  492. // Validate the contents of the schema array.
  493. // TODO: security issue!! Before using 'eval' on this string
  494. // we should make sure the array is valid and there is no hidden
  495. // PHP code.
  496. $schema_array = array();
  497. $success = eval("\$schema_array = $mview_schema;");
  498. $error = chado_validate_custom_table_schema($schema_array);
  499. if ($error) {
  500. drupal_set_message("Cannot import Materialized View: $error", "error");
  501. }
  502. tripal_add_mview($mview_name, $module_name, $schema_array, $mview_sql);
  503. break;
  504. case 'Extension Module':
  505. if (array_key_exists('drupal_project', $extension[$namespace])) {
  506. module_load_include('module', 'update', 'update');
  507. module_load_include('inc', 'update', 'update.manager');
  508. $project = $extension[$namespace]['drupal_project'];
  509. $tar = tripal_core_extensions_get_latest_module_version($project);
  510. if (!$tar) {
  511. drupal_set_message('Cannot find a suitable release of this module
  512. for download. You may need to manually install this module.', 'error');
  513. }
  514. else {
  515. // Download the file from the Drupal repository
  516. $local_cache = update_manager_file_get($tar);
  517. if (!$local_cache) {
  518. drupal_set_message('Cannot download the file. Check the
  519. "Recent log messages" for relavent errors.', 'error');
  520. }
  521. else {
  522. // The following code was borrowed from the update_manager_install_form_submit()
  523. // of drupal in the modules/update/update.manager.inc file.
  524. $directory = _update_manager_extract_directory();
  525. try {
  526. $archive = update_manager_archive_extract($local_cache, $directory);
  527. }
  528. catch (Exception $e) {
  529. drupal_set_message('Cannot extract the file. Please check
  530. permissions in the modules directory', 'error');
  531. return;
  532. }
  533. $archive_errors = update_manager_archive_verify($project, $local_cache, $directory);
  534. if (!empty($archive_errors)) {
  535. foreach ($archive_errors as $error) {
  536. drupal_set_message($error, 'error');
  537. }
  538. }
  539. $project_location = $directory . '/' . $project;
  540. try {
  541. $updater = Updater::factory($project_location);
  542. }
  543. catch (Exception $e) {
  544. drupal_set_message($e->getMessage(), 'error');
  545. return;
  546. }
  547. $project_real_location = drupal_realpath($project_location);
  548. $arguments = array(
  549. 'project' => $project,
  550. 'updater_name' => get_class($updater),
  551. 'local_url' => $project_real_location,
  552. );
  553. module_load_include('inc', 'update', 'update.authorize');
  554. $filetransfer = new FileTransferLocal(DRUPAL_ROOT);
  555. call_user_func_array('update_authorize_run_install', array_merge(array($filetransfer), $arguments));
  556. drupal_set_message('It appears the module was downloaded and
  557. extracted. You can now ' . l('enable this module'. 'admin/modules') . '.');
  558. }
  559. }
  560. }
  561. else {
  562. drupal_set_message('Cannot download this module. The Drpual project
  563. name is not set. You may have to manually download this module, and
  564. if possible encourage the developers to set the project name if it
  565. has been fully published on Drupal.org already.', 'error');
  566. }
  567. break;
  568. default:
  569. break;
  570. }
  571. }
  572. }
  573. /**
  574. * The theme function for rendering each element's table.
  575. *
  576. * @param $variables
  577. */
  578. function theme_tripal_core_extensions_form_tables($variables) {
  579. $element = $variables['element'];
  580. $headers = array(
  581. array(
  582. 'data' => drupal_render($element['header']),
  583. 'colspan' => 2,
  584. )
  585. );
  586. $button = array_key_exists('import', $element) ? drupal_render($element['import']) : '&nbsp;';
  587. $rows = array(
  588. array(
  589. array(
  590. 'data' => drupal_render($element['details']),
  591. ),
  592. array(
  593. 'data' => $button,
  594. 'width' => '5%',
  595. 'align' => 'right',
  596. ),
  597. ),
  598. );
  599. $table = array(
  600. 'header' => $headers,
  601. 'rows' => $rows,
  602. 'attributes' => array(),
  603. 'sticky' => FALSE,
  604. 'caption' => '',
  605. 'colgroups' => array(),
  606. 'empty' => '',
  607. );
  608. return theme_table($table);
  609. }
  610. /**
  611. * A callback function for the form
  612. *
  613. * @return unknown
  614. */
  615. function tripal_core_extensions_form_ajax_callback($form, $form_state) {
  616. // This function need not do anything as the form will take care of
  617. // updates needed. We just need to return the form.
  618. return $form;
  619. }
  620. /**
  621. * Determines the most recent downloadable package for a module.
  622. *
  623. * This function will connect to Drupal.org's RSS feed for a project and
  624. * determine the most recent version of the module and return the URL
  625. * for it's package.
  626. *
  627. * @param $project
  628. */
  629. function tripal_core_extensions_get_latest_module_version($project_name) {
  630. // First use the Drupal RESTful API to get the project
  631. $url = "https://www.drupal.org/api-d7/node.json?type=project_module&field_project_machine_name=$project_name";
  632. $result = json_decode(file_get_contents($url), TRUE);
  633. $project = $result['list'][0];
  634. $nid = $project['nid'];
  635. // Second get the releases for this node and find releases for this Drupal
  636. $url = "https://www.drupal.org/api-d7/node.json?type=project_release&field_release_project=$nid";
  637. $result = json_decode(file_get_contents($url), TRUE);
  638. $releases = $result['list'];
  639. $drupal_version = VERSION;
  640. $drupal_major = preg_replace('/^(\d+)\.\d+$/', "$1", $drupal_version);
  641. $best_release = NULL;
  642. foreach ($releases as $release) {
  643. // This release must match the Drupal major version or it won't
  644. // be compatiable. If it doesn't we'll skip it.
  645. $release_version = $release['field_release_version'];
  646. $release_drupal = preg_replace('/^(\d+)\.x-.*$/', "$1", $release_version);
  647. if ($release_drupal != $drupal_major) {
  648. continue;
  649. }
  650. // Set the current release to be the best one. On successive iterations
  651. // we'll check to see if that is still true.
  652. if ($best_release == NULL) {
  653. $best_release = $release;
  654. continue;
  655. }
  656. if ($release['field_release_version_major'] > $best_release['field_release_version_major']) {
  657. $best_release = $release;
  658. continue;
  659. }
  660. if ($release['field_release_version_patch'] > $best_release['field_release_version_patch']) {
  661. $best_release = $release;
  662. continue;
  663. }
  664. // If the best version has no extra part then let's keep it as this is the
  665. // most stable release.
  666. if (!$best_release['field_release_version_extra']) {
  667. continue;
  668. }
  669. // Convert the 'extra' part to a numeric value that will let us compare
  670. // the ranks of the release versions.
  671. $extra_rank = array(
  672. 'unstable' => 1,
  673. 'alpha' => 2,
  674. 'beta' => 3,
  675. 'rc' => 4,
  676. );
  677. $matches = array();
  678. $this_extra = 0;
  679. if (preg_match('/^(.*?)(\d+)$/', $release['field_release_version_extra'], $matches)) {
  680. $this_extra = $extra_rank[$matches[1]] . "." . $matches[2];
  681. }
  682. $best_extra = 0;
  683. if (preg_match('/^(.*?)(\d+)$/', $best_release['field_release_version_extra'], $matches)) {
  684. $best_extra = $extra_rank[$matches[1]] . "." . $matches[2];
  685. }
  686. if ($this_extra > $best_extra) {
  687. $best_release = $release;
  688. continue;
  689. }
  690. }
  691. // If we have a best result then build the download string.
  692. // TODO: we may need to make another web services call to get the actual
  693. // download path, but for now we'll hard code the construction of it.
  694. if ($best_release) {
  695. return 'http://ftp.drupal.org/files/projects/' . $project_name . '-' . $best_release['field_release_version'] . '.tar.gz';
  696. }
  697. return '';
  698. }