feeds.pages.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <?php
  2. /**
  3. * @file
  4. * Menu callbacks, form callbacks and helpers.
  5. */
  6. /**
  7. * Render a page of available importers.
  8. */
  9. function feeds_page() {
  10. $rows = array();
  11. if ($importers = feeds_importer_load_all()) {
  12. foreach ($importers as $importer) {
  13. if ($importer->disabled) {
  14. continue;
  15. }
  16. if (!(user_access('import ' . $importer->id . ' feeds') || user_access('administer feeds'))) {
  17. continue;
  18. }
  19. if (empty($importer->config['content_type'])) {
  20. $link = 'import/' . $importer->id;
  21. $title = $importer->config['name'];
  22. }
  23. elseif (node_access('create', $importer->config['content_type'])) {
  24. $link = 'node/add/' . str_replace('_', '-', $importer->config['content_type']);
  25. $title = node_type_get_name($importer->config['content_type']);
  26. }
  27. else {
  28. continue;
  29. }
  30. $rows[] = array(
  31. l($title, $link),
  32. check_plain($importer->config['description']),
  33. );
  34. }
  35. }
  36. if (empty($rows)) {
  37. // The feeds_ui module is enabled.
  38. if (module_exists('feeds_ui') && user_access('administer feeds')) {
  39. drupal_set_message(t('There are no importers, go to <a href="@importers">Feed importers</a> to create one or enable an existing one.', array('@importers' => url('admin/structure/feeds'))));
  40. }
  41. else {
  42. // The feeds_ui module is not enabled but the current user has access to
  43. // Modules to enable it.
  44. if (user_access('administer modules')) {
  45. drupal_set_message(t('The Feeds UI Admin module is not enabled and there are no importers, go to <a href="@modules">Modules</a> and enable Feeds Admin UI. Then go to <a href="@importers">Feed importers</a> to create one or enable an existing one.', array('@modules' => url('admin/modules'), '@importers' => url('admin/structure/feeds'))));
  46. }
  47. else {
  48. // The feeds_ui module is not enabled and the current user cannot
  49. // enable it.
  50. drupal_set_message(t("The Feeds UI Admin module is not enabled. Please contact the Administrator for your site and ask them to enable it."));
  51. }
  52. }
  53. }
  54. $header = array(
  55. t('Import'),
  56. t('Description'),
  57. );
  58. return theme('table', array('header' => $header, 'rows' => $rows));
  59. }
  60. /**
  61. * Render a feeds import form on import/[config] pages.
  62. */
  63. function feeds_import_form(array $form, array &$form_state, FeedsImporter $importer) {
  64. $source = feeds_source($importer->id);
  65. $form['#importer_id'] = $importer->id;
  66. // @todo Move this into fetcher?
  67. $form['#attributes']['enctype'] = 'multipart/form-data';
  68. $form['source_status'] = array(
  69. '#type' => 'fieldset',
  70. '#title' => t('Status'),
  71. '#tree' => TRUE,
  72. '#value' => feeds_source_status($source),
  73. );
  74. $source_form = $source->configForm($form_state);
  75. if (!empty($source_form)) {
  76. $form['feeds'] = array(
  77. '#type' => 'fieldset',
  78. '#title' => t('Import'),
  79. '#tree' => TRUE,
  80. ) + $source_form;
  81. }
  82. $form['submit'] = array(
  83. '#type' => 'submit',
  84. '#value' => t('Import'),
  85. );
  86. $progress = $source->progressImporting();
  87. if ($progress !== FEEDS_BATCH_COMPLETE) {
  88. $form['submit']['#disabled'] = TRUE;
  89. $form['submit']['#value'] =
  90. t('Importing (@progress %)', array('@progress' => number_format(100 * $progress, 0)));
  91. }
  92. return $form;
  93. }
  94. /**
  95. * Validation handler for node forms and feeds_import_form().
  96. */
  97. function feeds_import_form_validate($form, &$form_state) {
  98. // @todo This may be a problem here, as we don't have a feed_nid at this point.
  99. feeds_source($form['#importer_id'])->configFormValidate($form_state['values']['feeds']);
  100. }
  101. /**
  102. * Submit handler for feeds_import_form().
  103. */
  104. function feeds_import_form_submit($form, &$form_state) {
  105. // Save source and import.
  106. $source = feeds_source($form['#importer_id']);
  107. if (!empty($form_state['values']['feeds']) && is_array($form_state['values']['feeds'])) {
  108. $source->addConfig($form_state['values']['feeds']);
  109. $source->save();
  110. }
  111. // Refresh feed if import on create is selected.
  112. if ($source->importer->config['import_on_create']) {
  113. $source->startImport();
  114. }
  115. // Add to schedule, make sure importer is scheduled, too.
  116. $source->schedule();
  117. }
  118. /**
  119. * Render a feeds import form on node/id/import pages.
  120. */
  121. function feeds_import_tab_form($form, &$form_state, $node) {
  122. $importer_id = feeds_get_importer_id($node->type);
  123. $source = feeds_source($importer_id, $node->nid);
  124. $form = array();
  125. $form['#feed_nid'] = $node->nid;
  126. $form['#importer_id'] = $importer_id;
  127. $form['#redirect'] = 'node/' . $node->nid;
  128. $form['source_status'] = array(
  129. '#type' => 'fieldset',
  130. '#title' => t('Status'),
  131. '#tree' => TRUE,
  132. '#value' => feeds_source_status($source),
  133. );
  134. $form = confirm_form($form, t('Import all content from source?'), 'node/' . $node->nid, '', t('Import'), t('Cancel'), 'confirm feeds update');
  135. $progress = $source->progressImporting();
  136. if ($progress !== FEEDS_BATCH_COMPLETE) {
  137. $form['actions']['submit']['#disabled'] = TRUE;
  138. $form['actions']['submit']['#value'] =
  139. t('Importing (@progress %)', array('@progress' => number_format(100 * $progress, 0)));
  140. }
  141. return $form;
  142. }
  143. /**
  144. * Submit handler for feeds_import_tab_form().
  145. */
  146. function feeds_import_tab_form_submit($form, &$form_state) {
  147. $form_state['redirect'] = $form['#redirect'];
  148. feeds_source($form['#importer_id'], $form['#feed_nid'])->startImport();
  149. }
  150. /**
  151. * Render a feeds delete form.
  152. *
  153. * Used on both node pages and configuration pages.
  154. * Therefore $node may be missing.
  155. */
  156. function feeds_delete_tab_form(array $form, array &$form_state, FeedsImporter $importer = NULL, $node = NULL) {
  157. if (empty($node)) {
  158. $source = feeds_source($importer->id);
  159. $form['#redirect'] = 'import/' . $source->id;
  160. }
  161. else {
  162. $importer_id = feeds_get_importer_id($node->type);
  163. $source = feeds_source($importer_id, $node->nid);
  164. $form['#redirect'] = 'node/' . $source->feed_nid;
  165. }
  166. // Form cannot pass on source object.
  167. $form['#importer_id'] = $source->id;
  168. $form['#feed_nid'] = $source->feed_nid;
  169. $form['source_status'] = array(
  170. '#type' => 'fieldset',
  171. '#title' => t('Status'),
  172. '#tree' => TRUE,
  173. '#value' => feeds_source_status($source),
  174. );
  175. $form = confirm_form($form, t('Delete all items from source?'), $form['#redirect'], '', t('Delete'), t('Cancel'), 'confirm feeds update');
  176. $progress = $source->progressClearing();
  177. if ($progress !== FEEDS_BATCH_COMPLETE) {
  178. $form['actions']['submit']['#disabled'] = TRUE;
  179. $form['actions']['submit']['#value'] =
  180. t('Deleting (@progress %)', array('@progress' => number_format(100 * $progress, 0)));
  181. }
  182. return $form;
  183. }
  184. /**
  185. * Submit handler for feeds_delete_tab_form().
  186. */
  187. function feeds_delete_tab_form_submit($form, &$form_state) {
  188. $form_state['redirect'] = $form['#redirect'];
  189. $feed_nid = empty($form['#feed_nid']) ? 0 : $form['#feed_nid'];
  190. feeds_source($form['#importer_id'], $feed_nid)->startClear();
  191. }
  192. /**
  193. * Render a feeds unlock form.
  194. *
  195. * Used on both node pages and configuration pages.
  196. * Therefore $node may be missing.
  197. */
  198. function feeds_unlock_tab_form($form, &$form_state, FeedsImporter $importer = NULL, $node = NULL) {
  199. if (empty($node)) {
  200. $source = feeds_source($importer->id);
  201. $form['#redirect'] = 'import/' . $source->id;
  202. }
  203. else {
  204. $importer_id = feeds_get_importer_id($node->type);
  205. $source = feeds_source($importer_id, $node->nid);
  206. $form['#redirect'] = 'node/' . $source->feed_nid;
  207. }
  208. // Form cannot pass on source object.
  209. $form['#importer_id'] = $source->id;
  210. $form['#feed_nid'] = $source->feed_nid;
  211. $form['source_status'] = array(
  212. '#type' => 'fieldset',
  213. '#title' => t('Status'),
  214. '#tree' => TRUE,
  215. '#value' => feeds_source_status($source),
  216. );
  217. $form = confirm_form($form, t('Unlock this importer?'), $form['#redirect'], '', t('Delete'), t('Cancel'), 'confirm feeds update');
  218. if ($source->progressImporting() == FEEDS_BATCH_COMPLETE && $source->progressClearing() == FEEDS_BATCH_COMPLETE) {
  219. $form['source_locked'] = array(
  220. '#type' => 'markup',
  221. '#title' => t('Not Locked'),
  222. '#tree' => TRUE,
  223. '#markup' => t('This importer is not locked, therefore it cannot be unlocked.'),
  224. );
  225. $form['actions']['submit']['#disabled'] = TRUE;
  226. $form['actions']['submit']['#value'] = t('Unlock (disabled)');
  227. }
  228. else {
  229. $form['actions']['submit']['#value'] = t('Unlock');
  230. }
  231. return $form;
  232. }
  233. /**
  234. * Form submit handler. Resets all feeds state.
  235. */
  236. function feeds_unlock_tab_form_submit($form, &$form_state) {
  237. drupal_set_message(t('Import Unlocked'));
  238. $form_state['redirect'] = $form['#redirect'];
  239. $feed_nid = empty($form['#feed_nid']) ? 0 : $form['#feed_nid'];
  240. $importer_id = $form['#importer_id'];
  241. //Is there a more API-friendly way to set the state?
  242. db_update('feeds_source')
  243. ->condition('id', $importer_id)
  244. ->condition('feed_nid', $feed_nid)
  245. ->fields(array('state' => FALSE))
  246. ->execute();
  247. }
  248. /**
  249. * Handle a fetcher callback.
  250. */
  251. function feeds_fetcher_callback($importer, $feed_nid = 0) {
  252. if ($importer instanceof FeedsImporter) {
  253. try {
  254. return $importer->fetcher->request($feed_nid);
  255. }
  256. catch (Exception $e) {
  257. // Do nothing.
  258. }
  259. }
  260. drupal_access_denied();
  261. }
  262. /**
  263. * Template generation
  264. */
  265. function feeds_importer_template(FeedsImporter $importer) {
  266. if ($importer->parser instanceof FeedsCSVParser) {
  267. return $importer->parser->getTemplate();
  268. }
  269. return drupal_not_found();
  270. }
  271. /**
  272. * Renders a status display for a source.
  273. */
  274. function feeds_source_status($source) {
  275. $progress_importing = $source->progressImporting();
  276. $v = array();
  277. if ($progress_importing != FEEDS_BATCH_COMPLETE) {
  278. $v['progress_importing'] = $progress_importing;
  279. }
  280. $progress_clearing = $source->progressClearing();
  281. if ($progress_clearing != FEEDS_BATCH_COMPLETE) {
  282. $v['progress_clearing'] = $progress_clearing;
  283. }
  284. $v['imported'] = $source->imported;
  285. $v['count'] = $source->itemCount();
  286. if (!empty($v)) {
  287. return theme('feeds_source_status', $v);
  288. }
  289. }
  290. /**
  291. * Themes a status display for a source.
  292. */
  293. function theme_feeds_source_status($v) {
  294. $output = '<div class="info-box feeds-source-status">';
  295. $items = array();
  296. if ($v['progress_importing']) {
  297. $progress = number_format(100.0 * $v['progress_importing'], 0);
  298. $items[] = t('Importing - @progress % complete.', array('@progress' => $progress));
  299. }
  300. if ($v['progress_clearing']) {
  301. $progress = number_format(100.0 * $v['progress_clearing'], 0);
  302. $items[] = t('Deleting items - @progress % complete.', array('@progress' => $progress));
  303. }
  304. if (!count($items)) {
  305. if ($v['count']) {
  306. if ($v['imported']) {
  307. $items[] = t('Last import: @ago ago.', array('@ago' => format_interval(REQUEST_TIME - $v['imported'], 1)));
  308. }
  309. $items[] = t('@count imported items total.', array('@count' => $v['count']));
  310. }
  311. else {
  312. $items[] = t('No imported items.');
  313. }
  314. }
  315. $output .= theme('item_list', array('items' => $items));
  316. $output .= '</div>';
  317. return $output;
  318. }
  319. /**
  320. * Theme upload widget.
  321. */
  322. function theme_feeds_upload($variables) {
  323. $element = $variables['element'];
  324. drupal_add_css(drupal_get_path('module', 'feeds') . '/feeds.css');
  325. _form_set_class($element, array('form-file'));
  326. $summary = '';
  327. if (!empty($element['#file_info'])) {
  328. $file = $element['#file_info'];
  329. $wrapper = file_stream_wrapper_get_instance_by_uri($file->uri);
  330. $summary .= '<div class="feeds-file-info">';
  331. $summary .= '<div class="feeds-file-name">';
  332. if ($wrapper) {
  333. $summary .= l($file->filename, $wrapper->getExternalUrl());
  334. }
  335. else {
  336. $summary .= t('URI scheme %scheme not available.', array('%scheme' => file_uri_scheme($uri)));
  337. }
  338. $summary .= '</div>';
  339. $summary .= '<div class="file-size">';
  340. $summary .= format_size($file->filesize);
  341. $summary .= '</div>';
  342. $summary .= '<div class="feeds-file-mime">';
  343. $summary .= check_plain($file->filemime);
  344. $summary .= '</div>';
  345. $summary .= '</div>';
  346. }
  347. // Prepend the summary to the form field.
  348. $element['#children'] = '<div class="feeds-file">' . $summary . '<div class="feeds-file-upload">' . $element['#children'];
  349. // Render file upload field using theme_form_element().
  350. $output = theme('form_element', $element);
  351. // Close "feeds-file" and "feeds-file-upload" divs.
  352. $output .= '</div></div>';
  353. return $output;
  354. }