Adds tool to search in nl archives (Closes #664).
authorStéphane Jacob <sj@m4x.org>
Mon, 14 Mar 2011 10:10:42 +0000 (11:10 +0100)
committerStéphane Jacob <sj@m4x.org>
Mon, 14 Mar 2011 13:41:49 +0000 (14:41 +0100)
Signed-off-by: Stéphane Jacob <sj@m4x.org>
ChangeLog
include/newsletter.inc.php
modules/axletter.php
modules/epletter.php
modules/newsletter.php
modules/xnetnl.php
templates/newsletter/index.tpl
templates/newsletter/search.tpl [new file with mode: 0644]

index 8d90d6c..db63ff6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -14,6 +14,7 @@ Bug/Wish:
         - #1404: Implements best_domain                                    -JAC
 
     * Newsletter:
+        - #664: Adds tool to search in nl archives                         -JAC
         - #908: Displays remaining lines and characters in submission      -JAC
 
     * Payments:
index 0ee1423..7675813 100644 (file)
@@ -47,6 +47,11 @@ class NewsLetter
     const GROUP_AX = 'AX';
     const GROUP_EP = 'Ecole';
 
+    // Searches on mutiple fields
+    const SEARCH_ALL = 'all';
+    const SEARCH_TITLE = 'title';
+
+
     // {{{ Constructor, NewsLetter retrieval (forGroup, getAll)
 
     public function __construct($id)
@@ -251,6 +256,63 @@ class NewsLetter
         }
     }
 
+    /** Returns a list of either issues or articles corresponding to the search.
+     * @p $search The searched pattern.
+     * @p $field The fields where to search, if none given, search in all possible fields.
+     * @return The list of object found.
+     */
+    public function issueSearch($search, $field, $user)
+    {
+        $search = XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $search);
+        if ($field == self::SEARCH_ALL) {
+            $where = '(title ' . $search . ' OR mail_title ' . $search . ' OR head ' . $search . ' OR signature ' . $search . ')';
+        } elseif ($field == self::SEARCH_TITLE) {
+            $where = '(title ' . $search . ' OR mail_title ' . $search . ')';
+        } else {
+            $where = $field . $search;
+        }
+        $list = XDB::fetchColumn('SELECT  DISTINCT(id)
+                                    FROM  newsletter_issues
+                                   WHERE  nlid = {?} AND state = \'sent\' AND ' . $where . '
+                                ORDER BY  date DESC',
+                                 $this->id);
+
+        $issues = array();
+        foreach ($list as $id) {
+            $issue = new NLIssue($id, $this, false);
+            if ($issue->checkUser($user)) {
+                $issues[] = $issue;
+            }
+        }
+        return $issues;
+    }
+
+    public function articleSearch($search, $field, $user)
+    {
+        $search = XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $search);
+        if ($field == self::SEARCH_ALL) {
+            $where = '(a.title ' . $search . ' OR a.body ' . $search . ' OR a.append ' . $search . ')';
+        } else {
+            $where = 'a.' . $field . $search;
+        }
+        $list = XDB::fetchAllAssoc('SELECT  i.short_name, a.aid, i.id, a.title
+                                      FROM  newsletter_art    AS a
+                                INNER JOIN  newsletter_issues AS i ON (a.id = i.id)
+                                     WHERE  i.nlid = {?} AND i.state = \'sent\' AND ' . $where . '
+                                  GROUP BY  a.id, a.aid
+                                  ORDER BY  i.date DESC, a.aid',
+                                   $this->id);
+
+        $articles = array();
+        foreach ($list as $item) {
+            $issue = new NLIssue($item['id'], $this, false);
+            if ($issue->checkUser($user)) {
+                $articles[] = $item;
+            }
+        }
+        return $articles;
+    }
+
     // }}}
     // {{{ Subscription related function
 
index 9ffb0e3..99d45ad 100644 (file)
@@ -29,6 +29,7 @@ class AXLetterModule extends NewsletterModule
             'ax'                   => $this->make_hook('nl',  AUTH_COOKIE),
             'ax/out'               => $this->make_hook('out',    AUTH_PUBLIC),
             'ax/show'              => $this->make_hook('nl_show',   AUTH_COOKIE),
+            'ax/search'            => $this->make_hook('nl_search', AUTH_COOKIE),
             'ax/admin'             => $this->make_hook('admin_nl', AUTH_MDP),
             'ax/admin/edit'        => $this->make_hook('admin_nl_edit', AUTH_MDP),
             'ax/admin/edit/valid'  => $this->make_hook('admin_nl_valid', AUTH_MDP),
