From 99104bb27e1394adf083be9d521f59b96c1ec34c Mon Sep 17 00:00:00 2001
From: Gergely Lekli <gl90010@930940.no-reply.drupal.org>
Date: Wed, 9 Sep 2015 17:10:15 -0700
Subject: [PATCH] Implement whitelists.

---
 includes/mollom.class.inc | 103 +++++++++++++++++++++++
 mollom.admin.css          |   2 +
 mollom.admin.inc          | 206 ++++++++++++++++++++++++++++++++++++++++++++++
 mollom.module             |  23 ++++++
 4 files changed, 334 insertions(+)

diff --git a/includes/mollom.class.inc b/includes/mollom.class.inc
index a72103e..b9c1782 100644
--- a/includes/mollom.class.inc
+++ b/includes/mollom.class.inc
@@ -1338,6 +1338,109 @@ abstract class Mollom {
   }
 
   /**
+   * Retrieves the whitelist for a site.
+   *
+   * @param string $publicKey
+   *   (optional) The public Mollom API key of the site to retrieve the
+   *   whitelist for. Defaults to the public key of the client.
+   *
+   * @return mixed
+   *   An array containing whitelist entries; see Mollom::getWhitelistEntry()
+   *   for details. On failure, the error response code returned by the server.
+   *
+   * @todo List parameters.
+   */
+  public function getWhitelist($publicKey = NULL) {
+    if (!isset($publicKey)) {
+      $publicKey = $this->publicKey;
+    }
+    $publicKey = rawurlencode($publicKey);
+    $result = $this->query('GET', 'whitelist/' . $publicKey, array(), array('list'));
+    return isset($result['list']) ? $result['list'] : $result;
+  }
+
+  /**
+   * Creates or updates a whitelist entry for a site.
+   *
+   * @param array $data
+   *   An associative array describing the whitelist entry to create or update.
+   *   See return value of Mollom::getWhitelistEntry() for details. To update
+   *   an existing entry, its ID must be specified in 'id'.
+   * @param string $publicKey
+   *   (optional) The public Mollom API key of the site to save the whitelist
+   *   entry for. Defaults to the public key of the client.
+   *
+   * @return mixed
+   *   On success, the full whitelist entry record of the saved entry; see
+   *   Mollom::getWhitelistEntry() for details. On failure, the error response
+   *   code returned by the server.
+   */
+  public function saveWhitelistEntry(array $data = array(), $publicKey = NULL) {
+    if (!isset($publicKey)) {
+      $publicKey = $this->publicKey;
+    }
+    $path = 'whitelist/' . rawurlencode($publicKey);
+    if (!empty($data['id'])) {
+      $path .= '/' . rawurlencode($data['id']);
+      unset($data['id']);
+    }
+    $result = $this->query('POST', $path, $data, array('entry', 'id'));
+    return isset($result['entry']) ? $result['entry'] : $result;
+  }
+
+  /**
+   * Retrieves a whitelist entry stored for a site.
+   *
+   * @param string $entryId
+   *   The ID of the whitelist entry to retrieve.
+   * @param string $publicKey
+   *   (optional) The public Mollom API key of the site to retrieve the
+   *   whitelist entry for. Defaults to the public key of the client.
+   *
+   * @return mixed
+   *   On success, an associative array containing:
+   *   - id: The ID the of whitelist entry.
+   *   - created: A timestamp in seconds since the UNIX epoch of when the entry
+   *     was created.
+   *   - value: The whitelisted string/value.
+   *   - context: A string denoting where the entry's value may match.
+   *   - status: An integer denoting whether the entry is enabled (1) or not
+   *     (0).
+   *   - note: A custom string explaining the entry. Useful in a multi-moderator
+   *     scenario.
+   *   On failure, the error response code returned by the server.
+   */
+  public function getWhitelistEntry($entryId, $publicKey = NULL) {
+    if (!isset($publicKey)) {
+      $publicKey = $this->publicKey;
+    }
+    $path = 'whitelist/' . rawurlencode($publicKey) . '/' . rawurlencode($entryId);
+    $result = $this->query('GET', $path, array(), array('entry', 'id'));
+    return isset($result['entry']) ? $result['entry'] : $result;
+  }
+
+  /**
+   * Deletes a whitelist entry from a site.
+   *
+   * @param string $entryId
+   *   The ID of the whitelist entry to delete.
+   * @param string $publicKey
+   *   (optional) The public Mollom API key of the site to create the whitelist
+   *   entry for. Defaults to the public key of the client.
+   *
+   * @return bool
+   *   TRUE on success, FALSE otherwise.
+   */
+  public function deleteWhitelistEntry($entryId, $publicKey = NULL) {
+    if (!isset($publicKey)) {
+      $publicKey = $this->publicKey;
+    }
+    $path = 'whitelist/' . rawurlencode($publicKey) . '/' . rawurlencode($entryId) . '/delete';
+    $result = $this->query('POST', $path);
+    return $this->lastResponseCode === TRUE;
+  }
+
+  /**
    * Retrieves the blacklist for a site.
    *
    * @param string $publicKey
diff --git a/mollom.admin.css b/mollom.admin.css
index 7dddc75..6029890 100644
--- a/mollom.admin.css
+++ b/mollom.admin.css
@@ -6,6 +6,8 @@
  * buttons, which adds too much vertical spacing to the first table row in the
  * blacklist table.
  */
