feeds.pages.inc 11 KB

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