Platal::kill() doesn't exist, use Platal::page()->kill() instead.
[platal.git] / include / validations.inc.php
CommitLineData
0337d704 1<?php
2/***************************************************************************
12262f13 3 * Copyright (C) 2003-2011 Polytechnique.org *
0337d704 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
0337d704 22define('SIZE_MAX', 32768);
23
ce8ca505 24global $globals;
2f151d5f 25
0337d704 26
616918d0 27/** Virtual class to adapt for every possible implementation.
0337d704 28 */
612a2d8a 29abstract class Validate
0337d704 30{
31 // {{{ properties
eaf30d86 32
5daf68f6 33 public $user;
a3923909 34 public $formal;
612a2d8a 35
36 public $stamp;
37 public $unique;
616918d0 38 // Enable the refuse button.
612a2d8a 39 public $refuse = true;
eaf30d86 40
612a2d8a 41 public $type;
42 public $comments = Array();
616918d0
SJ
43 // Validations rules: comments for administrators.
44 public $rules = 'Mieux vaut laisser une demande de validation à un autre administrateur que de valider une requête illégale ou que de refuser une demande légitime.';
0337d704 45
e33b29e5
SJ
46 // Unless differently stated, a validation must be done by a site administrator.
47 public $requireAdmin = true;
48
0337d704 49 // }}}
50 // {{{ constructor
eaf30d86 51
616918d0
SJ
52 /** Constructor
53 * @param $_user: user object that required the validation.
54 * @param $_unique: set to false if a profile can have multiple requests of this type.
55 * @param $_type: request's type.
0337d704 56 */
26ba053e 57 public function __construct(User $_user, $_unique, $_type)
0337d704 58 {
532c06cf 59 $this->user = &$_user;
a3923909 60 $this->formal = !$this->user->hasProfile();
0337d704 61 $this->stamp = date('YmdHis');
62 $this->unique = $_unique;
63 $this->type = $_type;
8f2104cb 64 $this->promo = $this->user->promo();
0337d704 65 }
eaf30d86 66
0337d704 67 // }}}
68 // {{{ function submit()
69
616918d0
SJ
70 /** Sends data to validation.
71 * It also deletes multiple requests for a couple (profile, type)
72 * when $this->unique is set to true.
0337d704 73 */
612a2d8a 74 public function submit()
0337d704 75 {
0337d704 76 if ($this->unique) {
1bf36cd1
SJ
77 XDB::execute('DELETE FROM requests
78 WHERE uid = {?} AND type = {?}',
79 $this->user->id(), $this->type);
0337d704 80 }
eaf30d86 81
0337d704 82 $this->stamp = date('YmdHis');
1bf36cd1
SJ
83 XDB::execute('INSERT INTO requests (uid, type, data, stamp)
84 VALUES ({?}, {?}, {?}, {?})',
616918d0 85 $this->user->id(), $this->type, $this, $this->stamp);
0337d704 86
84868ee9 87 global $globals;
ebfdf077 88 $globals->updateNbValid();
0337d704 89 return true;
90 }
91
92 // }}}
93 // {{{ function update()
94
612a2d8a 95 protected function update()
0337d704 96 {
1bf36cd1
SJ
97 XDB::execute('UPDATE requests
98 SET data = {?}, stamp = stamp
99 WHERE uid = {?} AND type = {?} AND stamp = {?}',
5daf68f6 100 $this, $this->user->id(), $this->type, $this->stamp);
0337d704 101 return true;
102 }
103
104 // }}}
105 // {{{ function clean()
eaf30d86 106
616918d0
SJ
107 /** Deletes request from 'requests' table.
108 * If $this->unique is set, it deletes every requests of this type.
0337d704 109 */
d17761d8 110 public function clean()
0337d704 111 {
95e36b0f
SJ
112 global $globals;
113
0337d704 114 if ($this->unique) {
1bf36cd1
SJ
115 $success = XDB::execute('DELETE FROM requests
116 WHERE uid = {?} AND type = {?}',
5daf68f6 117 $this->user->id(), $this->type);
0337d704 118 } else {
1bf36cd1
SJ
119 $success = XDB::execute('DELETE FROM requests
120 WHERE uid = {?} AND type = {?} AND stamp = {?}',
5daf68f6 121 $this->user->id(), $this->type, $this->stamp);
0337d704 122 }
ebfdf077 123 $globals->updateNbValid();
84868ee9 124 return $success;
0337d704 125 }
126
127 // }}}
128 // {{{ function handle_formu()
eaf30d86 129
616918d0 130 /** Handles form validation.
0337d704 131 */
612a2d8a 132 public function handle_formu()
0337d704 133 {
e33b29e5
SJ
134 if ($this->requireAdmin && !S::admin()) {
135 $this->trigError('Vous n\'avez pas les permissions nécessaires pour valider cette demande.');
136 return false;
137 }
138
0337d704 139 if (Env::has('delete')) {
140 $this->clean();
616918d0 141 $this->trigSuccess('Requête supprimée.');
0337d704 142 return true;
143 }
144
616918d0 145 // Data updates.
6aa01fed 146 if (Env::has('edit')) {
147 if ($this->handle_editor()) {
148 $this->update();
616918d0 149 $this->trigSuccess('Requête mise à jour.');
6aa01fed 150 return true;
151 }
152 return false;
153 }
154
616918d0 155 // Comment addition.
0337d704 156 if (Env::has('hold') && Env::has('comm')) {
4791ff77 157 $formid = Env::i('formid');
158 foreach ($this->comments as $comment) {
159 if ($comment[2] === $formid) {
160 return true;
161 }
162 }
90608d68 163 if (!strlen(trim(Env::v('comm')))) {
164 return true;
165 }
616918d0 166 $this->comments[] = array(S::user()->login(), Env::v('comm'), $formid);
0337d704 167
616918d0 168 // Sends email to our hotline.
0337d704 169 global $globals;
b9c53090 170 $mailer = new PlMailer();
0337d704 171 $mailer->setSubject("Commentaires de validation {$this->type}");
172 $mailer->setFrom("validation+{$this->type}@{$globals->mail->domain}");
b9c53090 173 $mailer->addTo($globals->core->admin_email);
0337d704 174
53092def 175 $body = "Validation {$this->type} pour {$this->user->login()}\n\n"
5daf68f6
VZ
176 . S::user()->login() . " a ajouté le commentaire :\n\n"
177 . Env::v('comm') . "\n\n"
178 . "cf la discussion sur : " . $globals->baseurl . "/admin/validate";
0337d704 179
180 $mailer->setTxtBody(wordwrap($body));
181 $mailer->send();
182
183 $this->update();
616918d0 184 $this->trigSuccess('Commentaire ajouté.');
0337d704 185 return true;
186 }
187
188 if (Env::has('accept')) {
189 if ($this->commit()) {
190 $this->sendmail(true);
191 $this->clean();
faefdbb7 192 $this->trigSuccess('Email de validation envoyé');
0337d704 193 return true;
194 } else {
a7d35093 195 $this->trigError('Erreur lors de la validation');
0337d704 196 return false;
197 }
198 }
199
200 if (Env::has('refuse')) {
5e2307dc 201 if (Env::v('comm')) {
0337d704 202 $this->sendmail(false);
203 $this->clean();
616918d0 204 $this->trigSuccess('Email de refus envoyé.');
0337d704 205 return true;
206 } else {
6bb2f79a 207 $this->trigError('Pas de motivation pour le refus&nbsp;!!!');
0337d704 208 }
209 }
210
211 return false;
212 }
213
214 // }}}
215 // {{{ function sendmail
216
612a2d8a 217 protected function sendmail($isok)
0337d704 218 {
219 global $globals;
1e33266a 220 $mailer = new PlMailer();
0337d704 221 $mailer->setSubject($this->_mail_subj());
222 $mailer->setFrom("validation+{$this->type}@{$globals->mail->domain}");
5daf68f6 223 $mailer->addTo("\"{$this->user->fullName()}\" <{$this->user->bestEmail()}>");
0337d704 224 $mailer->addCc("validation+{$this->type}@{$globals->mail->domain}");
225
a3923909
SJ
226 // If the user has no profile, we should be more formal as if she has one.
227 if ($this->formal) {
228 $body = ($this->user->isFemale() ? 'Bonjour Madame' : 'Bonjour Monsieur');
229 } else {
230 $body = ($this->user->isFemale() ? 'Chère camarade' : 'Cher camarade');
231 }
232 $body .= ",\n\n" . $this->_mail_body($isok)
9be4a981 233 . (Env::has('comm') ? "\n\n" . Env::v('comm') : '')
5353e51e
SJ
234 . "\n\nCordialement,\n-- \nL'équipe de Polytechnique.org\n"
235 . $this->_mail_ps($isok);
0337d704 236
237 $mailer->setTxtBody(wordwrap($body));
238 $mailer->send();
239 }
240
241 // }}}
242 // {{{ function trig()
eaf30d86 243
a7d35093 244 protected function trigError($msg)
612a2d8a 245 {
d7610c35 246 Platal::page()->trigError($msg);
a7d35093
FB
247 }
248
249 protected function trigWarning($msg)
250 {
d7610c35 251 Platal::page()->trigWarning($msg);
a7d35093
FB
252 }
253
254 protected function trigSuccess($msg)
255 {
d7610c35 256 Platal::page()->trigSuccess($msg);
0337d704 257 }
eaf30d86 258
0337d704 259 // }}}
20d7932b 260 // {{{ function get_typed_request()
0337d704 261
616918d0
SJ
262 /**
263 * @param $pid: profile's pid
264 * @param $type: request's type
265 * @param $stamp: request's timestamp
0337d704 266 *
616918d0 267 * Should only be used to retrieve an object in the databse with Validate::get_typed_request(...)
0337d704 268 */
612a2d8a 269 static public function get_typed_request($uid, $type, $stamp = -1)
0337d704 270 {
0337d704 271 if ($stamp == -1) {
1bf36cd1
SJ
272 $res = XDB::query('SELECT data
273 FROM requests
274 WHERE uid = {?} and type = {?}',
275 $uid, $type);
0337d704 276 } else {
1bf36cd1
SJ
277 $res = XDB::query('SELECT data, DATE_FORMAT(stamp, "%Y%m%d%H%i%s")
278 FROM requests
279 WHERE uid = {?} AND type = {?} and stamp = {?}',
280 $uid, $type, $stamp);
0337d704 281 }
282 if ($result = $res->fetchOneCell()) {
33b47675 283 $result = Validate::unserialize($result);
0337d704 284 } else {
285 $result = false;
286 }
287 return($result);
288 }
289
290 // }}}
02838718 291 // {{{ function get_request_by_id()
292
293 static public function get_request_by_id($id)
294 {
295 list($uid, $type, $stamp) = explode('_', $id, 3);
296 return Validate::get_typed_request($uid, $type, $stamp);
297 }
298
299 // }}}
5b0dc389 300 // {{{ function get_typed_requests()
301
616918d0 302 /** Same as get_typed_request() but return an array of objects.
5b0dc389 303 */
612a2d8a 304 static public function get_typed_requests($uid, $type)
5b0dc389 305 {
1bf36cd1
SJ
306 $res = XDB::iterRow('SELECT data
307 FROM requests
308 WHERE uid = {?} and type = {?}',
309 $uid, $type);
5b0dc389 310 $array = array();
311 while (list($data) = $res->next()) {
33b47675 312 $array[] = Validate::unserialize($data);
5b0dc389 313 }
314 return $array;
315 }
316
317 // }}}
bb0727ea
VZ
318 // {{{ function get_typed_requests_count()
319
616918d0 320 /** Same as get_typed_requests() but return the count of available requests.
bb0727ea
VZ
321 */
322 static public function get_typed_requests_count($uid, $type)
323 {
1bf36cd1
SJ
324 $res = XDB::query('SELECT COUNT(data)
325 FROM requests
326 WHERE uid = {?} and type = {?}',
327 $uid, $type);
bb0727ea
VZ
328 return $res->fetchOneCell();
329 }
330
331 // }}}
0337d704 332 // {{{ function _mail_body
333
612a2d8a 334 abstract protected function _mail_body($isok);
eaf30d86 335
0337d704 336 // }}}
337 // {{{ function _mail_subj
338
612a2d8a 339 abstract protected function _mail_subj();
eaf30d86 340
0337d704 341 // }}}
9be4a981
SJ
342 // {{{ function _mail_ps
343
344 protected function _mail_ps($isok)
345 {
5353e51e 346 return '';
9be4a981
SJ
347 }
348
349 // }}}
0337d704 350 // {{{ function commit()
eaf30d86 351
616918d0 352 /** Inserts data in database.
0337d704 353 */
612a2d8a 354 abstract public function commit();
0337d704 355
356 // }}}
357 // {{{ function formu()
eaf30d86 358
616918d0 359 /** Retunrs the name of the form's template. */
612a2d8a 360 abstract public function formu();
0337d704 361
362 // }}}
6aa01fed 363 // {{{ function editor()
364
616918d0 365 /** Returns the name of the edition form's template. */
612a2d8a 366 public function editor()
367 {
368 return null;
369 }
6aa01fed 370
371 // }}}
e18888f4 372 // {{{ function answers()
373
616918d0 374 /** Automatic answers table for this type of validation. */
612a2d8a 375 public function answers()
376 {
e18888f4 377 static $answers_table;
378 if (!isset($answers_table[$this->type])) {
616918d0
SJ
379 $r = XDB::query('SELECT id, title, answer
380 FROM requests_answers
381 WHERE category = {?}',
382 $this->type);
745539c0 383 $answers_table[$this->type] = $r->fetchAllAssoc();
e18888f4 384 }
385 return $answers_table[$this->type];
386 }
387
388 // }}}
616918d0 389 // {{{ function id()
ed5b9703 390
612a2d8a 391 public function id()
ed5b9703 392 {
5daf68f6 393 return $this->user->id() . '_' . $this->type . '_' . $this->stamp;
ed5b9703 394 }
395
396 // }}}
fba760d2 397 // {{{ function ruleText()
398
399 public function ruleText()
400 {
401 return str_replace('\'', '\\\'', $this->rules);
402 }
403
404 // }}}
33b47675 405 // {{{ function unserialize()
4407871a 406
33b47675
FB
407 public static function unserialize($data)
408 {
616918d0 409 return unserialize($data);
33b47675 410 }
4407871a
SJ
411
412 // }}}
7b094a73
FB
413
414 /** Return an iterator over the validation concerning the given type
415 * and the given user.
416 *
417 * @param type The type of the validations to fetch, null mean "any type"
418 * @param applyTo A User or a Profile object the validation applies to.
419 */
420 public static function iterate($type = null, $applyTo = null)
421 {
422 function toValidation($elt)
423 {
424 list($result, $stamp) = $elt;
425 $result = Validate::unserialize($result);
426 $result->stamp = $stamp;
427 return $result;
428 }
429
430 $where = array();
431 if ($type) {
432 $where[] = XDB::format('type = {?}', $type);
433 }
434 if ($applyTo) {
435 if ($applyTo instanceof User) {
436 $where[] = XDB::format('uid = {?}', $applyTo->id());
437 } else if ($applyTo instanceof Profile) {
438 $where[] = XDB::format('pid = {?}', $applyTo->id());
439 }
440 }
441 if (!empty($where)) {
442 $where = 'WHERE ' . implode('AND', $where);
443 }
444 $it = XDB::iterRow('SELECT data, DATE_FORMAT(stamp, "%Y%m%d%H%i%s")
445 FROM requests
446 ' . $where . '
447 ORDER BY stamp');
448 return PlIteratorUtils::map($it, 'toValidation');
449 }
4407871a
SJ
450}
451
452/** Virtual class for profile related validation.
453 */
454abstract class ProfileValidate extends Validate
455{
456 // {{{ properties
457
458 public $profile;
459 public $profileOwner;
460 public $userIsProfileOwner;
a0fce0c6 461 public $ownerIsRegistered;
4407871a
SJ
462
463 // }}}
464 // {{{ constructor
465
616918d0 466 /** Constructor
4407871a
SJ
467 * @param $_user: user object that required the validation.
468 * @param $_profile: profile object that is to be modified,
469 * its owner (if exists) can differ from $_user.
470 * @param $_unique: set to false if a profile can have multiple requests of this type.
471 * @param $_type: request's type.
472 */
26ba053e 473 public function __construct(User $_user, Profile $_profile, $_unique, $_type)
4407871a
SJ
474 {
475 parent::__construct($_user, $_unique, $_type);
476 $this->profile = &$_profile;
477 $this->profileOwner = $this->profile->owner();
a0fce0c6
SJ
478 $this->userIsProfileOwner = (!is_null($this->profileOwner)
479 && $this->profileOwner->id() == $this->user->id());
480 $this->ownerIsRegistered = $this->profile->isActive();
4407871a
SJ
481 }
482
483 // }}}
484 // {{{ function submit()
485
486 /** Sends data to validation.
487 * It also deletes multiple requests for a couple (profile, type)
488 * when $this->unique is set to true.
489 */
490 public function submit()
491 {
492 if ($this->unique) {
493 XDB::execute('DELETE FROM requests
494 WHERE pid = {?} AND type = {?}',
495 $this->profile->id(), $this->type);
496 }
497
498 $this->stamp = date('YmdHis');
499 XDB::execute('INSERT INTO requests (uid, pid, type, data, stamp)
d84b97ba 500 VALUES ({?}, {?}, {?}, {?}, {?})',
4407871a
SJ
501 $this->user->id(), $this->profile->id(), $this->type, $this, $this->stamp);
502
503 global $globals;
504 $globals->updateNbValid();
505 return true;
506 }
507
508 // }}}
509 // {{{ function update()
510
511 protected function update()
512 {
513 XDB::execute('UPDATE requests
514 SET data = {?}, stamp = stamp
515 WHERE pid = {?} AND type = {?} AND stamp = {?}',
516 $this, $this->profile->id(), $this->type, $this->stamp);
517 return true;
518 }
519
520 // }}}
521 // {{{ function clean()
522
523 /** Deletes request from 'requests' table.
524 * If $this->unique is set, it deletes every requests of this type.
525 */
526 public function clean()
527 {
528 global $globals;
529
530 if ($this->unique) {
531 $success = XDB::execute('DELETE FROM requests
532 WHERE pid = {?} AND type = {?}',
533 $this->profile->id(), $this->type);
534 } else {
535 $success = XDB::execute('DELETE FROM requests
536 WHERE pid = {?} AND type = {?} AND stamp = {?}',
537 $this->profile->id(), $this->type, $this->stamp);
538 }
539 $globals->updateNbValid();
540 return $success;
541 }
542
543 // }}}
544 // {{{ function sendmail
545
546 protected function sendmail($isok)
547 {
a0fce0c6
SJ
548 // Only sends email if the profile's owner exists and is registered.
549 if ($this->ownerIsRegistered) {
550 global $globals;
4407871a 551
a0fce0c6
SJ
552 $mailer = new PlMailer();
553 $mailer->setSubject($this->_mail_subj());
554 $mailer->setFrom("validation+{$this->type}@{$globals->mail->domain}");
555 $mailer->addTo("\"{$this->profile->fullName()}\" <{$this->profileOwner->bestEmail()}>");
556 $mailer->addCc("validation+{$this->type}@{$globals->mail->domain}");
557 $body = ($this->profile->isFemale() ? "Chère camarade,\n\n" : "Cher camarade,\n\n")
558 . $this->_mail_body($isok)
559 . (Env::has('comm') ? "\n\n" . Env::v('comm') : '')
560 . "\n\nCordialement,\n-- \nL'équipe de Polytechnique.org\n"
561 . $this->_mail_ps($isok);
562 $mailer->setTxtBody(wordwrap($body));
563 $mailer->send();
564 }
4407871a
SJ
565 }
566
567 // }}}
568 // {{{ function get_typed_request()
569
570 /**
571 * @param $pid: profile's pid
572 * @param $type: request's type
573 * @param $stamp: request's timestamp
574 *
575 * Should only be used to retrieve an object in the databse with Validate::get_typed_request(...)
576 */
577 static public function get_typed_request($pid, $type, $stamp = -1)
578 {
579 if ($stamp == -1) {
580 $res = XDB::query('SELECT data
581 FROM requests
582 WHERE pid = {?} and type = {?}',
583 $pid, $type);
584 } else {
585 $res = XDB::query('SELECT data, DATE_FORMAT(stamp, "%Y%m%d%H%i%s")
586 FROM requests
587 WHERE pid = {?} AND type = {?} and stamp = {?}',
588 $pid, $type, $stamp);
589 }
590 if ($result = $res->fetchOneCell()) {
591 $result = Validate::unserialize($result);
592 } else {
593 $result = false;
594 }
595 return $result;
596 }
597
598 // }}}
599 // {{{ function get_request_by_id()
600
601 static public function get_request_by_id($id)
602 {
603 list($pid, $type, $stamp) = explode('_', $id, 3);
604 return Validate::get_typed_request($pid, $type, $stamp);
605 }
606
607 // }}}
608 // {{{ function get_typed_requests()
609
610 /** Same as get_typed_request() but return an array of objects.
611 */
612 static public function get_typed_requests($pid, $type)
613 {
614 $res = XDB::iterRow('SELECT data
615 FROM requests
328bd54a
SJ
616 WHERE pid = {?} and type = {?}
617 ORDER BY stamp',
4407871a
SJ
618 $pid, $type);
619 $array = array();
620 while (list($data) = $res->next()) {
621 $array[] = Validate::unserialize($data);
622 }
623 return $array;
624 }
625
626 // }}}
57fa97b3
SJ
627 // {{{ function get_all_typed_requests()
628
629 /** Same as get_typed_request() but return an array of objects.
630 */
631 static public function get_all_typed_requests($type)
632 {
633 $res = XDB::iterRow('SELECT data
634 FROM requests
635 WHERE type = {?}
636 ORDER BY stamp',
637 $type);
638 $array = array();
639 while (list($data) = $res->next()) {
640 $array[] = Validate::unserialize($data);
641 }
642 return $array;
643 }
644
645 // }}}
4407871a
SJ
646 // {{{ function get_typed_requests_count()
647
648 /** Same as get_typed_requests() but returns the count of available requests.
649 */
650 static public function get_typed_requests_count($pid, $type)
651 {
652 $res = XDB::query('SELECT COUNT(data)
653 FROM requests
654 WHERE pid = {?} and type = {?}',
655 $pid, $type);
656 return $res->fetchOneCell();
657 }
658
659 // }}}
616918d0 660 // {{{ function id()
4407871a
SJ
661
662 public function id()
663 {
d134ddda 664 return $this->profile->id() . '_' . $this->type . '_' . $this->stamp;
4407871a
SJ
665 }
666
667 // }}}
0337d704 668}
669
4407871a
SJ
670foreach (glob(dirname(__FILE__) . '/validations/*.inc.php') as $file) {
671 require_once $file;
0337d704 672}
673
a7de4ef7 674/* vim: set expandtab shiftwidth=4 tabstop=4 softtabstop=4 foldmethod=marker enc=utf-8: */
0337d704 675?>