Fixes display of non-users in aliases.
[platal.git] / include / newsletter.inc.php
index da97493..623121f 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)
@@ -174,7 +179,7 @@ class NewsLetter
             }
         }
 
-        return new NLIssue($id, &$this);
+        return new NLIssue($id, $this);
     }
 
     /** Create a new, empty, pending newsletter issue
@@ -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
 
@@ -433,7 +495,7 @@ class NewsLetter
     /** Get the prefix leading to the page for this NL
      * Only X.org / AX / X groups may be seen on X.org.
      */
-    public function prefix()
+    public function prefix($enforce_xnet=true)
     {
         if (!empty($GLOBALS['IS_XNET_SITE'])) {
             return $this->group . '/nl';
@@ -447,13 +509,13 @@ class NewsLetter
             return 'epletter';
         default:
             // Don't display groups NLs on X.org
-            assert(false);
+            assert(!$enforce_xnet);
         }
     }
 
     /** Get the prefix to use for all 'admin' pages of this NL.
      */
-    public function adminPrefix()
+    public function adminPrefix($enforce_xnet=true)
     {
         if (!empty($GLOBALS['IS_XNET_SITE'])) {
             return $this->group . '/admin/nl';
@@ -467,7 +529,7 @@ class NewsLetter
             return 'epletter/admin';
         default:
             // Don't display groups NLs on X.org
-            assert(false);
+            assert(!$enforce_xnet);
         }
     }
 
@@ -558,6 +620,7 @@ class NLIssue
             $this->nl = new NewsLetter($issue['nlid']);
         }
         $this->id = $id;
+        $this->nlid        = $issue['nlid'];
         $this->shortname   = $issue['short_name'];
         $this->date        = $issue['date'];
         $this->send_before = $issue['send_before'];
@@ -666,6 +729,11 @@ class NLIssue
                                       WHERE  id = {?}',
                                       $this->id);
             if ($success) {
+                global $globals;
+                $mailer = new PlMailer('newsletter/notify_scheduled.mail.tpl');
+                $mailer->assign('issue', $this);
+                $mailer->assign('base', $globals->baseurl);
+                $mailer->send();
                 $this->refresh();
             }
             return $success;