+#mollom-whitelist .form-actions,
+#mollom-whitelist .form-submit,
 #mollom-blacklist .form-actions,
 #mollom-blacklist .form-submit {
   margin: 0;
diff --git a/mollom.admin.inc b/mollom.admin.inc
index 29b72f8..2dfd83f 100644
--- a/mollom.admin.inc
+++ b/mollom.admin.inc
@@ -608,6 +608,173 @@ function mollom_admin_unprotect_form_submit($form, &$form_state) {
 }
 
 /**
+ * Form constructor to configure the whitelist.
+ */
+function mollom_admin_whitelist_form($form, &$form_state) {
+  $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(
+    'authorIp' => t('Author IP'),
+    'authorId' => t('Author User ID'),
+    'authorName' => t('Author name'),
+    'authorMail' => t('Author e-mail'),
+  );
+
+  $form['whitelist'] = array();
+  // Do not retrieve the current whitelist when submitting the form.
+  $whitelist = (empty($form_state['input']) ? mollom()->getWhitelist() : array());
+  if (is_array($whitelist)) {
+    foreach ($whitelist as $entry) {
+      $row = array();
+      // #class property is internally used by
+      // theme_mollom_admin_whitelist_form().
+      $row['context'] = array(
+        '#markup' => check_plain(isset($contexts[$entry['context']]) ? $contexts[$entry['context']] : $entry['context']),
+        '#class' => 'mollom-whitelist-context value-' . check_plain($entry['context']),
+      );
+      $row['value'] = array(
+        '#markup' => check_plain($entry['value']),
+        '#class' => 'mollom-whitelist-value',
+      );
+      $row['actions']['delete'] = array(
+        '#type' => 'link',
+        '#title' => t('delete'),
+        '#href' => 'admin/config/content/mollom/whitelist/delete',
+        '#options' => array(
+          'query' => array('id' => $entry['id']) + drupal_get_destination(),
+        ),
+      );
+      $form['whitelist'][$entry['id']] = $row;
+    }
+  }
+
+  $form['entry']['context'] = array(
+    '#type' => 'select',
+    '#title' => t('Context'),
+    '#title_display' => 'invisible',
+    '#options' => $contexts,
+    '#required' => TRUE,
+    '#id' => 'mollom-whitelist-filter-context',
+  );
+  $form['entry']['value'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Value'),
+    '#title_display' => 'invisible',
+    '#size' => 40,
+    '#required' => TRUE,
+    '#maxlength' => 64,
+    '#id' => 'mollom-whitelist-filter-value',
+    '#attributes' => array(
+      'autocomplete' => 'off',
+    ),
+  );
+  $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 whitelist.
+ */
+function mollom_admin_whitelist_form_submit($form, &$form_state) {
+  $data = array(
+    'value' => $form_state['values']['entry']['value'],
+    'context' => $form_state['values']['entry']['context'],
+  );
+  $result = mollom()->saveWhitelistEntry($data);
+
+  $args = array(
+    '@value' => $data['value'],
+    '@context' => $data['context'],
+  );
+
+  if (!empty($result['id'])) {
+    drupal_set_message(t('The entry was added to the whitelist.'));
+    mollom_log(array(
+      'message' => 'Added @value (@context) to whitelist.',
+      'arguments' => $args,
+    ));
+  }
+  else {
+    drupal_set_message(t('An error occurred upon trying to add the value to the whitelist.'), 'error');
+    mollom_log(array(
+      'message' => 'Failed to add @value (@context) to whitelist.',
+      'arguments' => $args,
+    ), WATCHDOG_ERROR);
+  }
+}
+
+/**
+ * Form builder; Builds the confirmation form for deleting a whitelist item.
+ *
+ * @ingroup forms
+ * @see mollom_admin_whitelist_delete_submit()
+ */
+function mollom_admin_whitelist_delete($form, &$form_state) {
+  if (empty($_GET['id'])) {
+    drupal_not_found();
+    return;
+  }
+
+  $entry = mollom()->getWhitelistEntry($_GET['id']);
+  if (!is_array($entry)) {
+    // The api returned an error code.
+    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 whitelist?', array('%value' => $entry['value'])),
+    'admin/config/content/mollom/whitelist',
+    t('This action cannot be undone.'),
+    t('Delete'), t('Cancel')
+  );
+}
+
+/**
+ * Form submit handler to delete an entry from the whitelist.
+ */
+function mollom_admin_whitelist_delete_submit($form, &$form_state) {
+  $result = mollom()->deleteWhitelistEntry($form_state['values']['entry']['id']);
+
+  $args = array(
+    '@value' => $form_state['values']['entry']['value'],
+    '@context' => $form_state['values']['entry']['context'],
+  );
+  if ($result === TRUE) {
+    drupal_set_message(t('The entry was removed from the whitelist.'));
+    mollom_log(array(
+      'message' => 'Removed @value (@context) from the whitelist.',
+      'arguments' => $args,
+    ));
+  }
+  else {
+    drupal_set_message(t('An error occurred upon trying to remove the item from the whitelist.'), 'error');
+    mollom_log(array(
+      'message' => 'Failed to remove @value (@context) from the whitelist.',
+      'arguments' => $args,
+    ), WATCHDOG_ERROR);
+  }
+
+  $form_state['redirect'] = 'admin/config/content/mollom/whitelist';
+}
+
+/**
  * Form constructor to configure the blacklist.
  *
  * @param $type
@@ -748,6 +915,45 @@ function mollom_admin_blacklist_form_submit($form, &$form_state) {
 }
 
 /**
+ * Formats the whitelist form as table to embed the form.
+ */
+function theme_mollom_admin_whitelist_form($variables) {
+  $form = $variables['form'];
+  $header = array(
+    t('Context'),
+    t('Value'),
+    '',
+  );
+  $rows = array();
+
+  $rows[] = array(
+    drupal_render($form['entry']['context']),
+    drupal_render($form['entry']['value']),
+    drupal_render($form['entry']['actions']),
+  );
+
+  foreach (element_children($form['whitelist']) as $id) {
+    $rows[] = array(
+      array(
+        'data' => drupal_render($form['whitelist'][$id]['context']),
+        'class' => $form['whitelist'][$id]['context']['#class'],
+      ),
+      array(
+        'data' => drupal_render($form['whitelist'][$id]['value']),
+        'class' => $form['whitelist'][$id]['value']['#class'],
+      ),
+      drupal_render($form['whitelist'][$id]['actions']),
+    );
+  }
+
+  // This table is never empty due to the form.
+  $output  = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'mollom-whitelist')));
+  $output .= drupal_render_children($form);
+
+  return $output;
+}
+
+/**
  * Formats the blacklist form as table to embed the form.
  */
 function theme_mollom_admin_blacklist_form($variables) {
diff --git a/mollom.module b/mollom.module
index 21e0bfd..95efa0c 100644
--- a/mollom.module
+++ b/mollom.module
@@ -213,6 +213,25 @@ function mollom_menu() {
     'access arguments' => array('administer mollom'),
     'file' => 'mollom.admin.inc',
   );
+  $items['admin/config/content/mollom/whitelist'] = array(
+    'title' => 'Whitelist',
+    'description' => 'Configure whitelist.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('mollom_admin_whitelist_form'),
+    'access callback' => '_mollom_access',
+    'access arguments' => array('administer mollom'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'mollom.admin.inc',
+  );
+  $items['admin/config/content/mollom/whitelist/delete'] = array(
+    'title' => 'Delete whitelist entry',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('mollom_admin_whitelist_delete'),
+    'access callback' => '_mollom_access',
+    'access arguments' => array('administer mollom'),
+    'type' => MENU_CALLBACK,
+    'file' => 'mollom.admin.inc',
+  );
   $items['admin/config/content/mollom/blacklist'] = array(
     'title' => 'Blacklists',
     'description' => 'Configure blacklists.',
@@ -1768,6 +1787,10 @@ function mollom_element_info() {
 function mollom_theme() {
   $base_path = base_path() . drupal_get_path('module', 'mollom');
   return array(
+    'mollom_admin_whitelist_form' => array(
+      'render element' => 'form',
+      'file' => 'mollom.admin.inc',
+    ),
     'mollom_admin_blacklist_form' => array(
       'render element' => 'form',
       'file' => 'mollom.admin.inc',
-- 
2.3.2 (Apple Git-55)

