pending commit, finished during MQ/S download ...
[platal.git] / include / newsletter.inc.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2006 Polytechnique.org *
4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 ***************************************************************************/
21
22 // {{{ requires + defines
23
24 require_once("xorg.misc.inc.php");
25 require_once("diogenes/diogenes.misc.inc.php");
26
27 if (isset($page)) {
28 $page->addCssLink('css/nl.css');
29 }
30
31 define('FEMME', 1);
32 define('HOMME', 0);
33
34 // }}}
35 // {{{ class NewsLetter
36
37 class NewsLetter
38 {
39 // {{{ properties
40
41 var $_id;
42 var $_date;
43 var $_title;
44 var $_head;
45 var $_cats = Array();
46 var $_arts = Array();
47
48 // }}}
49 // {{{ constructor
50
51 function NewsLetter($id=null)
52 {
53 if (isset($id)) {
54 if ($id == 'last') {
55 $res = XDB::query("SELECT MAX(id) FROM newsletter WHERE bits!='new'");
56 $id = $res->fetchOneCell();
57 }
58 $res = XDB::query("SELECT * FROM newsletter WHERE id={?}", $id);
59 } else {
60 $res = XDB::query("SELECT * FROM newsletter WHERE bits='new'");
61 }
62 $nl = $res->fetchOneAssoc();
63
64 $this->_id = $nl['id'];
65 $this->_date = $nl['date'];
66 $this->_title = $nl['titre'];
67 $this->_head = $nl['head'];
68
69 $res = XDB::iterRow("SELECT cid,titre FROM newsletter_cat ORDER BY pos");
70 while (list($cid, $title) = $res->next()) {
71 $this->_cats[$cid] = $title;
72 }
73
74 $res = XDB::iterRow(
75 "SELECT a.title,a.body,a.append,a.aid,a.cid,a.pos
76 FROM newsletter_art AS a
77 INNER JOIN newsletter AS n USING(id)
78 LEFT JOIN newsletter_cat AS c ON(a.cid=c.cid)
79 WHERE a.id={?}
80 ORDER BY c.pos,a.pos", $this->_id);
81 while (list($title, $body, $append, $aid, $cid, $pos) = $res->next()) {
82 $this->_arts[$cid]["a$aid"] = new NLArticle($title, $body, $append, $aid, $cid, $pos);
83 }
84 }
85
86 // }}}
87 // {{{ function setSent()
88
89 function setSent()
90 {
91 XDB::execute("UPDATE newsletter SET bits='sent' WHERE id={?}", $this->_id);
92 }
93
94 // }}}
95 // {{{ function save()
96
97 function save()
98 {
99 XDB::execute('UPDATE newsletter SET date={?},titre={?},head={?} WHERE id={?}',
100 $this->_date, $this->_title, $this->_head, $this->_id);
101 }
102
103 // }}}
104 // {{{ function title()
105
106 function title()
107 { return $this->_title; }
108
109 // }}}
110 // {{{ function head()
111
112 function head()
113 { return $this->_head; }
114
115 // }}}
116 // {{{ function getArt()
117
118 function getArt($aid)
119 {
120 foreach ($this->_arts as $key=>$artlist) {
121 if (isset($artlist["a$aid"])) {
122 return $artlist["a$aid"];
123 }
124 }
125 return null;
126 }
127
128 // }}}
129 // {{{ function saveArticle()
130
131 function saveArticle(&$a)
132 {
133 if ($a->_aid>=0) {
134 XDB::execute('REPLACE INTO newsletter_art (id,aid,cid,pos,title,body,append)
135 VALUES ({?},{?},{?},{?},{?},{?},{?})',
136 $this->_id, $a->_aid, $a->_cid, $a->_pos,
137 $a->_title, $a->_body, $a->_append);
138 $this->_arts['a'.$a->_aid] = $a;
139 } else {
140 XDB::execute(
141 'INSERT INTO newsletter_art
142 SELECT {?},MAX(aid)+1,{?},'.($a->_pos ? intval($a->_pos) : 'MAX(pos)+1').',{?},{?},{?}
143 FROM newsletter_art AS a
144 WHERE a.id={?}',
145 $this->_id, $a->_cid, $a->_title, $a->_body, $a->_append, $this->_id);
146 $this->_arts['a'.$a->_aid] = $a;
147 }
148 }
149
150 // }}}
151 // {{{ function delArticle()
152
153 function delArticle($aid)
154 {
155 XDB::execute('DELETE FROM newsletter_art WHERE id={?} AND aid={?}', $this->_id, $aid);
156 foreach ($this->_arts as $key=>$art) {
157 unset($this->_arts[$key]["a$aid"]);
158 }
159 }
160
161 // }}}
162 // {{{ function footer
163
164 function footer($html)
165 {
166 global $globals;
167 $url = $globals->baseurl;
168
169 if ($html) {
170 return '<div class="foot">Cette lettre est envoyée à tous les Polytechniciens sur Internet par l\'intermédiaire de Polytechnique.org.</div>'
171 . '<div class="foot">'
172 . "[<a href=\"$url/nl\">archives</a>&nbsp;|&nbsp;"
173 . "<a href=\"$url/nl/submit\">écrire dans la NL</a>&nbsp;|&nbsp;"
174 . "<a href=\"$url/nl/out\">ne plus recevoir</a>]"
175 . '</div>';
176 } else {
177 return "\n\n--------------------------------------------------------------------\n"
178 . "Cette lettre est envoyée à tous les Polytechniciens sur Internet par\n"
179 . "l'intermédiaire de Polytechnique.org.\n"
180 . "\n"
181 . "archives : [$url/nl]\n"
182 . "écrire : [$url/nl/submit]\n"
183 . "ne plus recevoir: [$url/nl/out]\n";
184 }
185 }
186
187 // }}}
188 // {{{ function toText()
189
190 function toText($prenom,$nom,$sexe)
191 {
192 $res = "====================================================================\n";
193 $res .= ' '.$this->title()."\n";
194 $res .= "====================================================================\n\n";
195
196 $head = $this->head();
197 $head = str_replace('<cher>', $sexe ? 'Chère' : 'Cher', $head);
198 $head = str_replace('<prenom>', $prenom, $head);
199 $head = str_replace('<nom>', $nom, $head);
200 $head = enriched_to_text($head,false,true,2,64);
201
202 if ($head) {
203 $res .= "\n$head\n\n\n";
204 }
205
206 $i = 1;
207 foreach ($this->_arts as $cid=>$arts) {
208 $res .= "\n$i *{$this->_cats[$cid]}*\n";
209 foreach ($arts as $art) {
210 $res .= '- '.$art->title()."\n";
211 }
212 $i ++;
213 }
214 $res .= "\n\n";
215
216 foreach ($this->_arts as $cid=>$arts) {
217 $res .= "--------------------------------------------------------------------\n";
218 $res .= "*{$this->_cats[$cid]}*\n";
219 $res .= "--------------------------------------------------------------------\n\n";
220 foreach ($arts as $art) {
221 $res .= $art->toText();
222 $res .= "\n\n";
223 }
224 }
225
226 $res .= $this->footer(false);
227
228 return $res;
229 }
230
231 // }}}
232 // {{{ function toHtml()
233
234 function toHtml($prenom,$nom,$sexe,$body=false)
235 {
236 $res = '<div class="title">'.$this->title().'</div>';
237
238 $head = $this->head();
239 $head = str_replace('<cher>', $sexe ? 'Chère' : 'Cher', $head);
240 $head = str_replace('<prenom>', $prenom, $head);
241 $head = str_replace('<nom>', $nom, $head);
242 $head = enriched_to_text($head,true);
243
244 if($head) {
245 $res .= "<div class='intro'>$head</div>";
246 }
247
248 $i = 1;
249 $res .= "<a id='top_lnk'></a>";
250 foreach ($this->_arts as $cid=>$arts) {
251 $res .= "<div class='lnk'><a href='#cat$cid'><strong>$i. {$this->_cats[$cid]}</strong></a>";
252 foreach ($arts as $art) {
253 $res .= "<a href='#art{$art->_aid}'>&nbsp;&nbsp;- ".htmlentities($art->title())."</a>";
254 }
255 $res .= '</div>';
256 $i ++;
257 }
258
259 foreach ($this->_arts as $cid=>$arts) {
260 $res .= "<h1><a id='cat$cid'></a><span>".$this->_cats[$cid].'</span></h1>';
261 foreach($arts as $art) {
262 $res .= $art->toHtml();
263 $res .= "<p><a href='#top_lnk'>Revenir au sommaire</a></p>";
264 }
265 }
266
267 $res .= $this->footer(true);
268
269 if ($body) {
270 $res = <<<EOF
271 <html>
272 <head>
273 <style type="text/css">
274 <!--
275 div.nl { margin: auto; font-family: "Georgia","times new roman",serif; width: 60ex; text-align: justify; font-size: 10pt; }
276 div.title { margin: 2ex 0ex 2ex 0ex; padding: 1ex; width: 100%; font-size: 140%; text-align: center;
277 font-weight: bold; border-bottom: 3px red solid; border-top: 3px red solid; }
278
279 a[href] { text-decoration: none; }
280 a[href]:hover { text-decoration: underline; }
281
282 div.lnk { margin: 2ex 0ex 2ex 0ex; padding: 0ex 2ex 0ex 2ex; }
283 div.lnk a { display: block; }
284
285 h1 { margin: 6ex 0ex 4ex 0ex; padding: 2px 4ex 2px 0ex; width: 60ex; font-size: 100%;
286 border-bottom: 3px red solid; border-top: 3px red solid; }
287 h2 { width: 100%; margin: 0ex 1ex 0ex 1ex; padding: 2px 0px 2px 0px; font-weight: bold; font-style: italic; font-size: 95%; }
288 h1 span { font-size: 140%; padding: 2px 1ex 2px 1ex; border-bottom: 3px red solid; }
289 h2 span { padding: 2px 4px 2px 4px; border-bottom: 2px yellow solid; }
290
291 div.art { padding: 2ex; margin: 0ex 1ex 2ex 1ex; width: 58ex; border-top: 2px yellow solid; }
292 div.app { padding: 2ex 3ex 0ex 3ex; width: 100%; margin: 0ex; text-align: left; font-size: 95%; }
293 div.intro { padding: 2ex; }
294 div.foot { border-top: 1px #808080 dashed; font-size: 95%; padding: 1ex; color: #808080; background: inherit;
295 text-align: center; width: 100% }
296 -->
297 </style>
298 </head>
299 <body>
300 <div class='nl'>
301 $res
302 </div>
303 </body>
304 </html>
305 EOF;
306 }
307 return $res;
308 }
309
310 // }}}
311 // {{{ function sendTo()
312
313 function sendTo($prenom, $nom, $login, $sex, $html)
314 {
315 global $globals;
316 require_once('diogenes/diogenes.hermes.inc.php');
317
318 $mailer = new HermesMailer();
319 $mailer->setFrom($globals->newsletter->from);
320 $mailer->setSubject($this->title());
321 $mailer->addTo("\"$prenom $nom\" <$login@{$globals->mail->domain}>");
322 if (!empty($globals->newsletter->replyto)) {
323 $mailer->addHeader('Reply-To',$globals->newsletter->replyto);
324 }
325 if (!empty($globals->newsletter->retpath)) {
326 $mailer->addHeader('Return-Path',$globals->newsletter->retpath);
327 }
328 $mailer->setTxtBody($this->toText($prenom,$nom,$sex));
329 if ($html) {
330 $mailer->setHTMLBody($this->toHtml($prenom,$nom,$sex,true));
331 }
332 $mailer->send();
333 }
334
335 // }}}
336 }
337
338 // }}}
339 // {{{ class NLArticle
340
341 class NLArticle
342 {
343 // {{{ properties
344
345 var $_aid;
346 var $_cid;
347 var $_pos;
348 var $_title;
349 var $_body;
350 var $_append;
351
352 // }}}
353 // {{{ constructor
354
355 function NLArticle($title='', $body='', $append='', $aid=-1, $cid=0, $pos=0)
356 {
357 $this->_body = $body;
358 $this->_title = $title;
359 $this->_append = $append;
360 $this->_aid = $aid;
361 $this->_cid = $cid;
362 $this->_pos = $pos;
363 }
364
365 // }}}
366 // {{{ function title()
367
368 function title()
369 { return trim($this->_title); }
370
371 // }}}
372 // {{{ function body()
373
374 function body()
375 { return trim($this->_body); }
376
377 // }}}
378 // {{{ function append()
379
380 function append()
381 { return trim($this->_append); }
382
383 // }}}
384 // {{{ function toText()
385
386 function toText()
387 {
388 $title = '*'.$this->title().'*';
389 $body = enriched_to_text($this->_body,false,true);
390 $app = enriched_to_text($this->_append,false,false,4);
391 return trim("$title\n\n$body\n\n$app")."\n";
392 }
393
394 // }}}
395 // {{{ function toHtml()
396
397 function toHtml()
398 {
399 $title = "<h2><a id='art{$this->_aid}'></a><span>".htmlentities($this->title()).'</span></h2>';
400 $body = enriched_to_text($this->_body,true);
401 $app = enriched_to_text($this->_append,true);
402
403 $art = "$title\n";
404 $art .= "<div class='art'>\n$body\n";
405 if ($app) {
406 $art .= "<div class='app'>$app</div>";
407 }
408 $art .= "</div>\n";
409
410 return $art;
411 }
412
413 // }}}
414 // {{{ function check()
415
416 function check()
417 {
418 $text = enriched_to_text($this->_body);
419 $arr = explode("\n",wordwrap($text,68));
420 $c = 0;
421 foreach ($arr as $line) {
422 if (trim($line)) {
423 $c++;
424 }
425 }
426 return $c<9;
427 }
428
429 // }}}
430 }
431
432 // }}}
433 // {{{ Functions
434
435 function insert_new_nl()
436 {
437 XDB::execute("INSERT INTO newsletter SET bits='new',date=NOW(),titre='to be continued'");
438 }
439
440 function get_nl_slist()
441 {
442 $res = XDB::query("SELECT id,date,titre FROM newsletter ORDER BY date DESC");
443 return $res->fetchAllAssoc();
444 }
445
446 function get_nl_list()
447 {
448 $res = XDB::query("SELECT id,date,titre FROM newsletter WHERE bits!='new' ORDER BY date DESC");
449 return $res->fetchAllAssoc();
450 }
451
452 function get_nl_state()
453 {
454 $res = XDB::query('SELECT 1 FROM newsletter_ins WHERE user_id={?}', S::v('uid'));
455 return $res->fetchOneCell();
456 }
457
458 function unsubscribe_nl()
459 {
460 XDB::execute('DELETE FROM newsletter_ins WHERE user_id={?}', S::v('uid'));
461 }
462
463 function subscribe_nl($uid=-1)
464 {
465 $user = ($uid == -1) ? S::v('uid') : $uid;
466 XDB::execute('REPLACE INTO newsletter_ins (user_id,last)
467 VALUES ({?}, 0)', $user);
468 }
469
470 function justify($text,$n)
471 {
472 $arr = explode("\n",wordwrap($text,$n));
473 $arr = array_map('trim',$arr);
474 $res = '';
475 foreach ($arr as $key => $line) {
476 $nxl = isset($arr[$key+1]) ? trim($arr[$key+1]) : '';
477 $nxl_split = preg_split('! +!',$nxl);
478 $nxw_len = count($nxl_split) ? strlen($nxl_split[0]) : 0;
479 $line = trim($line);
480
481 if (strlen($line)+1+$nxw_len < $n) {
482 $res .= "$line\n";
483 continue;
484 }
485
486 if (preg_match('![.:;]$!',$line)) {
487 $res .= "$line\n";
488 continue;
489 }
490
491 $tmp = preg_split('! +!',trim($line));
492 $words = count($tmp);
493 if ($words <= 1) {
494 $res .= "$line\n";
495 continue;
496 }
497
498 $len = array_sum(array_map('strlen',$tmp));
499 $empty = $n - $len;
500 $sw = floatval($empty) / floatval($words-1);
501
502 $cur = 0;
503 $l = '';
504 foreach ($tmp as $word) {
505 $l .= $word;
506 $cur += $sw + strlen($word);
507 $l = str_pad($l,intval($cur+0.5));
508 }
509 $res .= trim($l)."\n";
510 }
511 return trim($res);
512 }
513
514 function enriched_to_text($input,$html=false,$just=false,$indent=0,$width=68)
515 {
516 $text = trim($input);
517 if ($html) {
518 $text = htmlspecialchars($text);
519 $text = str_replace('[b]','<strong>', $text);
520 $text = str_replace('[/b]','</strong>', $text);
521 $text = str_replace('[i]','<em>', $text);
522 $text = str_replace('[/i]','</em>', $text);
523 $text = str_replace('[u]','<span style="text-decoration: underline">', $text);
524 $text = str_replace('[/u]','</span>', $text);
525 $text = preg_replace('!((https?|ftp)://[^\r\n\t ]*)!','<a href="\1">\1</a>', $text);
526 $text = preg_replace('!(([a-zA-Z0-9\-_+.]*@[a-zA-Z0-9\-_+.]*)(?:\?[^\r\n\t ]*)?)!','<a href="mailto:\1">\2</a>', $text);
527 return nl2br($text);
528 } else {
529 $text = preg_replace('!\[\/?b\]!','*',$text);
530 $text = preg_replace('!\[\/?u\]!','_',$text);
531 $text = preg_replace('!\[\/?i\]!','/',$text);
532 $text = preg_replace('!((https?|ftp)://[^\r\n\t ]*)!','[\1]', $text);
533 $text = preg_replace('!(([a-zA-Z0-9\-_+.]*@[a-zA-Z0-9\-_+.]*)(?:\?[^\r\n\t ]*)?)!','[mailto:\1]', $text);
534 $text = $just ? justify($text,$width-$indent) : wordwrap($text,$width-$indent);
535 if($indent) {
536 $ind = str_pad('',$indent);
537 $text = $ind.str_replace("\n","\n$ind",$text);
538 }
539 return $text;
540 }
541 }
542
543 // }}}
544
545 // vim:set et sw=4 sts=4 sws=4:
546 ?>