diff --git a/feeds.module b/feeds.module index 33a4a4674decdde0b0c7f2ae9bdd94954b6325cb..b4028232e22bdcfe42fa11098f6f95e3020eb392 100644 --- a/feeds.module +++ b/feeds.module @@ -416,6 +416,16 @@ function feeds_access($action, $param) { return FALSE; } +/** + * Access callback to determine if the user can import Feeds importers. + * + * Feeds imports require an additional access check because they are PHP + * code and PHP is more locked down than administer feeds. + */ +function feeds_importer_import_access() { + return user_access('administer feeds') && user_access('use PHP for settings'); +} + /** * Menu access callback. */ @@ -1218,3 +1228,11 @@ function feeds_file_download($uri) { // Return file headers. return file_get_content_headers($file); } + +/** + * Feeds API version. + */ +function feeds_api_version() { + $version = feeds_ctools_plugin_api('feeds', 'plugins'); + return $version['version']; +} diff --git a/feeds_ui/feeds_ui.admin.inc b/feeds_ui/feeds_ui.admin.inc index 35feff2718fa02a4834fd0f26fa3452e942b85a6..1c6cc589c3eb48b9ed8d45b063543a40662995c0 100644 --- a/feeds_ui/feeds_ui.admin.inc +++ b/feeds_ui/feeds_ui.admin.inc @@ -1078,3 +1078,103 @@ function theme_feeds_ui_mapping_form($variables) { drupal_add_tabledrag('feeds-ui-mapping-overview', 'order', 'sibling', 'feeds-ui-mapping-weight'); return $output; } + +/** + * Page callback to import a feeds importer. + */ +function feeds_ui_importer_import($form, &$form_state) { + $form['id'] = array( + '#type' => 'textfield', + '#title' => t('Importer id'), + '#description' => t('Enter the id to use for this importer if it is different from the source importer. Leave blank to use the id of the importer.'), + ); + $form['id_override'] = array( + '#type' => 'checkbox', + '#title' => t('Replace an existing importer if one exists with the same id.'), + ); + $form['bypass_validation'] = array( + '#type' => 'checkbox', + '#title' => t('Bypass importer validation'), + '#description' => t('Bypass the validation of plugins when importing.'), + ); + $form['importer'] = array( + '#type' => 'textarea', + '#rows' => 10, + ); + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Import'), + ); + return $form; +} + +/** + * Form validation handler for feeds_ui_importer_import(). + * + * @see feeds_ui_importer_import_submit() + */ +function feeds_ui_importer_import_validate($form, &$form_state) { + $form_state['values']['importer'] = trim($form_state['values']['importer']); + $form_state['values']['id'] = trim($form_state['values']['id']); + + if (!empty($form_state['values']['id']) && preg_match('/[^a-zA-Z0-9_]/', $form_state['values']['id'])) { + form_error($form['id'], t('Feeds importer id must be alphanumeric with underscores only.')); + } + + if (substr($form_state['values']['importer'], 0, 5) == '<?php') { + $form_state['values']['importer'] = substr($form_state['values']['importer'], 5); + } + + $feeds_importer = NULL; + ob_start(); + eval($form_state['values']['importer']); + ob_end_clean(); + + if (!is_object($feeds_importer)) { + return form_error($form['importer'], t('Unable to interpret feeds importer code.')); + } + + if (empty($feeds_importer->api_version) || $feeds_importer->api_version < 1) { + form_error($form['importer'], t('The importer is not compatible with this version of Feeds.')); + } + elseif (version_compare($feeds_importer->api_version, feeds_api_version(), '>')) { + form_error($form['importer'], t('That importer is created for the version %import_version of Feeds, but you only have version %api_version.', array( + '%import_version' => $feeds_importer->api_version, + '%api_version' => feeds_api_version()))); + } + + $existing = feeds_importer($feeds_importer->id); + if ($existing && !$form_state['values']['id_override'] && $existing->export_type != EXPORT_IN_CODE) { + return form_error($form['id'], t('Feeds importer already exists with that id.')); + } + + if (!$form_state['values']['bypass_validation']) { + foreach (array('fetcher', 'parser', 'processor') as $type) { + $plugin = feeds_plugin($feeds_importer->config[$type]['plugin_key'], $feeds_importer->id); + if (get_class($plugin) == 'FeedsMissingPlugin') { + form_error($form['importer'], t('The plugin %plugin is unavailable.', array('%plugin' => $feeds_importer->config[$type]['plugin_key']))); + } + } + } + + $form_state['importer'] = $feeds_importer; +} + +/** + * Form submission handler for feeds_ui_importer_import(). + * + * @see feeds_ui_importer_import_validate() + */ +function feeds_ui_importer_import_submit($form, &$form_state) { + $importer = $form_state['importer']; + $importer = feeds_importer($importer->id); + $importer->setConfig($importer->config); + foreach (array('fetcher', 'parser', 'processor') as $type) { + $importer->$type->setConfig($importer->config[$type]['config']); + } + $importer->save(); + + drupal_set_message(t('Successfully imported the %id feeds importer.', array('%id' => $importer->id))); + $form_state['redirect'] = 'admin/structure/feeds'; +} diff --git a/feeds_ui/feeds_ui.module b/feeds_ui/feeds_ui.module index ba76d6fcef0140d6ad61d4a444f705125b2639fd..08cc40f2158d5b76d425032ed65c43ccb867531f 100644 --- a/feeds_ui/feeds_ui.module +++ b/feeds_ui/feeds_ui.module @@ -35,6 +35,14 @@ function feeds_ui_menu() { 'file' => 'feeds_ui.admin.inc', 'type' => MENU_LOCAL_ACTION, ); + $items['admin/structure/feeds/import'] = array( + 'title' => 'Import importer', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('feeds_ui_importer_import'), + 'access callback' => 'feeds_importer_import_access', + 'file' => 'feeds_ui.admin.inc', + 'type' => MENU_LOCAL_ACTION, + ); $items['admin/structure/feeds/%feeds_importer'] = array( 'title callback' => 'feeds_ui_importer_title', 'title arguments' => array(3),