You are here

public function Botcha::getAdminForm in BOTCHA Spam Prevention 7.3

Same name and namespace in other branches
  1. 6.2 controller/botcha.controller.inc \Botcha::getAdminForm()
  2. 6.3 controller/application/botcha.application.controller.inc \Botcha::getAdminForm()
  3. 7.2 controller/botcha.controller.inc \Botcha::getAdminForm()

File

controller/application/botcha.application.controller.inc, line 392
Contains Botcha class.

Class

Botcha
Just a middleman for achieving purposes such as:

Code

public function getAdminForm($form, &$form_state, $form_name) {

  // @todo Abstract it.

  //$form = parent::getAdminForm($form_state, $form_name);
  $form = parent::getAdminForm($form, $form_state, $form_name);

  // It is used on submit stage.
  $form['#form_name'] = array(
    '#type' => 'hidden',
    '#value' => $form_name,
  );

  // @todo Refactor this switch stuff with classes since they are similar a lot.
  switch ($form_name) {
    case 'general':

      // Module settings form.
      // We can't use system_settings_form() here because it will put all extra
      // stuff into variables, that we want to avoid.
      $form['botcha_secret'] = array(
        '#type' => 'textfield',
        '#title' => t('Secret key'),
        '#default_value' => variable_get('botcha_secret', $this
          ->generateSecretKey()),
        '#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');

      // @todo Refactor logging.
      $form['botcha_statistics']['botcha_loglevel'] = array(
        '#type' => 'select',
        '#title' => t('Log level'),
        '#default_value' => variable_get('botcha_loglevel', 2),
        '#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.' . ' Please note!: Using BOTCHA logging setting could cause at high' . ' levels putting vulnerable data into logs. We have some basic' . ' escaping (e.g., for password field) - but any other data could' . ' be found in raw format. Please be careful with logging level' . ' setting!', 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,
      );

      // @todo Abstract it.

      //if (isset($form_state['post']['op']) && $form_state['post']['op']
      if (isset($form_state['input']['op']) && $form_state['input']['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',
        // @todo Abstarct it.

        //'#value' => format_plural(
        '#markup' => 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';
      break;
    case 'form_delete':

      // @todo Abstract it.

      //$botcha_form = func_get_arg(2);
      $botcha_form = func_get_arg(3);
      $form['botcha_form_id'] = array(
        '#type' => 'value',
        '#value' => $botcha_form->id,
      );
      $message = t('Are you sure you want to delete the BOTCHA protection for form_id %form_id?', array(
        '%form_id' => $botcha_form->id,
      ));

      // @todo Refactor: remove code duplication (filling in #submit is intended to be done below).
      $form = confirm_form($form, $message, Botcha::ADMIN_PATH, NULL, t('Delete'));
      $form['actions']['submit']['#submit'] = array(
        'Botcha_submitAdminForm',
      );
      return $form;
      break;
    case 'form_edit':
      $args = func_get_args();

      // @todo Abstract it.

      //$botcha_form = (!empty($args[2]) ? $args[2] : NULL);
      $botcha_form = !empty($args[3]) ? $args[3] : NULL;
      $recipebook_controller = $this
        ->getController(Botcha::CONTROLLER_TYPE_RECIPEBOOK);

      // Determine default values depending on whether we add or edit form.
      $edit = !empty($botcha_form);
      if ($edit) {
        if ($botcha_form instanceof BotchaFormNone) {

          // Redirect in case we are trying to edit unexisting item.
          drupal_goto(Botcha::ADMIN_PATH . '/form/add', array(
            'query' => array(
              'botcha_form_id' => $botcha_form->id,
            ),
          ));
        }
        $operation = 'edit';
        $isEnabled = $botcha_form
          ->isEnabled();
        $recipebook = $recipebook_controller
          ->getRecipebook($botcha_form
          ->getRecipebook(), FALSE);
        $botcha_form_id_default = check_plain($botcha_form->id);

        // @todo Abstract it.

        //$validate = array();
        $button = t('Save');
      }
      else {
        $operation = 'add';
        $isEnabled = TRUE;

        // 'default' will be selected.
        $recipebook = $recipebook_controller
          ->getRecipebook();

        // @todo Abstract it.
        $query_params = drupal_get_query_parameters();
        $botcha_form_id_default = !empty($query_params['botcha_form_id']) ? $query_params['botcha_form_id'] : NULL;

        // @todo Abstract it.

        //$validate = array('botcha_formIdValidate');
        $button = t('Add');
      }

      // Insert a field that allows to understand whether it is creation or edition form submission.
      $form['botcha_operation'] = array(
        '#type' => 'value',
        '#value' => $operation,
      );

      // Determine whether the form enabled or not.
      $form['botcha_enabled'] = array(
        '#type' => 'checkbox',
        '#title' => t('Enabled'),
        '#description' => t('Enable BOTCHA protection for the form.'),
        '#default_value' => $isEnabled,
      );

      // Use passed as a parameter form id.
      $form['botcha_form_id'] = array(
        // @todo Abstract it. Perhaps use Elements for adapter to it.
        // @see http://drupal.org/node/995784

        //'#type' => 'textfield',

        //'#element_validate' => $validate,

        //'#required' => TRUE,
        '#title' => t('Form ID'),
        '#description' => t('The Drupal form_id of the form to add the BOTCHA protection to.'),
        '#maxlength' => 128,
      );
      if ($edit) {

        // Change type to textfield to avoid unique checking.
        $form['botcha_form_id']['#type'] = 'textfield';
        $form['botcha_form_id']['#disabled'] = TRUE;

        // We use #value instead of #default_value as a workaround.
        // @see http://drupal.org/node/1837306
        $form['botcha_form_id']['#value'] = $botcha_form_id_default;
      }
      else {
        $form['botcha_form_id']['#type'] = 'machine_name';
        $form['botcha_form_id']['#default_value'] = $botcha_form_id_default;
        $form['botcha_form_id']['#machine_name']['exists'] = 'Botcha_formExists';
        $form['botcha_form_id']['#required'] = TRUE;
      }
      $options = array();
      $rbs = $recipebook_controller
        ->getRecipebooks(TRUE, TRUE);
      foreach ($rbs as $rb) {
        $options[$rb->id] = $rb->title;
      }
      $form['botcha_form_recipebook'] = array(
        '#type' => 'select',
        '#title' => t('Recipe book'),
        '#description' => t('Recipe book to apply to the form.'),
        '#default_value' => $recipebook->id,
        '#options' => $options,
      );
      $form['submit'] = array(
        '#type' => 'submit',
        '#value' => $button,
      );
      break;
    case 'form_list':
      $form['botcha_form_protection'] = array();

      // List known form_ids.
      $form['botcha_form_protection']['botcha_form_id_overview'] = array(
        '#theme' => 'botcha_forms_form_botcha_forms',
        '#tree' => TRUE,
      );
      $form['botcha_form_protection']['botcha_form_id_overview']['#header'] = array(
        t('Enabled'),
        'form_id',
        t('Recipe book'),
      );
      $form['botcha_form_protection']['botcha_form_id_overview']['botcha_forms'] = array();
      $forms = $this
        ->getController(Botcha::CONTROLLER_TYPE_FORM)
        ->getForms(TRUE);
      foreach ($forms as $botcha_form) {

        // Get individual admin form as a row of our overview table.
        // @todo Abstract it.
        $fake_form = array();
        $fake_form_state = array();

        // @todo Abstract it.

        //$item_form = $this->getAdminForm($fake_form_state, 'form_edit', $botcha_form);
        $item_form = $this
          ->getAdminForm($fake_form, $fake_form_state, 'form_edit', $botcha_form);

        // Remove submit button ...
        unset($item_form['submit']);

        // ... and botcha_operation field ...
        unset($item_form['botcha_operation']);

        // ... and also additional properties of some fields.
        unset($item_form['botcha_enabled']['#title']);
        unset($item_form['botcha_enabled']['#description']);
        $form['botcha_form_protection']['botcha_form_id_overview']['botcha_forms'][$botcha_form->id] = $item_form;
      }
      if (module_exists('captcha')) {

        // Checkbox to put BOTCHA on same forms as CAPTCHA.
        $form['botcha_form_protection']['botcha_on_captcha_forms'] = array(
          '#type' => 'checkbox',
          '#title' => t('Add BOTCHA to forms selected for CAPTCHA'),
          '#default_value' => variable_get('botcha_on_captcha_forms', TRUE),
          '#description' => t('This option makes it easy to manage BOTCHA settings on forms. When enabled, all forms that are configured to have CAPTCHA on them (<a href="@captcha">see configuration</a>) will also be selected for BOTCHA protection.!more', array(
            // @todo Abstract it.

            //'@captcha' => url('admin/user/captcha'),
            '@captcha' => url('admin/config/people/captcha'),
            '!more' => module_exists('captcha') ? '' : '<br />' . t('<b>Note:</b> <a href="@captcha_home">CAPTCHA module</a> is not installed. This setting will have no effect.', array(
              '@captcha_home' => 'http://drupal.org/project/captcha',
            )),
          )),
        );
      }

      // Field for the BOTCHA administration mode.
      $form['botcha_form_protection']['botcha_administration_mode'] = array(
        '#type' => 'checkbox',
        '#title' => t('Add BOTCHA administration links to forms'),
        '#default_value' => variable_get('botcha_administration_mode', FALSE),
        '#description' => t('This option makes it easy to manage BOTCHA settings on forms. When enabled, users with the "%adminbotcha" permission will see a fieldset with BOTCHA administration links on all forms, except on administrative pages.', array(
          '%adminbotcha' => t('administer BOTCHA settings'),
        )),
      );

      // Field for the BOTCHAs on admin pages.
      $form['botcha_form_protection']['botcha_allow_on_admin_pages'] = array(
        '#type' => 'checkbox',
        '#title' => t('Allow BOTCHAs and BOTCHA administration links on administrative pages'),
        '#default_value' => variable_get('botcha_allow_on_admin_pages', FALSE),
        '#description' => t('This option makes it possible to add BOTCHAs to forms on administrative pages. BOTCHAs are disabled by default on administrative pages (which shouldn\'t be accessible to untrusted users normally) to avoid the related overhead. In some situations, e.g. in the case of demo sites, it can be usefull to allow BOTCHAs on administrative pages.'),
      );
      $form['submit'] = array(
        '#type' => 'submit',
        '#value' => t('Save configuration'),
      );

      // @todo Abstract it.
      // @todo ?Do we need it?

      //$form['#theme'] = 'system_settings_form';
      break;
    case 'recipe_delete':

      // Unused yet.
      // @todo Abstract it.

      //$recipe = func_get_arg(2);
      $recipe = func_get_arg(3);
      break;
    case 'recipe_edit':

      // Unused yet.
      $args = func_get_args();

      // @todo Abstract it.

      //$recipe = (!empty($args[2]) ? $args[2] : NULL);
      $recipe = !empty($args[3]) ? $args[3] : NULL;
      break;
    case 'recipe_list':

      // @todo Implement Recipe UI.
      // @see https://drupal.org/node/1815080
      $form['stub'] = array(
        // @todo Abstract it.

        //'#value' => $this->getStubText(1815080),
        '#markup' => $this
          ->getStubText(1815080),
      );
      break;
    case 'recipebook_delete':

      // @todo Abstract it.

      //$recipebook = func_get_arg(2);
      $recipebook = func_get_arg(3);

      // @todo Pass just rbid, not the whole object.
      $form['#botcha_recipebook'] = array(
        '#type' => 'value',
        '#value' => $recipebook,
      );

      // @todo Refactor: remove code duplication (filling in #submit is intended to be done below).
      $form = confirm_form($form, t('Are you sure you want to delete the recipe book @recipebook?', array(
        '@recipebook' => $recipebook->title,
      )), Botcha::ADMIN_PATH . '/recipebook', t('This action cannot be undone.'), t('Delete'));
      $form['actions']['submit']['#submit'] = array(
        'Botcha_submitAdminForm',
      );
      return $form;
      break;
    case 'recipebook_edit':
      $args = func_get_args();

      // @todo Abstract it.

      //$recipebook = (!empty($args[2]) ? $args[2] : NULL);
      $recipebook = !empty($args[3]) ? $args[3] : NULL;

      // Determine default values depending on whether we add or edit recipe book.
      // Form a list of recipes.
      $options_recipes = array();
      $recipe_controller = $this
        ->getController(Botcha::CONTROLLER_TYPE_RECIPE);
      foreach ($recipe_controller
        ->getRecipes() as $recipe_id) {
        $recipe = $recipe_controller
          ->getRecipe($recipe_id, FALSE);
        $options_recipes[$recipe->id] = $recipe->title;
      }
      $edit = !empty($recipebook);
      if ($edit) {
        if ($recipebook instanceof BotchaRecipebookNone) {

          // Redirect in case we are trying to edit unexisting item.
          drupal_goto(Botcha::ADMIN_PATH . '/recipebook/add', array(
            'query' => array(
              'rbid' => $recipebook->id,
            ),
          ));
        }
        $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 {
        $default_id = '';
        $default_title = '';
        $default_description = '';
        $default_recipes = array();

        // @todo Abstract it.

        //$validate = array('botcha_recipebookIdValidate');
        $button = t('Add');
      }
      $form['id'] = array(
        // @todo Abstract it. Perhaps use Elements for adapter to it.
        // @see http://drupal.org/node/995784

        //'#type' => 'textfield',

        //'#element_validate' => $validate,

        //'#required' => TRUE,

        //'#title' => t('Machine-readable name'),

        //'#description' => t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'),
        '#maxlength' => 128,
      );
      if ($edit) {

        // Change type to textfield to avoid unique checking.
        $form['id']['#type'] = 'textfield';
        $form['id']['#disabled'] = TRUE;

        // We use #value instead of #default_value as a workaround.
        // @see http://drupal.org/node/1837306
        $form['id']['#value'] = $default_id;
      }
      else {
        $form['id']['#type'] = 'machine_name';
        $form['id']['#default_value'] = $default_id;
        $form['id']['#machine_name']['exists'] = 'Botcha_recipebookExists';
        $form['id']['#required'] = TRUE;
      }
      $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['recipes'] = array(
        '#type' => 'checkboxes',
        '#title' => t('Recipes'),
        '#description' => t('Choose what recipes are included in recipe book.'),
        '#options' => $options_recipes,
        '#default_value' => $default_recipes,
      );
      $form['submit'] = array(
        '#type' => 'submit',
        '#value' => $button,
      );
      break;
    case 'recipebook_list':
      $form['#theme'] = 'botcha_recipebooks_form';

      // @todo Refactor it: turn list into multiple single forms.
      $form['#header'] = array(
        t('Title'),
        t('Description'),
        t('Operations'),
      );

      // Get all recipe books from database.
      $recipebooks = $this
        ->getController(Botcha::CONTROLLER_TYPE_RECIPEBOOK)
        ->getRecipebooks(TRUE);

      // Protect default recipebook from being deleted.
      foreach ($recipebooks as $recipebook) {

        // @todo Abstract it.

        //$form['recipebooks'][$recipebook->id]['title']['#value'] = $recipebook->title;
        $form['recipebooks'][$recipebook->id]['title']['#markup'] = $recipebook->title;

        // @todo Abstract it.

        //$form['recipebooks'][$recipebook->id]['description']['#value'] = $recipebook->description;
        $form['recipebooks'][$recipebook->id]['description']['#markup'] = $recipebook->description;

        // @todo Abstract it.

        //$form['recipebooks'][$recipebook->id]['operations']['#value'] =
        $form['recipebooks'][$recipebook->id]['operations']['#markup'] = in_array($recipebook->id, array(
          'forbidden_forms',
        )) ? '' : l(t('Edit'), Botcha::ADMIN_PATH . "/recipebook/{$recipebook->id}") . (in_array($recipebook->id, array(
          'default',
          'forbidden_forms',
        )) ? '' : ' | ' . l(t('Delete'), Botcha::ADMIN_PATH . "/recipebook/{$recipebook->id}/delete"));
      }
      break;
  }

  // Turn on submit magic.
  // @todo Remove it after RecipeUI implementation.
  if ($form_name != 'recipe_list') {
    $form['submit']['#submit'] = array(
      'Botcha_submitAdminForm',
    );
  }
  return $form;
}