botcha.admin.inc in BOTCHA Spam Prevention 6.2
Same filename and directory in other branches
Implementation of botcha administration forms.
File
botcha.admin.incView source
<?php
// @todo Migrate all necessary functions not to have this including.
module_load_include('inc', 'botcha', 'botcha');
/**
* @file
* Implementation of botcha administration forms.
*/
/**
* Generate a random secret key.
*/
function botcha_generate_secret_key() {
return md5(uniqid(mt_rand(), TRUE));
}
function botcha_admin_settings(&$form_state) {
// We can't use system_settings_form() here because it will put all extra stuff into variables, that we want to avoid.
$form = array();
$form['botcha_secret'] = array(
'#type' => 'textfield',
'#title' => t('Secret key'),
'#default_value' => variable_get('botcha_secret', botcha_generate_secret_key()),
'#description' => t('It is recommended to enter some random text into the secret key. This setting makes your site\'s BOTCHA challenges unique and harder to break.') . '<br />' . t('If you leave this field empty and save configuration, a new random key will be generated for you.'),
);
// BOTCHA Statistics & Logging
$form['botcha_statistics'] = array(
'#type' => 'fieldset',
'#title' => t('Statistics & logging'),
'#description' => t('BOTCHA collects statistics of form submissions and it can report different events into the system log.'),
);
$dblog_link = l(t('log'), 'admin/reports/dblog');
$form['botcha_statistics']['botcha_loglevel'] = array(
'#type' => 'select',
'#title' => t('Log level'),
'#default_value' => variable_get('botcha_loglevel', BOTCHA_LOGLEVEL),
'#options' => array(
0 => t('0: no log'),
1 => t('1: blocked/bad submissions only'),
2 => t('2: ... and why blocked'),
3 => t('3: ... and good submissions'),
4 => t('4: ... and protected forms'),
5 => t('5: ... and extra submission details'),
6 => t('6: ... and misc development items'),
),
'#description' => t('Select what information to report into the !log.', array(
'!log' => $dblog_link,
)),
);
// Button for resetting the BOTCHA statistics.
$form['botcha_statistics']['botcha_statistics_group'] = array(
'#type' => 'item',
'#title' => t('BOTCHA statistics'),
'#description' => t('Reset all accumulated statistics of form submissions.'),
);
// Handle the button for resetting the BOTCHA statistics.
// This is done here instead of in a submit handler because the button is
// not a submitting button.
$form['botcha_statistics']['botcha_statistics_group']['botcha_statistics_reset'] = array(
'#type' => 'button',
'#value' => t('Reset BOTCHA statistics'),
'#submit' => array(
'botcha_statistics_reset',
),
// Pull it down.
'#weight' => 100,
);
if (isset($form_state['post']['op']) && $form_state['post']['op'] == $form['botcha_statistics']['botcha_statistics_group']['botcha_statistics_reset']['#value']) {
variable_set('botcha_form_passed_counter', 0);
variable_set('botcha_form_blocked_counter', 0);
drupal_set_message(t('BOTCHA statistics have been reset.'));
}
// Show statistic counters.
$block_cnt = variable_get('botcha_form_blocked_counter', 0);
$build_cnt = variable_get('botcha_form_passed_counter', 0) + $block_cnt;
$form['botcha_statistics']['botcha_statistics_group']['botcha_statistics'] = array(
'#type' => 'item',
'#value' => format_plural($block_cnt, 'Already 1 blocked form submission.', 'Already @count blocked form submissions.') . ($build_cnt > 0 ? ' ' . t('(!percent% of total !build_cnt processed)', array(
'!percent' => sprintf("%0.3f", 100 * $block_cnt / $build_cnt),
'!build_cnt' => $build_cnt,
)) : ''),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save configuration'),
);
$form['#theme'] = 'system_settings_form';
return $form;
}
/**
* Submission function for botcha_admin_settings form.
*/
function botcha_admin_settings_submit($form, &$form_state) {
// Generate the secret key.
// @todo Move secret key generation to validate phase.
if (empty($form_state['values']['botcha_secret'])) {
// Generate unique secret for this site
$secret = botcha_generate_secret_key();
$form_state['values']['botcha_secret'] = $secret;
drupal_set_message(t('New BOTCHA secret key have been generated.'));
}
// Do what system_settings_form() would do with regular variable fields
variable_set('botcha_secret', $form_state['values']['botcha_secret']);
variable_set('botcha_loglevel', $form_state['values']['botcha_loglevel']);
drupal_set_message(t('The BOTCHA settings were saved.'), 'status');
}
/**
* Callback for "Forms" admin page.
* Configuration of which forms to protect, with what recipe.
*/
function botcha_forms_form() {
return Botcha::getAdminForm('form_list');
}
/**
* Submission handler for botcha_forms_form form.
*/
function botcha_forms_form_submit($form, &$form_state) {
Botcha::submitAdminForm('form_list', $form, $form_state);
}
/**
* Edit existent or add BOTCHA protection to another form.
* @param array $form_state
* Form API form state array.
* @param BotchaForm $botcha_form
* Botcha form object.
*/
function botcha_form_form(&$form_state, $botcha_form = NULL) {
return Botcha::getAdminForm('form_edit', $form_state, $botcha_form);
}
function botcha_form_id_validate($element, &$form_state) {
$value = $element['#value'];
// @todo ?Is it correct way to check if the form is protected?
if (!Botcha::getForm($value, FALSE)
->getRecipebook() instanceof BotchaRecipebookNone) {
form_set_error('botcha_form_id', t('Form %form_id is already protected by BOTCHA', array(
'%form_id' => $value,
)));
}
}
/**
* Submit handler for botcha_form_form.
*/
function botcha_form_form_submit($form, &$form_state) {
Botcha::submitAdminForm('form_edit', $form, $form_state);
}
/**
* Confirm dialog for deleting a BOTCHA form completely.
*/
function botcha_form_delete_form(&$form_state, $botcha_form) {
$form['#botcha_form'] = $botcha_form;
return confirm_form($form, t('Are you sure you want to delete the BOTCHA protection for form_id %form_id?', array(
'%form_id' => $botcha_form->id,
)), Botcha::BOTCHA_ADMIN_PATH . '/form', NULL, t('Delete'));
}
/**
* Submission handler of BOTCHA form deleting.
*/
function botcha_form_delete_form_submit($form, &$form_state) {
$botcha_form = $form['#botcha_form'];
drupal_set_message(t('Deleted BOTCHA protection for form %form_id.', array(
'%form_id' => $botcha_form->id,
)));
// Remove BOTCHA protection for form.
$botcha_form
->delete();
$form_state['redirect'] = Botcha::BOTCHA_ADMIN_PATH . '/form';
}
/**
* Callback for "Recipe books" admin page.
* @todo ?Is it form really? Perhaps table?
*/
function botcha_recipebooks_form() {
$form['#header'] = array(
t('Title'),
t('Description'),
t('Operations'),
);
// Get all recipe books from database.
$recipebooks = Botcha::getRecipebooks();
// Protect default recipebook from being deleted.
foreach ($recipebooks as $recipebook) {
/* @todo Abstarct it.
$form['recipebooks'][$recipebook->id]['title']['#markup'] = $recipebook->title;
$form['recipebooks'][$recipebook->id]['description']['#markup'] = $recipebook->description;
$form['recipebooks'][$recipebook->id]['operations']['#markup'] = l(t('Edit'), Botcha::BOTCHA_ADMIN_PATH . '/recipebook/' . $recipebook->id)
*
*/
$form['recipebooks'][$recipebook->id]['title']['#value'] = $recipebook->title;
$form['recipebooks'][$recipebook->id]['description']['#value'] = $recipebook->description;
$form['recipebooks'][$recipebook->id]['operations']['#value'] = in_array($recipebook->id, array(
'forbidden_forms',
)) ? '' : l(t('Edit'), Botcha::BOTCHA_ADMIN_PATH . '/recipebook/' . $recipebook->id) . (in_array($recipebook->id, array(
'default',
'forbidden_forms',
)) ? '' : ' | ' . l(t('Delete'), Botcha::BOTCHA_ADMIN_PATH . '/recipebook/' . $recipebook->id . '/delete'));
}
return $form;
}
/**
* Edit existent or add a new recipe book.
* @param array $form_state
* Form API form state array.
* @param BotchaRecipebookAbstract $recipebook
* Recipe book object.
*/
function botcha_recipebook_form(&$form_state, $recipebook = NULL) {
if ($recipebook instanceof BotchaRecipebookNone) {
// Redirect in case we are trying to edit unexisting item.
drupal_goto(Botcha::BOTCHA_ADMIN_PATH . '/recipebook/add', array(
'query' => array(
'botcha_rbid' => $recipebook->id,
),
));
}
// Determine default values depending on whether we add or edit recipe book.
if ($edit = !empty($recipebook)) {
$default_id = $recipebook->id;
$default_title = $recipebook->title;
$default_description = $recipebook->description;
$default_recipes = array_keys($recipebook
->getRecipes());
// @todo Abstract it.
$validate = array();
$button = t('Save');
}
else {
// @todo Unused yet. Do we need it?
$default_id = !empty($_GET['botcha_rbid']) ? $_GET['botcha_rbid'] : NULL;
$default_title = '';
$default_description = '';
$default_recipes = array();
// @todo Abstract it.
$validate = array(
'botcha_form_id_validate',
);
$button = t('Add');
}
$form['id'] = array(
'#type' => 'textfield',
'#title' => t('Id'),
'#description' => t('The unique identifier of the recipe book.'),
// @todo Abstract it.
//'#default_value' => $default_id,
//'#value' => $default_id,
'#required' => TRUE,
'#disabled' => $edit,
'#maxlength' => 128,
'#element_validate' => $validate,
);
// @todo Abstract it.
if ($edit) {
$form['id']['#value'] = $default_id;
}
else {
$form['id']['#default_value'] = $default_id;
}
$form['title'] = array(
'#type' => 'textfield',
'#title' => t('Title'),
'#description' => t('A title for this recipe book. You can always change this name later.'),
'#default_value' => $default_title,
'#required' => TRUE,
'#maxlength' => 128,
);
$form['description'] = array(
'#type' => 'textarea',
'#rows' => 5,
'#title' => t('Description'),
'#description' => t('A description of the recipe book.'),
'#default_value' => $default_description,
);
// Form a list of recipes.
$form['recipes'] = array(
'#type' => 'fieldset',
'#title' => t('Recipes'),
'#description' => t('Choose what recipes are included in recipe book.'),
'#tree' => TRUE,
);
foreach (Botcha::getRecipes() as $recipe) {
$form['recipes'][$recipe->id] = array(
'#type' => 'checkbox',
'#title' => $recipe
->getTitle(),
'#description' => $recipe
->getDescription(),
'#default_value' => in_array($recipe->id, $default_recipes),
);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => $button,
);
return $form;
}
function botcha_recipebook_id_validate($element, $form_state) {
$value = $element['#value'];
if (!Botcha::getRecipebook($value, FALSE) instanceof BotchaRecipebookNone) {
form_set_error('id', t('Recipe book %rbid already exists', array(
'%rbid' => $value,
)));
}
}
/**
* Submit handler for botcha_recipebook_form.
* @param $form
* Form API form array.
* @param $form_state
* Form API form state array.
*/
function botcha_recipebook_form_submit($form, &$form_state) {
$values = $form_state['values'];
$recipebook = Botcha::getRecipebook($values['id'])
->setTitle($values['title'])
->setDescription($values['description']);
/*
foreach (array_filter($values['recipes']) as $recipe_id) {
$recipebook->setRecipe($recipe_id);
}
*
*/
foreach ($values['recipes'] as $recipe_id => $value) {
if ($value) {
$recipebook = $recipebook
->setRecipe($recipe_id);
}
else {
$recipebook = $recipebook
->unsetRecipe($recipe_id);
}
}
$recipebook
->save();
$form_state['redirect'] = Botcha::BOTCHA_ADMIN_PATH . '/recipebook';
drupal_set_message(t('Settings for recipe book "%recipebook" are successfully saved.', array(
'%recipebook' => $recipebook->id,
)), 'status');
}
/**
* Delete configuration form.
*/
function botcha_recipebook_delete_form(&$form_state, $recipebook) {
$form['#recipebook'] = $recipebook;
return confirm_form($form, t('Would you really like to delete the recipe book @recipebook?', array(
'@recipebook' => $recipebook->title,
)), Botcha::BOTCHA_ADMIN_PATH . '/recipebook', NULL, t('Delete'));
}
/**
* Submit handler for botcha_recipebook_delete_form().
*/
function botcha_recipebook_delete_form_submit($form, &$form_state) {
$recipebook = $form['#recipebook'];
drupal_set_message(t('Recipe book %rbid successfully deleted.', array(
'%rbid' => $recipebook->id,
)));
// Remove recipe book.
$recipebook
->delete();
$form_state['redirect'] = Botcha::BOTCHA_ADMIN_PATH . '/recipebook';
}
function botcha_recipes_form() {
// @todo Implement Recipe UI.
// @see https://drupal.org/node/1815080
$form = array();
$form['stub'] = array(
'#value' => t('This functionality is currently in development. See <a href="@issue_link">related issue</a>. Please consider participating in <a href="@patchranger_link">patch crowd funding of this issue</a>. Read more about patch crowd funding on <a href="@botcha_project_link">the BOTCHA project page</a>.', array(
'@issue_link' => url('http://drupal.org/node/1815080'),
'@patchranger_link' => url('http://www.patchranger.com/?do_nid=1815080'),
'@botcha_project_link' => url('http://drupal.org/project/botcha#how-much-does-it-cost'),
)),
);
return $form;
}
/**
* Theme botcha_recipebooks_form().
*/
function theme_botcha_recipebooks_form($form) {
// @todo Abstract it.
// "Add recipebook" link.
$output = l(t('Add recipe book'), Botcha::BOTCHA_ADMIN_PATH . '/recipebook/add');
// Prepare header before pass to theme.
$header = $form['#header'];
// Iterate through all recipebooks and build a table.
$rows = array();
foreach (element_children($form['recipebooks']) as $id) {
$row = array();
foreach (element_children($form['recipebooks'][$id]) as $col) {
$row[$col] = drupal_render($form['recipebooks'][$id][$col]);
}
$rows[$id] = $row;
}
$output .= theme('table', $header, $rows);
return $output;
}
/**
* Custom theme function for a table of (form_id -> BOTCHA type) settings
*/
function theme_botcha_forms_form_botcha_forms($form) {
// @todo Abstract it.
// "Add BOTCHA protection to the form" link.
$output = l(t('Add BOTCHA protection to the form'), Botcha::BOTCHA_ADMIN_PATH . '/form/add');
// Prepare header before pass to theme.
$header = $form['#header'];
$rows = array();
// Existing BOTCHA points.
foreach (element_children($form['botcha_forms']) as $id) {
$row = array();
foreach (element_children($form['botcha_forms'][$id]) as $col) {
$row[$col] = drupal_render($form['botcha_forms'][$id][$col]);
}
$rows[$id] = $row;
}
$output .= theme('table', $header, $rows);
return $output;
}
//END
Functions
Name | Description |
---|---|
botcha_admin_settings | |
botcha_admin_settings_submit | Submission function for botcha_admin_settings form. |
botcha_forms_form | Callback for "Forms" admin page. Configuration of which forms to protect, with what recipe. |
botcha_forms_form_submit | Submission handler for botcha_forms_form form. |
botcha_form_delete_form | Confirm dialog for deleting a BOTCHA form completely. |
botcha_form_delete_form_submit | Submission handler of BOTCHA form deleting. |
botcha_form_form | Edit existent or add BOTCHA protection to another form. |
botcha_form_form_submit | Submit handler for botcha_form_form. |
botcha_form_id_validate | |
botcha_generate_secret_key | Generate a random secret key. |
botcha_recipebooks_form | Callback for "Recipe books" admin page. @todo ?Is it form really? Perhaps table? |
botcha_recipebook_delete_form | Delete configuration form. |
botcha_recipebook_delete_form_submit | Submit handler for botcha_recipebook_delete_form(). |
botcha_recipebook_form | Edit existent or add a new recipe book. |
botcha_recipebook_form_submit | Submit handler for botcha_recipebook_form. |
botcha_recipebook_id_validate | |
botcha_recipes_form | |
theme_botcha_forms_form_botcha_forms | Custom theme function for a table of (form_id -> BOTCHA type) settings |
theme_botcha_recipebooks_form | Theme botcha_recipebooks_form(). |