index 285242e..af633f8 100644 (file)
@@ -29,6 +29,7 @@ class EPLetterModule extends NewsletterModule
             'epletter'                   => $this->make_hook('nl',  AUTH_COOKIE),
             'epletter/out'               => $this->make_hook('out',    AUTH_PUBLIC),
             'epletter/show'              => $this->make_hook('nl_show',   AUTH_COOKIE),
+            'epletter/search'            => $this->make_hook('nl_search', AUTH_COOKIE),
             'epletter/admin'             => $this->make_hook('admin_nl', AUTH_MDP),
             'epletter/admin/edit'        => $this->make_hook('admin_nl_edit', AUTH_MDP),
             'epletter/admin/edit/valid'  => $this->make_hook('admin_nl_valid', AUTH_MDP),
index 632f375..7691cae 100644 (file)
@@ -26,6 +26,7 @@ class NewsletterModule extends PLModule
         return array(
             'nl'                           => $this->make_hook('nl',              AUTH_COOKIE),
             'nl/show'                      => $this->make_hook('nl_show',         AUTH_COOKIE),
+            'nl/search'                    => $this->make_hook('nl_search',       AUTH_COOKIE),
             'nl/submit'                    => $this->make_hook('nl_submit',       AUTH_MDP),
             'nl/remaining'                 => $this->make_hook('nl_remaining',    AUTH_MDP),
             'admin/nls'                    => $this->make_hook('admin_nl_groups', AUTH_MDP, 'admin'),
@@ -92,6 +93,55 @@ class NewsletterModule extends PLModule
         }
     }
 
