Moving to GitHub.
[platal.git] / include / validations.inc.php
CommitLineData
0337d704 1<?php
2/***************************************************************************
c441aabe 3 * Copyright (C) 2003-2014 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 {
2963be50 393 return str_replace(" ", "_", $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);
1b5f4ba2
NI
443 } else {
444 $where = '';
7b094a73
FB
445 }
446 $it = XDB::iterRow('SELECT data, DATE_FORMAT(stamp, "%Y%m%d%H%i%s")
447 FROM requests
448 ' . $where . '
449 ORDER BY stamp');
450 return PlIteratorUtils::map($it, 'toValidation');
451 }
4407871a
SJ
452}
453
454/** Virtual class for profile related validation.
455 */
456abstract class ProfileValidate extends Validate
457{
458 // {{{ properties
459
460 public $profile;
461 public $profileOwner;
462 public $userIsProfileOwner;
a0fce0c6 463 public $ownerIsRegistered;
4407871a
SJ
464
465 // }}}
466 // {{{ constructor
467
616918d0 468 /** Constructor
4407871a
SJ
469 * @param $_user: user object that required the validation.
470 * @param $_profile: profile object that is to be modified,
471 * its owner (if exists) can differ from $_user.
472 * @param $_unique: set to false if a profile can have multiple requests of this type.
473 * @param $_type: request's type.
474 */
26ba053e 475 public function __construct(User $_user, Profile $_profile, $_unique, $_type)
4407871a
SJ
476 {
477 parent::__construct($_user, $_unique, $_type);
478 $this->profile = &$_profile;
479 $this->profileOwner = $this->profile->owner();
a0fce0c6
SJ
480 $this->userIsProfileOwner = (!is_null($this->profileOwner)
481 && $this->profileOwner->id() == $this->user->id());
482 $this->ownerIsRegistered = $this->profile->isActive();
4407871a
SJ
483 }
484
485 // }}}
486 // {{{ function submit()
487
488 /** Sends data to validation.
489 * It also deletes multiple requests for a couple (profile, type)
490 * when $this->unique is set to true.
491 */
492 public function submit()
493 {
494 if ($this->unique) {
495 XDB::execute('DELETE FROM requests
496 WHERE pid = {?} AND type = {?}',
497 $this->profile->id(), $this->type);
498 }
499
500 $this->stamp = date('YmdHis');
501 XDB::execute('INSERT INTO requests (uid, pid, type, data, stamp)
d84b97ba 502 VALUES ({?}, {?}, {?}, {?}, {?})',
4407871a
SJ
503 $this->user->id(), $this->profile->id(), $this->type, $this, $this->stamp);
504
505 global $globals;
506 $globals->updateNbValid();
507 return true;
508 }
509
510 // }}}
511 // {{{ function update()
512
513 protected function update()
514 {
515 XDB::execute('UPDATE requests
516 SET data = {?}, stamp = stamp
517 WHERE pid = {?} AND type = {?} AND stamp = {?}',
518 $this, $this->profile->id(), $this->type, $this->stamp);
519 return true;
520 }
521
522 // }}}
523 // {{{ function clean()
524
525 /** Deletes request from 'requests' table.
526 * If $this->unique is set, it deletes every requests of this type.
527 */
528 public function clean()
529 {
530 global $globals;
531
532 if ($this->unique) {
533 $success = XDB::execute('DELETE FROM requests
534 WHERE pid = {?} AND type = {?}',
535 $this->profile->id(), $this->type);
536 } else {
537 $success = XDB::execute('DELETE FROM requests
538 WHERE pid = {?} AND type = {?} AND stamp = {?}',
539 $this->profile->id(), $this->type, $this->stamp);
540 }
541 $globals->updateNbValid();
542 return $success;
543 }
544
545 // }}}
546 // {{{ function sendmail
547
548 protected function sendmail($isok)
549 {
a0fce0c6
SJ
550 // Only sends email if the profile's owner exists and is registered.
551 if ($this->ownerIsRegistered) {
552 global $globals;
4407871a 553
a0fce0c6
SJ
554 $mailer = new PlMailer();
555 $mailer->setSubject($this->_mail_subj());
556 $mailer->setFrom("validation+{$this->type}@{$globals->mail->domain}");
557 $mailer->addTo("\"{$this->profile->fullName()}\" <{$this->profileOwner->bestEmail()}>");
558 $mailer->addCc("validation+{$this->type}@{$globals->mail->domain}");
559 $body = ($this->profile->isFemale() ? "Chère camarade,\n\n" : "Cher camarade,\n\n")
560 . $this->_mail_body($isok)
561 . (Env::has('comm') ? "\n\n" . Env::v('comm') : '')
562 . "\n\nCordialement,\n-- \nL'équipe de Polytechnique.org\n"
563 . $this->_mail_ps($isok);
564 $mailer->setTxtBody(wordwrap($body));
565 $mailer->send();
566 }
4407871a
SJ
567 }
568
569 // }}}
570 // {{{ function get_typed_request()
571
572 /**
573 * @param $pid: profile's pid
574 * @param $type: request's type
575 * @param $stamp: request's timestamp
576 *
577 * Should only be used to retrieve an object in the databse with Validate::get_typed_request(...)
578 */
579 static public function get_typed_request($pid, $type, $stamp = -1)
580 {
581 if ($stamp == -1) {
582 $res = XDB::query('SELECT data
583 FROM requests
584 WHERE pid = {?} and type = {?}',
585 $pid, $type);
586 } else {
587 $res = XDB::query('SELECT data, DATE_FORMAT(stamp, "%Y%m%d%H%i%s")
588 FROM requests
589 WHERE pid = {?} AND type = {?} and stamp = {?}',
590 $pid, $type, $stamp);
591 }
592 if ($result = $res->fetchOneCell()) {
593 $result = Validate::unserialize($result);
594 } else {
595 $result = false;
596 }
597 return $result;
598 }
599
600 // }}}
601 // {{{ function get_request_by_id()
602
603 static public function get_request_by_id($id)
604 {
605 list($pid, $type, $stamp) = explode('_', $id, 3);
606 return Validate::get_typed_request($pid, $type, $stamp);
607 }
608
609 // }}}
610 // {{{ function get_typed_requests()
611
612 /** Same as get_typed_request() but return an array of objects.
613 */
614 static public function get_typed_requests($pid, $type)
615 {
616 $res = XDB::iterRow('SELECT data
617 FROM requests
328bd54a
SJ
618 WHERE pid = {?} and type = {?}
619 ORDER BY stamp',
4407871a
SJ
620 $pid, $type);
621 $array = array();
622 while (list($data) = $res->next()) {
623 $array[] = Validate::unserialize($data);
624 }
625 return $array;
626 }
627
628 // }}}
57fa97b3
SJ
629 // {{{ function get_all_typed_requests()
630
631 /** Same as get_typed_request() but return an array of objects.
632 */
633 static public function get_all_typed_requests($type)
634 {
635 $res = XDB::iterRow('SELECT data
636 FROM requests
637 WHERE type = {?}
638 ORDER BY stamp',
639 $type);
640 $array = array();
641 while (list($data) = $res->next()) {
642 $array[] = Validate::unserialize($data);
643 }
644 return $array;
645 }
646
647 // }}}
4407871a
SJ
648 // {{{ function get_typed_requests_count()
649
650 /** Same as get_typed_requests() but returns the count of available requests.
651 */
652 static public function get_typed_requests_count($pid, $type)
653 {
654 $res = XDB::query('SELECT COUNT(data)
655 FROM requests
656 WHERE pid = {?} and type = {?}',
657 $pid, $type);
658 return $res->fetchOneCell();
659 }
660
661 // }}}
616918d0 662 // {{{ function id()
4407871a
SJ
663
664 public function id()
665 {
d134ddda 666 return $this->profile->id() . '_' . $this->type . '_' . $this->stamp;
4407871a
SJ
667 }
668
669 // }}}
0337d704 670}
671
4407871a
SJ
672foreach (glob(dirname(__FILE__) . '/validations/*.inc.php') as $file) {
673 require_once $file;
0337d704 674}
675
448c8cdc 676/* vim:set expandtab shiftwidth=4 tabstop=4 softtabstop=4 foldmethod=marker fenc=utf-8: */
0337d704 677?>