'no',
'zh-hans' => 'zh-cn',
'zh-hant' => 'zh-tw',
);
foreach($mapped as $drupal_key => $mollom_key) {
if (isset($supported[$mollom_key])) {
$supported[$drupal_key] = $mollom_key;
unset($supported[$mollom_key]);
}
}
$options = array();
$languages_enabled = language_list();
$installed_languages = array();
// This does assume that all Mollom supported languages are in the predefined
// Drupal list.
foreach ($predefined as $langcode => $language) {
$found = FALSE;
$simplified_code = strtok($langcode, '-');
if (isset($supported[$simplified_code]) && !isset($options[$simplified_code])) {
$options[$supported[$simplified_code]] = t($language[0]);
$found = TRUE;
}
else if (isset($supported[$langcode]) && !isset($options[$langcode])) {
$options[$supported[$langcode]] = t($language[0]);
$found = TRUE;
}
if ($found) {
// Update the list of installed languages that are supported.
if (isset($languages_enabled[$langcode])) {
$installed_languages[$supported[$simplified_code]] = $simplified_code;
}
}
}
// Sort by translated option labels.
asort($options);
// UX: Sort installed languages first.
return array_intersect_key($options, $installed_languages) + $options;
}
/**
* Checks the configuration status on Mollom administration pages.
*
* On all Mollom administration pages, check the module configuration and
* display the corresponding requirements error, if invalid.
*/
function mollom_admin_site_status($force = FALSE, $update = FALSE) {
$status = _mollom_status($force, $update);
if (empty($_POST) && !$status['isVerified']) {
// Fetch and display requirements error message, without re-checking.
module_load_install('mollom');
$requirements = mollom_requirements('runtime', FALSE);
if (isset($requirements['mollom']['description'])) {
drupal_set_message($requirements['mollom']['description'], 'error');
}
}
return $status;
}
/**
* Menu callback; Displays a list of forms configured for Mollom.
*/
function mollom_admin_form_list() {
mollom_admin_site_status();
_mollom_testing_mode_warning();
// Reset the cached list of protected forms.
mollom_form_cache(TRUE);
$modes = array(
MOLLOM_MODE_ANALYSIS => t('Text analysis'),
MOLLOM_MODE_CAPTCHA => t('CAPTCHA'),
);
$header = array(
t('Form'),
t('Protection mode'),
array('data' => t('Operations'), 'colspan' => 2),
);
$result = db_query('SELECT form_id FROM {mollom_form}')->fetchCol();
$forms = array();
$module_info = system_get_info('module');
foreach ($result as $form_id) {
$forms[$form_id] = mollom_form_load($form_id);
// system_get_info() only supports enabled modules. Default to the module's
// machine name in case it is disabled.
$module = $forms[$form_id]['module'];
if (!isset($module_info[$module])) {
$module_info[$module]['name'] = $module;
}
$forms[$form_id]['title'] = t('!module: !form-title', array(
'!form-title' => $forms[$form_id]['title'],
'!module' => t($module_info[$module]['name']),
));
}
// Sort forms by title (including module name prefix).
uasort($forms, 'drupal_sort_title');
$rows = array();
foreach ($forms as $form_id => $mollom_form) {
$row_attributes = array();
$row = array();
$row[] = $mollom_form['title'];
if (isset($modes[$mollom_form['mode']])) {
if ($mollom_form['mode'] == MOLLOM_MODE_ANALYSIS) {
// @todo Output unsure mode in summary listing.
$row[] = t('!protection-mode (@discard)', array(
'!protection-mode' => $modes[$mollom_form['mode']],
'@discard' => $mollom_form['discard'] ? t('discard') : t('retain'),
));
}
else {
$row[] = $modes[$mollom_form['mode']];
}
}
else {
$row[] = t('- orphan -');
}
if (empty($mollom_form['orphan'])) {
$row[] = array('data' => array(
'#type' => 'link',
'#title' => t('Configure'),
'#href' => 'admin/config/content/mollom/manage/' . $form_id,
));
}
else {
$row[] = '';
$row_attributes['class'] = array('error');
drupal_set_message(t("%module module's %form_id form no longer exists.", array(
'%form_id' => $form_id,
'%module' => isset($module_info[$mollom_form['module']]['name']) ? t($module_info[$mollom_form['module']]['name']) : $mollom_form['module'],
)), 'warning');
}
$row[] = array('data' => array(
'#type' => 'link',
'#title' => t('Unprotect'),
'#href' => 'admin/config/content/mollom/unprotect/' . $form_id,
));
$rows[] = $row_attributes + array('data' => $row);
}
$build['forms'] = array(
'#theme' => 'table',
'#header' => $header,
'#rows' => $rows,
'#empty' => l(t('Add form'), 'admin/config/content/mollom/add'),
);
return $build;
}
/**
* Return registered forms as an array suitable for a 'checkboxes' form element #options property.
*/
function mollom_admin_form_options() {
// Retrieve all registered forms.
$form_list = mollom_form_list();
// Remove already configured form ids.
$result = db_query('SELECT form_id FROM {mollom_form}')->fetchCol();
foreach ($result as $form_id) {
unset($form_list[$form_id]);
}
// If all registered forms are configured already, output a message, and
// redirect the user back to overview.
if (empty($form_list)) {
drupal_set_message(t('All available forms are protected already.'));
drupal_goto('admin/config/content/mollom');
}
// Load module information.
$module_info = system_get_info('module');
// Transform form information into an associative array suitable for #options.
$options = array();
foreach ($form_list as $form_id => $info) {
// system_get_info() only supports enabled modules. Default to the module's
// machine name in case it is disabled.
$module = $info['module'];
if (!isset($module_info[$module])) {
$module_info[$module]['name'] = $module;
}
$options[$form_id] = t('!module: !form-title', array(
'!form-title' => $info['title'],
'!module' => t($module_info[$module]['name']),
));
}
// Sort form options by title.
asort($options);
return $options;
}
/**
* Form builder; Configure Mollom protection for a form.
*/
function mollom_admin_configure_form($form, &$form_state, $mollom_form = NULL) {
// If no $mollom_form was passed, then we are adding a new form configuration.
if (!isset($mollom_form)) {
if (!isset($form_state['storage']['mollom_form'])) {
$form_state['storage']['step'] = 'select';
}
else {
$form_state['storage']['step'] = 'configure';
$mollom_form = $form_state['storage']['mollom_form'];
}
}
// When adding a new form configuration, passing form_id via path argument.
elseif (is_string($mollom_form)) {
$mollom_form = mollom_form_new($mollom_form);
$form_state['storage']['step'] = 'configure';
$form_state['storage']['mollom_form'] = $mollom_form;
}
// Otherwise, we are editing an existing form configuration.
else {
$form_state['storage']['step'] = 'configure';
$form_state['storage']['mollom_form'] = $mollom_form;
}
$form['#tree'] = TRUE;
$form['actions'] = array(
'#type' => 'actions',
);
$form['#attached'] = array(
'js' => array(
drupal_get_path('module', 'mollom') . '/mollom.admin.js',
),
);
switch ($form_state['storage']['step']) {
case 'select':
$form['mollom']['form_id'] = array(
'#type' => 'select',
'#title' => t('Form'),
'#options' => mollom_admin_form_options(),
'#required' => TRUE,
);
$form['actions']['next'] = array(
'#type' => 'submit',
'#value' => t('Next'),
'#submit' => array('mollom_admin_configure_form_next_submit'),
);
break;
case 'configure':
drupal_set_title(t('Configure %form-title protection', array('%form-title' => $mollom_form['title'])), PASS_THROUGH);
$recommended = t('recommended');
$form['mollom']['form_id'] = array(
'#type' => 'value',
'#value' => $mollom_form['form_id'],
);
$modes = array();
$modes[MOLLOM_MODE_ANALYSIS] = t('!option (!recommended)', array(
'!option' => t('Text analysis'),
'!recommended' => $recommended,
));
$modes[MOLLOM_MODE_CAPTCHA] = t('CAPTCHA only');
$form['mollom']['mode'] = array(
'#type' => 'radios',
'#title' => t('Protection mode'),
'#options' => $modes,
'#default_value' => isset($mollom_form['mode']) ? $mollom_form['mode'] : key($modes),
);
$form['mollom']['mode'][MOLLOM_MODE_ANALYSIS] = array(
'#description' => t('Mollom will analyze the post and will only show a CAPTCHA when it is unsure.'),
);
$form['mollom']['mode'][MOLLOM_MODE_CAPTCHA] = array(
'#description' => t('A CAPTCHA will be shown for every post. Only choose this if there are too few text fields to analyze.'),
);
$form['mollom']['mode'][MOLLOM_MODE_CAPTCHA]['#description'] .= '
' . t('Note: Page caching is disabled on all pages containing a CAPTCHA-only protected form.');
$all_permissions = array();
foreach (module_implements('permission') as $module) {
if ($module_permissions = module_invoke($module, 'permission')) {
foreach ($module_permissions as &$info) {
$info += array('module' => $module);
}
$all_permissions += $module_permissions;
}
}
// Prepend Mollom's global permission to the list.
array_unshift($mollom_form['bypass access'], 'bypass mollom protection');
$permissions = array();
foreach ($mollom_form['bypass access'] as $permission) {
// @todo D7: Array keys are used as CSS class for the link list item,
// but are not sanitized: http://drupal.org/node/98696
$permissions[drupal_html_class($permission)] = array(
'title' => $all_permissions[$permission]['title'],
'href' => 'admin/people/permissions',
'fragment' => 'module-' . $all_permissions[$permission]['module'],
'html' => TRUE,
);
}
$form['mollom']['mode']['#description'] = t('The protection is omitted for users having any of the permissions: !permission-list', array(
'!permission-list' => theme('links', array(
'links' => $permissions,
// @todo D7: Something went entirely wrong: system.menus.css makes ANY
// ul.links appear as if it would have the .inline CSS class.
'attributes' => array(),
)),
));
// If not re-configuring an existing protection, make it the default.
if (!isset($mollom_form['mode'])) {
$form['mollom']['mode']['#default_value'] = MOLLOM_MODE_ANALYSIS;
}
// Textual analysis filters.
$form['mollom']['checks'] = array(
'#type' => 'checkboxes',
'#title' => t('Text analysis checks'),
'#options' => array(
'spam' => t('Spam'),
'profanity' => t('Profanity'),
),
'#default_value' => $mollom_form['checks'],
'#states' => array(
'visible' => array(
':input[name="mollom[mode]"]' => array('value' => (string) MOLLOM_MODE_ANALYSIS),
),
),
);
// Profanity check requires text to analyze; unlike the spam check, there
// is no fallback in case there is no text.
$form['mollom']['checks']['profanity']['#access'] = !empty($mollom_form['elements']);
// Form elements defined by hook_mollom_form_info() use the
// 'parent][child' syntax, which Form API also uses internally for
// form_set_error(), and which allows us to recurse into nested fields
// during processing of submitted form values. However, since we are using
// those keys also as internal values to configure the fields to use for
// textual analysis, we need to encode them. Otherwise, a nested field key
// would result in the following checkbox attribute:
// '#name' => 'mollom[enabled_fields][parent][child]'
// This would lead to a form validation error, because it is a valid key.
// By encoding them, we prevent this from happening:
// '#name' => 'mollom[enabled_fields][parent%5D%5Bchild]'
$elements = array();
foreach ($mollom_form['elements'] as $key => $value) {
$elements[rawurlencode($key)] = $value;
}
$enabled_fields = array();
foreach ($mollom_form['enabled_fields'] as $value) {
$enabled_fields[] = rawurlencode($value);
}
$form['mollom']['enabled_fields'] = array(
'#type' => 'checkboxes',
'#title' => t('Text fields to analyze'),
'#options' => $elements,
'#default_value' => $enabled_fields,
'#description' => t('Only enable fields that accept text (not numbers). Omit fields that contain sensitive data (e.g., credit card numbers) or computed/auto-generated values, as well as author information fields (e.g., name, e-mail).'),
'#access' => !empty($mollom_form['elements']),
'#states' => array(
'visible' => array(
':input[name="mollom[mode]"]' => array('value' => (string) MOLLOM_MODE_ANALYSIS),
),
),
);
$form['mollom']['strictness'] = array(
'#type' => 'radios',
'#title' => t('Text analysis strictness'),
'#options' => array(
'normal' => t('!option (!recommended)', array(
'!option' => t('Normal'),
'!recommended' => $recommended,
)),
'strict' => t('Strict: Posts are more likely classified as spam'),
'relaxed' => t('Relaxed: Posts are more likely classified as ham'),
),
'#default_value' => $mollom_form['strictness'],
'#states' => array(
'visible' => array(
':input[name="mollom[mode]"]' => array('value' => (string) MOLLOM_MODE_ANALYSIS),
),
),
);
$form['mollom']['unsure'] = array(
'#type' => 'radios',
'#title' => t('When text analysis is unsure'),
'#default_value' => $mollom_form['unsure'],
'#options' => array(
'captcha' => t('!option (!recommended)', array(
'!option' => t('Show a CAPTCHA'),
'!recommended' => $recommended,
)),
'moderate' => t('Retain the post for manual moderation'),
'binary' => t('Accept the post'),
),
'#required' => $mollom_form['mode'] == MOLLOM_MODE_ANALYSIS,
// Only possible for forms protected via text analysis.
'#states' => array(
'visible' => array(
':input[name="mollom[mode]"]' => array('value' => (string) MOLLOM_MODE_ANALYSIS),
':input[name="mollom[checks][spam]"]' => array('checked' => TRUE),
),
),
);
// Only possible for forms supporting moderation of unpublished posts.
$form['mollom']['unsure']['moderate']['#access'] = !empty($mollom_form['moderation callback']);
$form['mollom']['discard'] = array(
'#type' => 'radios',
'#title' => t('When text analysis identifies spam'),
'#default_value' => $mollom_form['discard'],
'#options' => array(
1 => t('!option (!recommended)', array(
'!option' => t('Discard the post'),
'!recommended' => $recommended,
)),
0 => t('!option (!recommended)', array(
'!option' => t('Retain the post for manual moderation'),
'!recommended' => $recommended,
)),
),
'#required' => $mollom_form['mode'] == MOLLOM_MODE_ANALYSIS,
// Only possible for forms supporting moderation of unpublished posts.
'#access' => !empty($mollom_form['moderation callback']),
// Only possible for forms protected via text analysis.
'#states' => array(
'visible' => array(
':input[name="mollom[mode]"]' => array('value' => (string) MOLLOM_MODE_ANALYSIS),
':input[name="mollom[checks][spam]"]' => array('checked' => TRUE),
),
),
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
break;
}
$form['actions']['cancel'] = array(
'#type' => 'link',
'#title' => t('Cancel'),
'#href' => 'admin/config/content/mollom',
);
return $form;
}
/**
* Form submit handler for 'Next' button on Mollom form configuration form.
*/
function mollom_admin_configure_form_next_submit($form, &$form_state) {
$form_id = $form_state['values']['mollom']['form_id'];
$form_state['redirect'] = $_GET['q'] . '/' . $form_id;
}
/**
* Form validation handler for mollom_admin_configure_form().
*/
function mollom_admin_configure_form_validate(&$form, &$form_state) {
// For the 'configure' step, output custom #required form element errors for
// 'checks' and 'enabled_fields', as their labels do not work with the default
// #required form error message.
if ($form_state['storage']['step'] == 'configure') {
// Make field checkboxes required, if protection mode is text analysis.
// @see http://drupal.org/node/875722
$required = ($form_state['values']['mollom']['mode'] == MOLLOM_MODE_ANALYSIS);
$form['mollom']['checks']['#required'] = $required;
$form['mollom']['discard']['#required'] = $required;
if ($required && !array_filter($form_state['values']['mollom']['checks'])) {
form_error($form['mollom']['checks'], t('At least one text analysis check is required.'));
}
}
}
/**
* Form submit handler for mollom_admin_configure_form().
*/
function mollom_admin_configure_form_submit($form, &$form_state) {
$mollom_form = $form_state['values']['mollom'];
// Merge in form information from $form_state.
$mollom_form += $form_state['storage']['mollom_form'];
// Only store a list of enabled textual analysis checks.
$mollom_form['checks'] = array_keys(array_filter($mollom_form['checks']));
// Prepare selected fields for storage.
$enabled_fields = array();
foreach (array_keys(array_filter($mollom_form['enabled_fields'])) as $field) {
$enabled_fields[] = rawurldecode($field);
}
$mollom_form['enabled_fields'] = $enabled_fields;
$status = mollom_form_save($mollom_form);
if ($status === SAVED_NEW) {
drupal_set_message(t('The form protection has been added.'));
}
else {
drupal_set_message(t('The form protection has been updated.'));
}
if (!empty($mollom_form['discard']) && !empty($mollom_form['moderation'])) {
drupal_set_message(t('Spam that is discarded cannot be moderated from the Mollom Content Moderation Platform.'), 'warning');
}
else {
$form_state['redirect'] = 'admin/config/content/mollom';
}
}
/**
* Form builder; Remove Mollom protection from a form.
*/
function mollom_admin_unprotect_form($form, &$form_state, $mollom_form) {
$form['#tree'] = TRUE;
$form['form'] = array(
'#type' => 'item',
'#title' => t('Form'),
'#markup' => $mollom_form['title'],
);
$form['mollom']['form_id'] = array(
'#type' => 'value',
'#value' => $mollom_form['form_id'],
);
return confirm_form($form,
t('Are you sure you want to unprotect this form?'),
'admin/config/content/mollom',
t('Mollom will no longer protect this form from spam.')
);
}
/**
* Form submit handler for mollom_admin_unprotect_form().
*/
function mollom_admin_unprotect_form_submit($form, &$form_state) {
mollom_form_delete($form_state['values']['mollom']['form_id']);
drupal_set_message(t('The form protection has been removed.'));
$form_state['redirect'] = 'admin/config/content/mollom';
}
/**
* Form constructor to configure the blacklist.
*
* @param $type
* The type of blacklist; i.e., 'spam', 'profanity', or 'unwanted'.
*/
function mollom_admin_blacklist_form($form, &$form_state, $type = 'spam') {
$form['#tree'] = TRUE;
$form['#attached']['css'][] = drupal_get_path('module', 'mollom') . '/mollom.admin.css';
// Translate internal reason values for rendering and select list in form.
$contexts = array(
'allFields' => t('- All fields -'),
'author' => t('- All author fields -'),
'authorName' => t('Author name'),
'authorMail' => t('Author e-mail'),
'authorIp' => t('Author IP'),
'authorId' => t('Author User ID'),
'post' => t('- All post fields -'),
'postTitle' => t('Post title'),
'links' => t('Links'),
);
$matches = array(
'contains' => t('contains'),
'exact' => t('exact'),
);
$form['blacklist'] = array();
// Do not retrieve the current blacklist when submitting the form.
$blacklist = (empty($form_state['input']) ? mollom()->getBlacklist() : array());
if (is_array($blacklist)) {
foreach ($blacklist as $entry) {
if ($entry['reason'] != $type) {
continue;
}
$row = array();
// #class property is internally used by
// theme_mollom_admin_blacklist_form().
$row['context'] = array(
'#markup' => check_plain(isset($contexts[$entry['context']]) ? $contexts[$entry['context']] : $entry['context']),
'#class' => 'mollom-blacklist-context value-' . check_plain($entry['context']),
);
$row['match'] = array(
'#markup' => check_plain($matches[$entry['match']]),
'#class' => 'mollom-blacklist-match value-' . check_plain($entry['match']),
);
$row['value'] = array(
'#markup' => check_plain($entry['value']),
'#class' => 'mollom-blacklist-value',
);
$row['actions']['delete'] = array(
'#type' => 'link',
'#title' => t('delete'),
'#href' => 'admin/config/content/mollom/blacklist/delete',
'#options' => array(
'query' => array('id' => $entry['id']) + drupal_get_destination(),
),
);
$form['blacklist'][$entry['id']] = $row;
}
}
$form['entry']['context'] = array(
'#type' => 'select',
'#title' => t('Context'),
'#title_display' => 'invisible',
'#options' => $contexts,
'#required' => TRUE,
'#id' => 'mollom-blacklist-filter-context',
);
$form['entry']['match'] = array(
'#type' => 'select',
'#title' => t('Match'),
'#title_display' => 'invisible',
'#options' => $matches,
'#required' => TRUE,
'#id' => 'mollom-blacklist-filter-match',
);
$form['entry']['value'] = array(
'#type' => 'textfield',
'#title' => t('Value'),
'#title_display' => 'invisible',
'#size' => 40,
'#required' => TRUE,
'#maxlength' => 64,
'#id' => 'mollom-blacklist-filter-value',
'#attributes' => array(
'autocomplete' => 'off',
),
);
$form['entry']['reason'] = array(
'#type' => 'value',
'#value' => $type,
);
$form['entry']['actions'] = array(
'#type' => 'actions',
'#tree' => FALSE,
);
$form['entry']['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Add'),
);
return $form;
}
/**
* Form submit handler to save a text string to the Mollom blacklist.
*/
function mollom_admin_blacklist_form_submit($form, &$form_state) {
$data = array(
'value' => $form_state['values']['entry']['value'],
'context' => $form_state['values']['entry']['context'],
'match' => $form_state['values']['entry']['match'],
'reason' => $form_state['values']['entry']['reason'],
);
$result = mollom()->saveBlacklistEntry($data);
$args = array(
'@value' => $data['value'],
'@context' => $data['context'],
'@match' => $data['match'],
'@reason' => $data['reason'],
);
if (!empty($result['id'])) {
drupal_set_message(t('The entry was added to the blacklist.'));
mollom_log(array(
'message' => 'Added @value (@context, @match) to @reason blacklist.',
'arguments' => $args,
));
}
else {
drupal_set_message(t('An error occurred upon trying to add the value to the blacklist.'), 'error');
mollom_log(array(
'message' => 'Failed to add @value (@context, @match) to @reason blacklist.',
'arguments' => $args,
), WATCHDOG_ERROR);
}
}
/**
* Formats the blacklist form as table to embed the form.
*/
function theme_mollom_admin_blacklist_form($variables) {
$form = $variables['form'];
$header = array(
t('Context'),
t('Matches'),
t('Value'),
'',
);
$rows = array();
$rows[] = array(
drupal_render($form['entry']['context']),
drupal_render($form['entry']['match']),
drupal_render($form['entry']['value']),
drupal_render($form['entry']['actions']),
);
foreach (element_children($form['blacklist']) as $id) {
$rows[] = array(
array(
'data' => drupal_render($form['blacklist'][$id]['context']),
'class' => $form['blacklist'][$id]['context']['#class'],
),
array(
'data' => drupal_render($form['blacklist'][$id]['match']),
'class' => $form['blacklist'][$id]['match']['#class'],
),
array(
'data' => drupal_render($form['blacklist'][$id]['value']),
'class' => $form['blacklist'][$id]['value']['#class'],
),
drupal_render($form['blacklist'][$id]['actions']),
);
}
// This table is never empty due to the form.
$output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'mollom-blacklist')));
$output .= drupal_render_children($form);
drupal_add_js(drupal_get_path('module', 'mollom') . '/mollom.admin.blacklist.js');
return $output;
}
/**
* Form builder; Builds the confirmation form for deleting a blacklist item.
*
* @ingroup forms
* @see mollom_admin_blacklist_delete_submit()
*/
function mollom_admin_blacklist_delete($form, &$form_state) {
$id = $_GET['id'];
if (empty($id) || !($entry = mollom()->getBlacklistEntry($id))) {
drupal_not_found();
return;
}
$form['entry'] = array(
'#type' => 'value',
'#value' => $entry,
);
return confirm_form(
$form,
t('Are you sure you want to delete %value from the blacklist?', array('%value' => $entry['value'])),
'admin/config/content/mollom/blacklist',
t('This action cannot be undone.'),
t('Delete'), t('Cancel')
);
}
/**
* Form submit handler to delete an entry from the blacklist.
*/
function mollom_admin_blacklist_delete_submit($form, &$form_state) {
$result = mollom()->deleteBlacklistEntry($form_state['values']['entry']['id']);
$args = array(
'@value' => $form_state['values']['entry']['value'],
'@context' => $form_state['values']['entry']['context'],
'@reason' => $form_state['values']['entry']['reason'],
);
if ($result === TRUE) {
drupal_set_message(t('The entry was removed from the blacklist.'));
mollom_log(array(
'message' => 'Removed @value (@context) from @reason blacklist.',
'arguments' => $args,
));
}
else {
drupal_set_message(t('An error occurred upon trying to remove the item from the blacklist.'), 'error');
mollom_log(array(
'message' => 'Failed to remove @value (%context) from @reason blacklist.',
'arguments' => $args,
), WATCHDOG_ERROR);
}
$form_state['redirect'] = 'admin/config/content/mollom/blacklist';
}
/**
* Form builder; Global Mollom settings form.
*
* This form does not validate Mollom API keys, since the fallback method still
* needs to be able to be reconfigured in case Mollom services are down.
* mollom.verifyKey would invalidate the keys and throw an error; hence,
* _mollom_fallback() would invoke form_set_error(), effectively preventing this
* form from submitting.
*
* @todo Implement proper form validation now that mollom() no longer triggers
* the fallback mode.
*/
function mollom_admin_settings($form, &$form_state) {
$mollom = mollom();
$check = empty($_POST);
$status = mollom_admin_site_status($check);
if ($check && $status['isVerified'] && !variable_get('mollom_testing_mode', 0)) {
drupal_set_message(t('Mollom servers verified your keys. The services are operating correctly.'));
}
$form['access-keys'] = array(
'#type' => 'fieldset',
'#title' => t('Mollom API keys'),
'#description' => t('To obtain API keys, sign up or log in to your Site manager, register this site, and copy the keys into the fields below.', array(
'@signup-url' => 'https://www.mollom.com/pricing',
'@site-manager-url' => 'https://www.mollom.com/site-manager',
)),
'#collapsible' => TRUE,
// Only show key configuration fields if they are not configured or invalid.
'#collapsed' => !$status['isVerified'],
);
// Keys are not #required to allow to install this module and configure it
// later.
$form['access-keys']['mollom_public_key'] = array(
'#type' => 'textfield',
'#title' => t('Public key'),
'#default_value' => variable_get('mollom_public_key'),
'#element_validate' => array('mollom_admin_settings_validate_key'),
'#description' => t('Used to uniquely identify this site.'),
);
$form['access-keys']['mollom_private_key'] = array(
'#type' => 'textfield',
'#title' => t('Private key'),
'#default_value' => variable_get('mollom_private_key'),
'#element_validate' => array('mollom_admin_settings_validate_key'),
'#description' => t('Used for authentication. Similar to a password, the private key should not be shared with anyone.'),
);
$form['mollom_fallback'] = array(
'#type' => 'radios',
'#title' => t('When the Mollom service is unavailable'),
'#default_value' => variable_get('mollom_fallback', MOLLOM_FALLBACK_ACCEPT),
'#options' => array(
MOLLOM_FALLBACK_ACCEPT => t('Accept all form submissions'),
MOLLOM_FALLBACK_BLOCK => t('Block all form submissions'),
),
'#description' => t('Mollom offers a high-availability infrastructure for users on paid plans to reduce potential downtime.', array(
'@pricing-url' => 'https://www.mollom.com/pricing',
)),
);
$options = _mollom_supported_languages();
$default_languages = array();
if (isset($status['expectedLanguages'])) {
$default_languages = $status['expectedLanguages'];
}
else {
$default_languages = $mollom->loadConfiguration('expectedLanguages');
}
$path = drupal_get_path('module', 'mollom');
$form[$mollom->configuration_map['expectedLanguages']] = array(
'#type' => 'select',
'#title' => t('Expected languages'),
'#options' => $options,
'#multiple' => TRUE,
'#size' => 6,
'#default_value' => $default_languages,
'#description' => t('Restricts all posts to selected languages. Used by text analysis only. Leave empty if users may post in other languages.'),
// Ensure that selected languages are apparent for site administrators and
// not potentially hidden in a large select widget.
'#attributes' => array(
// @see form_process_select()
'data-placeholder' => t('- Empty -'),
'id' => $mollom->configuration_map['expectedLanguages'],
),
'#attached' => array(
'js' => array(
$path . '/mollom.admin.js',
),
),
);
// Add the chosen library if available through the libraries module.
if (module_exists('libraries')) {
if ($path = libraries_get_path('chosen')) {
$form[$mollom->configuration_map['expectedLanguages']]['#attached']['js'][] = $path . '/chosen.jquery.min.js';
$form[$mollom->configuration_map['expectedLanguages']]['#attached']['css'][] = $path . '/chosen.min.css';
}
}
$form['mollom_privacy_link'] = array(
'#type' => 'checkbox',
'#title' => t("Show a link to Mollom's privacy policy"),
'#return_value' => 1,
'#default_value' => variable_get('mollom_privacy_link', 1),
'#description' => t('Only applies to forms protected with text analysis. When disabling this option, you should inform visitors about the privacy of their data through other means.'),
);
$form['mollom_testing_mode'] = array(
'#type' => 'checkbox',
'#title' => t('Enable testing mode'),
'#default_value' => variable_get('mollom_testing_mode', 0),
'#description' => t('Submitting "ham", "unsure", or "spam" triggers the corresponding behavior; image CAPTCHAs only respond to "correct" and audio CAPTCHAs only respond to "demo". Do not enable this option if this site is publicly accessible.'),
);
$form['mollom_advanced'] = array(
'#type' => 'fieldset',
'#title' => t('Advanced configuration'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
// Lower severity numbers indicate a high severity level.
$min_severity = variable_get('mollom_log_minimum_severity', WATCHDOG_WARNING);
$form['mollom_advanced']['mollom_log_minimum_severity'] = array(
'#type' => 'radios',
'#title' => t('Mollom logging level warning'),
'#options' => array(
WATCHDOG_WARNING => t('Only log warnings and errors'),
WATCHDOG_DEBUG => t('Log all Mollom messages'),
),
'#default_value' => $min_severity <= WATCHDOG_WARNING ? WATCHDOG_WARNING : WATCHDOG_DEBUG,
);
$form['mollom_advanced']['mollom_audio_captcha_enabled'] = array(
'#type' => 'checkbox',
'#title' => t('Enable audio CAPTCHAs.'),
'#description' => t('Allows users to switch to an audio verification using the NATO alphabet. This may not be appropriate for non-English language sites.', array(
'!faq-url' => 'https://www.mollom.com/faq/mollom-audible-captcha-language',
)),
'#default_value' => variable_get('mollom_audio_captcha_enabled', 1),
);
$form['mollom_advanced']['mollom_connection_timeout'] = array(
'#type' => 'textfield',
'#title' => t('Time-out when attempting to contact Mollom servers.'),
'#description' => t('This is the length of time that a call to Mollom will wait before timing out.'),
'#default_value' => variable_get('mollom_connection_timeout', 3),
'#size' => 5,
'#field_suffix' => t('seconds'),
'#required' => TRUE,
);
$form['mollom_advanced']['mollom_fba_enabled'] = array(
'#type' => 'checkbox',
'#title' => t('Enable form behavior analysis (beta).'),
'#description' => t('This will place a small tracking image from Mollom on each form protected by textural analysis to help Mollom determine if the form is filled out by a bot. Learn more.', array(
'!fba-url' => 'https://www.mollom.com/faq/form-behavior-analysis',
)),
'#default_value' => variable_get('mollom_fba_enabled', 0),
);
// Available entity types are those entities that have a report access
// callback defined. This is limited by type even though multiple forms
// can be for the same entity type.
$forms = mollom_form_list();
$options = array();
foreach($forms as $info) {
if (!empty($info['entity']) && !empty($info['entity report access callback'])) {
$options[] = $info['entity'];
}
};
sort($options);
$form['mollom_advanced']['mollom_fai_entity_types'] = array(
'#type' => 'checkboxes',
'#title' => t('Allow users to "Flag as Inappropriate" for the following:'),
'#description' => t('"Flag as inappropriate" will only appear on protected forms for users who have permission to the content type and have the permission to "Report to Mollom". Learn more.', array(
'!fai-url' => 'https://www.mollom.com/faq/flag-as-inappropriate',
)),
'#options' => drupal_map_assoc($options),
'#default_value' => variable_get('mollom_fai_entity_types', array('comment' => 'comment')),
);
// Only display dialog options if the user has at least one integrated
// module installed and enabled.
module_load_include('inc', 'mollom', 'mollom.flag');
$implemented = mollom_flag_dialog_info();
$available = array_intersect_key($implemented, module_list());
$options = array();
foreach($available as $module => $info) {
$options[$module] = $info['title'];
}
if (count($options) > 0) {
$options['mollom'] = 'Mollom custom dialog';
$form['mollom_advanced']['mollom_fai_dialog'] = array(
'#type' => 'radios',
'#title' => t('Flag as inappropriate dialog type'),
'#options' => $options,
'#default_value' => variable_get('mollom_fai_dialog', 'mollom'),
);
}
else {
// Reset to use the Mollom dialog if no integrated modules are available.
$form['mollom_advanced']['mollom_fai_dialog'] = array(
'#type' => 'value',
'#value' => 'mollom',
);
}
$form['#submit'][] = 'mollom_admin_settings_prepare_submit';
$form = system_settings_form($form);
$form['#submit'][] = 'mollom_admin_settings_submit';
return $form;
}
/**
* Element validation handler for API key text fields.
*/
function mollom_admin_settings_validate_key($element, &$form_state) {
if ($element['#value'] !== '') {
// Remove any leading/trailing white-space and override submitted value.
$element['#value'] = trim($element['#value']);
form_set_value($element, $element['#value'], $form_state);
// Verify the key has a length of 32 characters.
if (drupal_strlen($element['#value']) != 32) {
form_error($element, t('!title must be 32 characters. Ensure you copied the key correctly.', array(
'!title' => $element['#title'],
)));
}
}
}
/**
* Form submission handler for global settings form.
*/
function mollom_admin_settings_prepare_submit($form, &$form_state) {
// If the minimum log severity checkbox was disabled (no input), convert
// 0 into WATCHDOG_DEBUG.
if (!isset($form_state['input']['mollom_log_minimum_severity'])) {
$form_state['values']['mollom_log_minimum_severity'] = WATCHDOG_DEBUG;
}
}
/**
* Form submission handler for global settings form.
*/
function mollom_admin_settings_submit($form, &$form_state) {
// Update Mollom site record with local configuration.
_mollom_status(TRUE, TRUE);
}
/**
* Menu callback; Displays the administrative reports page.
*/
function mollom_reports_page($form, &$form_state) {
$embed_attributes = array(
'src' => 'https://www.mollom.com/statistics.swf?key=' . check_plain(variable_get('mollom_public_key', '')),
'quality' => 'high',
'width' => '100%',
'height' => '430',
'name' => 'Mollom',
'align' => 'middle',
'play' => 'true',
'loop' => 'false',
'allowScriptAccess' => 'sameDomain',
'type' => 'application/x-shockwave-flash',
'pluginspage' => 'http://www.adobe.com/go/getflashplayer',
'wmode' => 'transparent',
);
$form['chart'] = array(
'#type' => 'item',
'#title' => t('Statistics'),
'#markup' => '',
);
return $form;
}