+    function handler_nl_search($page)
+    {
+        S::assert_xsrf_token();
+        $nl = $this->getNl();
+        if (!$nl) {
+            return PL_NOT_FOUND;
+        }
+
+        if (!Post::has('nl_search')) {
+            pl_redirect($nl->prefix());
+        }
+
+        $nl_search = Post::t('nl_search');
+        $nl_search_type = Post::t('nl_search_type');
+        if (!$nl_search || !($nl_search_type > 0 && $nl_search_type < 10)) {
+            $page->trigErrorRedirect('La recherche est vide ou erronée.', $nl->prefix());
+        }
+
+        $page->changeTpl('newsletter/search.tpl');
+        $user = S::user();
+        $fields = array(1 => 'all', 2 => 'all', 3 => 'title', 4 => 'body', 5 => 'append', 6 => 'all', 7 => 'title', 8 => 'head', 9 => 'signature');
+        $res_articles = $res_issues = array();
+        if ($nl_search_type < 6) {
+            $res_articles = $nl->articleSearch($nl_search, $fields[$nl_search_type], $user);
+        }
+        if ($nl_search_type > 5 || $nl_search_type == 1) {
+            $res_issues = $nl->issueSearch($nl_search, $fields[$nl_search_type], $user);
+        }
+
+        $articles_count = count($res_articles);
+        $issues_count = count($res_issues);
+        $results_count = $articles_count + $issues_count;
+        if ($results_count > 200) {
+            $page->trigError('Recherche trop générale.');
+        } elseif ($results_count == 0) {
+            $page->trigWarning('Aucun résultat pour cette recherche.');
+        } else {
+            $page->assign('res_articles', $res_articles);
+            $page->assign('res_issues', $res_issues);
+            $page->assign('articles_count', $articles_count);
+            $page->assign('issues_count', $issues_count);
+        }
+
+        $page->assign_by_ref('nl', $nl);
+        $page->assign('nl_search', $nl_search);
+        $page->assign('nl_search_type', $nl_search_type);
+        $page->assign('results_count', $results_count);
+    }
+
     function handler_nl_submit($page)
     {
         $page->changeTpl('newsletter/submit.tpl');
index aa769be..a5a25ed 100644 (file)
@@ -28,6 +28,7 @@ class XnetNlModule extends NewsletterModule
         return array(
             '%grp/nl'                   => $this->make_hook('nl',                    AUTH_MDP),
             '%grp/nl/show'              => $this->make_hook('nl_show',               AUTH_MDP),
+            '%grp/nl/search'            => $this->make_hook('nl_search',             AUTH_MDP),
             '%grp/admin/nl'             => $this->make_hook('admin_nl',              AUTH_MDP,    'groupadmin'),
             '%grp/admin/nl/edit'        => $this->make_hook('admin_nl_edit',         AUTH_MDP,    'groupadmin'),
             '%grp/admin/nl/edit/cancel' => $this->make_hook('admin_nl_cancel',       AUTH_MDP,    'groupadmin'),
index 1978e44..990722c 100644 (file)
@@ -52,6 +52,8 @@ Tu n'es actuellement pas inscrit à la {$nl->name}.
 </div>
 {/if}
 
+{include file="newsletter/search.tpl" nl_search_type="1" nl_search=""}
+
 <h2>Les archives</h2>
 
 <table class="bicol" cellpadding="3" cellspacing="0" summary="liste des NL">
diff --git a/templates/newsletter/search.tpl b/templates/newsletter/search.tpl
new file mode 100644 (file)
index 0000000..445f7d7
--- /dev/null
@@ -0,0 +1,79 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2011 Polytechnique.org                             *}
+{*  http://opensource.polytechnique.org/                                  *}
+{*                                                                        *}
+{*  This program is free software; you can redistribute it and/or modify  *}
+{*  it under the terms of the GNU General Public License as published by  *}
+{*  the Free Software Foundation; either version 2 of the License, or     *}
+{*  (at your option) any later version.                                   *}
+{*                                                                        *}
+{*  This program is distributed in the hope that it will be useful,       *}
+{*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *}
+{*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *}
+{*  GNU General Public License for more details.                          *}
+{*                                                                        *}
+{*  You should have received a copy of the GNU General Public License     *}
+{*  along with this program; if not, write to the Free Software           *}
+{*  Foundation, Inc.,                                                     *}
+{*  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA               *}
+{*                                                                        *}
+{**************************************************************************}
+
+{if $nl_search}
+<h1>
+  {$nl->name}
+</h1>
+{/if}
+
+<h2>Rechercher dans les archives</h2>
+
+<form action="{$nl->prefix()}/search" method="post">
+  {xsrf_token_field}
+  <p>
+  <select name="nl_search_type">
+    <optgroup label="Recherche gobale">
+      <option value="1" {if $nl_search_type eq 1}selected="selected"{/if}>N'importe où dans les lettres</option>
+    </optgroup>
+    <optgroup label="Recherche dans les articles">
+      <option value="2" {if $nl_search_type eq 2}selected="selected"{/if}>N'importe où dans les articles</option>
+      <option value="3" {if $nl_search_type eq 3}selected="selected"{/if}>Dans les titres des articles</option>
+      <option value="4" {if $nl_search_type eq 4}selected="selected"{/if}>Dans les corps des articles</option>
+      <option value="5" {if $nl_search_type eq 5}selected="selected"{/if}>Dans les appendices des articles</option>
+    </optgroup>
+    <optgroup label="Recherche dans le reste des lettres">
+      <option value="6" {if $nl_search_type eq 6}selected="selected"{/if}>N'importe où dans le reste des lettres</option>
+      <option value="7" {if $nl_search_type eq 7}selected="selected"{/if}>Dans les titres des emails/lettres</option>
+      <option value="8" {if $nl_search_type eq 8}selected="selected"{/if}>Dans les chapeaux/contenus des lettres</option>
+      <option value="9" {if $nl_search_type eq 9}selected="selected"{/if}>Dans les signatures des lettres</option>
+    </optgroup>
+  </select>
+  <input type="text" name="nl_search" value="{$nl_search}" />
+  </p>
+  <p class="center"><input type="submit" value="Chercher" /></p>
+</form>
+
+{if $nl_search}
+<h2>{$results_count} résultat{if $results_count > 1}s{/if} pour cette recherche</h2>
+
+{if t($res_articles) && $res_articles|@count}
+{$articles_count} article{if $articles_count > 1}s{/if} correspondant{if $articles_count > 1}s{/if}&nbsp;:
+<ul>
+  {foreach from=$res_articles item=article}
+  <li><a href="{$nl->prefix()}/show/{$article.short_name}#art{$article.aid}">{$article.title|default:"[Sans titre]"}</a></li>
+  {/foreach}
+</ul>
+{/if}
+
+{if t($res_issues) && $res_issues|@count}
+{$issues_count} lettre{if $issues_count > 1}s{/if} correspondate{if $issues_count > 1}s{/if}&nbsp;:
+<ul>
+  {foreach from=$res_issues item=issue}
+  <li><a href="{$nl->prefix()}/show/{$issue->id()}">{$issue->title()|default:"[Sans titre]"}</a></li>
+  {/foreach}
+</ul>
+{/if}
+
+{/if}
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}