@@ -681,7 +749,7 @@ class NLIssue
     {
         if ($this->state == self::STATE_PENDING) {
             $success = XDB::execute('UPDATE  newsletter_issues
-                                        SET  send_before = NULL, state = \'new\'
+                                        SET  state = \'new\'
                                       WHERE  id = {?}', $this->id);
             if ($success) {
                 $this->refresh();
@@ -761,6 +829,7 @@ class NLIssue
 
     const ERROR_INVALID_SHORTNAME = 'invalid_shortname';
     const ERROR_INVALID_UFC = 'invalid_ufc';
+    const ERROR_TOO_LONG_UFC = 'too_long_ufc';
     const ERROR_SQL_SAVE = 'sql_error';
 
     /** Save the global properties of this NL issue (title&co).
@@ -786,6 +855,11 @@ class NLIssue
             }
             if ($this->sufb->isValid() || $this->sufb->isEmpty()) {
                 $fields['sufb_json'] = json_encode($this->sufb->export()->dict());
+                // If sufb_json is too long to be store, we do not store a truncated json and notify the user.
+                // The limit is LONGTEXT's one, ie 2^32 = 4294967296.
+                if (strlen($fields['sufb_json']) > 4294967295) {
+                    $errors[] = self::ERROR_TOO_LONG_UFC;
+                }
             } else {
                 $errors[] = self::ERROR_INVALID_UFC;
             }
@@ -831,9 +905,9 @@ class NLIssue
     }
 
     /** Save an article
-     * @p &$a A reference to a NLArticle object (will be modified once saved)
+     * @p $a A reference to a NLArticle object (will be modified once saved)
      */
-    public function saveArticle(&$a)
+    public function saveArticle($a)
     {
         $this->fetchArticles();
 
@@ -927,7 +1001,7 @@ class NLIssue
      * @p $page Smarty object
      * @return Either 'true' (if CSS was added to a page) or the raw CSS to add (when $page is null)
      */
-    public function css(&$page = null)
+    public function css($page = null)
     {
         if (!is_null($page)) {
             $page->addCssLink($this->nl->cssFile());
@@ -942,7 +1016,7 @@ class NLIssue
      * @p $page Smarty object (using the $this->nl->tplFile() template)
      * @p $user User to use when rendering the template
      */
-    public function toText(&$page, $user)
+    public function toText($page, $user)
     {
         $this->fetchArticles();
 
@@ -959,7 +1033,7 @@ class NLIssue
      * @p $page Smarty object (using the $this->nl->tplFile() template)
      * @p $user User to use when rendering the template
      */
-    public function toHtml(&$page, $user)
+    public function toHtml($page, $user)
     {
         $this->fetchArticles();
 
@@ -975,7 +1049,7 @@ class NLIssue
     /** Set all 'common' data for the page (those which are required for both web and email rendering)
      * @p $smarty Smarty object (e.g page) which should be filled
      */
-    protected function assignData(&$smarty)
+    protected function assignData($smarty)
     {
         $this->fetchArticles();
 
@@ -985,7 +1059,15 @@ class NLIssue
 
     // }}}
     // {{{ Mailing
-    
+
+    /** Check whether this issue is empty
+     * An issue is empty if the email has no title (or the default one), or no articles and an empty head.
+     */
+    public function isEmpty()
+    {
+        return $this->title_mail == '' || $this->title_mail == 'to be continued' || (count($this->arts) == 0 && strlen($this->head) == 0);
+    }
+
     /** Retrieve the 'Send before' date, in a clean format.
      */
     public function getSendBeforeDate()
@@ -1077,9 +1159,9 @@ class NLIssue
                        WHERE  id = {?}',
                        $this->id);
 
-        $ufc = new PFC_And($this->getRecipientsUFC(), new UFC_NLSubscribed($this->nl->id, $this->id), new UFC_HasEmailRedirect());
+        $ufc = new PFC_And($this->getRecipientsUFC(), new UFC_NLSubscribed($this->nl->id, $this->id), new UFC_HasValidEmail());
         $emailsCount = 0;
-        $uf = new UserFilter($ufc);
+        $uf = new UserFilter($ufc, array(new UFO_IsAdmin(), new UFO_Uid()));
         $limit = new PlLimit(self::BATCH_SIZE);
 
         while (true) {
@@ -1111,7 +1193,8 @@ class NLIssue
 class NLArticle
 {
     // Maximum number of lines per article
-    const MAX_LINES_PER_ARTICLE = 9;
+    const MAX_LINES_PER_ARTICLE = 8;
+    const MAX_CHARACTERS_PER_LINE = 68;
 
     // {{{ properties
 
@@ -1199,17 +1282,30 @@ class NLArticle
 
     public function check()
     {
-        $text = MiniWiki::WikiToText($this->body);
-        $arr  = explode("\n",wordwrap($text,68));
-        $c    = 0;
-        foreach ($arr as $line) {
-            if (trim($line)) {
-                $c++;
+        $rest = $this->remain();
+
+        return $rest['remaining_lines'] >= 0;
+    }
+
+    // }}}
+    // {{{ function remain()
+
+    public function remain()
+    {
+        $text  = MiniWiki::WikiToText($this->body);
+        $array = explode("\n", wordwrap($text, self::MAX_CHARACTERS_PER_LINE));
+        $lines_count = 0;
+        foreach ($array as $line) {
+            if (trim($line) != '') {
+                ++$lines_count;
             }
         }
-        return $c < self::MAX_LINES_PER_ARTICLE;
-    }
 
+        return array(
+            'remaining_lines'                    => self::MAX_LINES_PER_ARTICLE - $lines_count,
+            'remaining_characters_for_last_line' => self::MAX_CHARACTERS_PER_LINE - strlen($array[count($array) - 1])
+       );
+    }
     // }}}
     // {{{ function parseUrlsFromArticle()