diff --git a/captcha.admin.inc b/captcha.admin.inc index 2a956c4..6878d8e 100644 --- a/captcha.admin.inc +++ b/captcha.admin.inc @@ -64,10 +64,10 @@ function captcha_admin_settings() { ); $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'] = array(); $captcha_type_options = _captcha_available_challenge_types(); - $result = db_select('captcha_points', 'cp')->fields('cp')->orderBy('form_id')->execute(); - foreach ($result as $captcha_point) { - $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id] = array(); - $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id]['form_id'] = array( + $captcha_points = captcha_get_captcha_points(); + foreach ($captcha_points as $captcha_point) { + $elem = array(); + $elem['form_id'] = array( '#markup' => $captcha_point->form_id, ); // Select widget for CAPTCHA type. @@ -80,17 +80,24 @@ function captcha_admin_settings() { else { $captcha_type = 'none'; } - $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id]['captcha_type'] = array( + $elem['captcha_type'] = array( '#type' => 'select', '#default_value' => $captcha_type, '#options' => $captcha_type_options, ); - // Additional operations. - $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id]['operations'] = array( - '#markup' => implode(", ", array( - l(t('delete'), "admin/config/people/captcha/captcha/captcha_point/{$captcha_point->form_id}/delete"), - )), - ); + $ops = array(); + if (module_exists('ctools') && $captcha_point->export_type & EXPORT_IN_CODE) { + if ($captcha_point->export_type & EXPORT_IN_DATABASE) { + $ops[] = l(t('revert'), "admin/config/people/captcha/captcha/captcha_point/{$captcha_point->form_id}/delete"); + } + // TODO Disable exported points. + } + else { + $ops[] = l(t('delete'), "admin/config/people/captcha/captcha/captcha_point/{$captcha_point->form_id}/delete"); + } + $elem['operations'] = array('#markup' => implode(", ", $ops)); + + $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id] = $elem; } // Form items for new form_id. @@ -281,7 +288,26 @@ function captcha_admin_settings_submit($form, &$form_state) { // Process CAPTCHA points. if (isset($form_state['values']['captcha_form_id_overview']['captcha_captcha_points'])) { + // Load existing data. + $captcha_points = captcha_get_captcha_points(); foreach ($form_state['values']['captcha_form_id_overview']['captcha_captcha_points'] as $captcha_point_form_id => $data) { + // If this is an in-code captcha point and its settings are unchanged, + // don't save to the database. + if (module_exists('ctools') && isset($captcha_points[$captcha_point_form_id])) { + // Parse module and captcha_type from submitted values. + if (is_string($data['captcha_type']) && substr_count($data['captcha_type'], '/') == 1) { + list($module, $captcha_type) = explode('/', $data['captcha_type']); + } + else { + $module = ''; + $captcha_type = $data['captcha_type']; + } + + $point = $captcha_points[$captcha_point_form_id]; + if ($point->export_type & EXPORT_IN_CODE && !($point->export_type & EXPORT_IN_DATABASE) && $point->module == $module && $point->captcha_type == $captcha_type) { + continue; + } + } captcha_set_form_id_setting($captcha_point_form_id, $data['captcha_type']); } } diff --git a/captcha.inc b/captcha.inc index 9412bc7..934d72f 100644 --- a/captcha.inc +++ b/captcha.inc @@ -83,8 +83,16 @@ function captcha_set_form_id_setting($form_id, $captcha_type) { */ function captcha_get_form_id_setting($form_id, $symbolic = FALSE) { // Fetch setting from database. - $result = db_query("SELECT module, captcha_type FROM {captcha_points} WHERE form_id = :form_id", array(':form_id' => $form_id)); - $captcha_point = $result->fetchObject(); + if (module_exists('ctools')) { + ctools_include('export'); + $object = ctools_export_load_object('captcha_points', 'names', array($form_id)); + $captcha_point = array_pop($object); + } + else { + $result = db_query("SELECT module, captcha_type FROM {captcha_points} WHERE form_id = :form_id", + array(':form_id' => $form_id)); + $captcha_point = $result->fetchObject(); + } // If no setting is available in database for the given form, // but 'captcha_default_challenge_on_nonlisted_forms' is enabled, pick the default type anyway. @@ -116,6 +124,26 @@ function captcha_get_form_id_setting($form_id, $symbolic = FALSE) { } /** + * Helper function to load all captcha points. + * + * @return array of all captcha_points + */ +function captcha_get_captcha_points() { + if (module_exists('ctools')) { + ctools_include('export'); + $captcha_points = ctools_export_load_object('captcha_points', 'all'); + } + else { + $captcha_points = array(); + $result = db_select('captcha_points', 'cp')->fields('cp')->orderBy('form_id')->execute(); + foreach ($result as $captcha_point) { + $captcha_points[] = $captcha_point; + } + } + return $captcha_points; +} + +/** * Helper function for generating a new CAPTCHA session. * * @param string $form_id diff --git a/captcha.install b/captcha.install index 58d0847..dc37f83 100644 --- a/captcha.install +++ b/captcha.install @@ -12,6 +12,18 @@ function captcha_schema() { // Table for positions and types of the challenges. $schema['captcha_points'] = array( 'description' => 'This table describes which challenges should be added to which forms.', + 'export' => array( + 'key' => 'form_id', + 'identifier' => 'captcha', + 'default hook' => 'captcha_default_points', // Function hook name. + 'status' => 'mark_status', + 'api' => array( + 'owner' => 'captcha', + 'api' => 'captcha', // Base name for api include files. + 'minimum_version' => 1, + 'current_version' => 1, + ), + ), 'fields' => array( 'form_id' => array( 'description' => 'The form_id of the form to add a CAPTCHA to.', @@ -134,25 +146,6 @@ function captcha_requirements($phase) { */ function captcha_install() { $t = get_t(); - // Insert some default CAPTCHA points. - $form_ids = array( - 'contact_site_form', 'contact_personal_form', - 'user_register_form', 'user_pass', 'user_login', 'user_login_block', - 'forum_node_form', - ); - // Add form_ids of all currently known node types too. - foreach (node_type_get_names() as $type => $name) { - $form_ids[] = 'comment_node_' . $type . '_form'; - } - foreach ($form_ids as $form_id) { - db_insert('captcha_points') - ->fields(array( - 'form_id' => $form_id, - 'module' => NULL, - 'captcha_type' => NULL, - )) - ->execute(); - } // Be friendly to your users: what to do after install? drupal_set_message($t('You can now configure the CAPTCHA module for your site.', diff --git a/captcha.module b/captcha.module index 1323393..16844ec 100644 --- a/captcha.module +++ b/captcha.module @@ -304,6 +304,54 @@ function captcha_element_process($element, &$form_state, $complete_form) { } /** + * Implementation of hook_captcha_default_points_alter(). + * + * Provide some default captchas only if defaults are not already + * provided by other modules. + */ +function captcha_captcha_default_points_alter(&$items) { + $modules = array( + 'comment' => array( + ), + 'contact' => array( + 'contact_site_form', + 'contact_personal_form' + ), + 'forum' => array( + 'forum_node_form', + ), + 'user' => array( + 'user_register_form', + 'user_pass', + 'user_login', + 'user_login_block', + ), + ); + // Add comment form_ids of all currently known node types. + foreach (node_type_get_names() as $type => $name) { + $modules['comment'][] = 'comment_node_' . $type . '_form'; + } + + foreach ($modules as $module => $form_ids) { + // Only give defaults if the module exists. + if (module_exists($module)) { + foreach ($form_ids as $form_id) { + // Ensure a default has not been provided already. + if (!isset($items[$form_id])) { + $captcha = new stdClass; + $captcha->disabled = FALSE; + $captcha->api_version = 1; + $captcha->form_id = $form_id; + $captcha->module = ''; + $captcha->captcha_type = 'default'; + $items[$form_id] = $captcha; + } + } + } + } +} + +/** * Theme function for a CAPTCHA element. * * Render it in a fieldset if a description of the CAPTCHA