Merge commit 'origin/fusionax' into account
[platal.git] / modules / xnetevents.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2009 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 define('NB_PER_PAGE', 25);
23
24 class XnetEventsModule extends PLModule
25 {
26 function handlers()
27 {
28 return array(
29 '%grp/events' => $this->make_hook('events', AUTH_MDP),
30 '%grp/events/sub' => $this->make_hook('sub', AUTH_MDP),
31 '%grp/events/csv' => $this->make_hook('csv', AUTH_MDP, 'user', NO_HTTPS),
32 '%grp/events/ical' => $this->make_hook('ical', AUTH_MDP, 'user', NO_HTTPS),
33 '%grp/events/edit' => $this->make_hook('edit', AUTH_MDP, 'groupadmin'),
34 '%grp/events/admin' => $this->make_hook('admin', AUTH_MDP, 'groupmember'),
35 );
36 }
37
38 function handler_events(&$page, $archive = null)
39 {
40 global $globals;
41
42 $page->changeTpl('xnetevents/index.tpl');
43 $action = null;
44 $archive = ($archive == 'archive' && may_update());
45
46 if (Post::has('del')) {
47 $action = 'del';
48 $eid = Post::v('del');
49 } elseif (Post::has('archive')) {
50 $action = 'archive';
51 $eid = Post::v('archive');
52 } elseif (Post::has('unarchive')) {
53 $action = 'unarchive';
54 $eid = Post::v('unarchive');
55 }
56
57 if (!is_null($action)) {
58 if (!may_update()) {
59 return PL_FORBIDDEN;
60 }
61 S::assert_xsrf_token();
62
63 $res = XDB::query("SELECT asso_id, short_name FROM groupex.evenements
64 WHERE eid = {?} AND asso_id = {?}",
65 $eid, $globals->asso('id'));
66
67 $tmp = $res->fetchOneRow();
68 if (!$tmp) {
69 return PL_FORBIDDEN;
70 }
71 }
72
73 if ($action == 'del') {
74 // deletes the event mailing aliases
75 if ($tmp[1]) {
76 XDB::execute(
77 "DELETE FROM virtual WHERE type = 'evt' AND alias LIKE {?}",
78 $tmp[1].'-absents@%');
79 XDB::execute(
80 "DELETE FROM virtual WHERE type = 'evt' AND alias LIKE {?}",
81 $tmp[1].'-participants@%');
82 }
83
84 // deletes the event items
85 XDB::execute("DELETE FROM groupex.evenements_items WHERE eid = {?}", $eid);
86
87 // deletes the event participants
88 XDB::execute("DELETE FROM groupex.evenements_participants
89 WHERE eid = {?}", $eid);
90
91 // deletes the event
92 XDB::execute("DELETE FROM groupex.evenements
93 WHERE eid = {?} AND asso_id = {?}",
94 $eid, $globals->asso('id'));
95
96 // delete the requests for payments
97 require_once 'validations.inc.php';
98 XDB::execute("DELETE FROM requests
99 WHERE type = 'paiements' AND data LIKE {?}",
100 PayReq::same_event($eid, $globals->asso('id')));
101 $globals->updateNbValid();
102 }
103
104 if ($action == 'archive') {
105 XDB::execute("UPDATE groupex.evenements
106 SET archive = 1
107 WHERE eid = {?} AND asso_id = {?}",
108 $eid, $globals->asso('id'));
109 }
110
111 if ($action == 'unarchive') {
112 XDB::execute("UPDATE groupex.evenements
113 SET archive = 0
114 WHERE eid = {?} AND asso_id = {?}",
115 $eid, $globals->asso('id'));
116 }
117
118 $page->assign('archive', $archive);
119 $evenements = XDB::iterator('SELECT e.*, LEFT(10, e.debut) AS first_day, LEFT(10, e.fin) AS last_day,
120 IF(e.deadline_inscription,
121 e.deadline_inscription >= LEFT(NOW(), 10),
122 1) AS inscr_open,
123 e.deadline_inscription,
124 MAX(ep.nb) IS NOT NULL AS inscrit, MAX(ep.paid) AS paid
125 FROM groupex.evenements AS e
126 LEFT JOIN groupex.evenements_participants AS ep ON (ep.eid = e.eid AND ep.uid = {?})
127 WHERE asso_id = {?} AND archive = {?}
128 GROUP BY e.eid
129 ORDER BY inscr_open DESC, debut DESC',
130 S::i('uid'), $globals->asso('id'), $archive ? 1 : 0);
131
132 $evts = array();
133 $undisplayed_events = 0;
134 $this->load('xnetevents.inc.php');
135
136 while ($e = $evenements->next()) {
137 if (!is_member() && !may_update() && !$e['accept_nonmembre']) {
138 $undisplayed_events ++;
139 continue;
140 }
141
142 $e['show_participants'] = ($e['show_participants'] && (is_member() || may_update()));
143 $e['moments'] = XDB::fetchAllAssoc('SELECT titre, details, montant, ei.item_id, nb, ep.paid
144 FROM groupex.evenements_items AS ei
145 LEFT JOIN groupex.evenements_participants AS ep
146 ON (ep.eid = ei.eid AND ep.item_id = ei.item_id AND ep.uid = {?})
147 WHERE ei.eid = {?}',
148 S::i('uid'), $e['eid']);
149
150 $e['topay'] = 0;
151 $e['paid'] = $e['moments'][0]['paid'];
152 foreach ($e['moments'] as $m) {
153 $e['topay'] += $m['nb'] * $m['montant'];
154 }
155
156 $query = XDB::query(
157 "SELECT montant
158 FROM {$globals->money->mpay_tprefix}transactions AS t
159 WHERE ref = {?} AND uid = {?}", $e['paiement_id'], S::v('uid'));
160 $montants = $query->fetchColumn();
161
162 foreach ($montants as $m) {
163 $p = strtr(substr($m, 0, strpos($m, 'EUR')), ',', '.');
164 $e['paid'] += trim($p);
165 }
166
167 make_event_date($e);
168
169 if (Env::has('updated') && $e['eid'] == Env::i('updated')) {
170 $page->assign('updated', $e);
171 }
172 $evts[] = $e;
173 }
174
175 $page->assign('evenements', $evts);
176 $page->assign('undisplayed_events', $undisplayed_events);
177 }
178
179 function handler_sub(&$page, $eid = null)
180 {
181 $this->load('xnetevents.inc.php');
182 $page->changeTpl('xnetevents/subscribe.tpl');
183
184 $evt = get_event_detail($eid);
185 if (is_null($evt)) {
186 return PL_NOT_FOUND;
187 }
188 if ($evt === false) {
189 global $globals, $platal;
190 $url = $globals->asso('sub_url');
191 if (empty($url)) {
192 $url = $platal->ns . 'subscribe';
193 }
194 $page->kill('Cet événement est reservé aux membres du groupe ' . $globals->asso('nom') .
195 '. Pour devenir membre, rends-toi sur la page de <a href="' . $url . '">demande d\'inscripton</a>.');
196 }
197
198 if (!$evt['inscr_open']) {
199 $page->kill('Les inscriptions pour cet événement sont closes');
200 }
201 if (!$evt['accept_nonmembre'] && !is_member() && !may_update()) {
202 $page->kill('Cet événement est fermé aux non-membres du groupe');
203 }
204
205 global $globals;
206 $res = XDB::query("SELECT stamp FROM requests
207 WHERE type = 'paiements' AND data LIKE {?}",
208 PayReq::same_event($evt['eid'], $globals->asso('id')));
209 $page->assign('validation', $res->numRows());
210 $page->assign('event', $evt);
211
212 if (!Post::has('submit')) {
213 return;
214 } else {
215 S::assert_xsrf_token();
216 }
217
218 $moments = Post::v('moment', array());
219 $pers = Post::v('personnes', array());
220 $subs = array();
221
222 foreach ($moments as $j => $v) {
223 $subs[$j] = intval($v);
224
225 // retreive ohter field when more than one person
226 if ($subs[$j] == 2) {
227 if (!isset($pers[$j]) || !is_numeric($pers[$j])
228 || $pers[$j] < 0)
229 {
230 $page->trigError('Tu dois choisir un nombre d\'invités correct !');
231 return;
232 }
233 $subs[$j] = 1 + $pers[$j];
234 }
235 }
236
237 // impossible to unsubscribe if you already paid sthing
238 if (!array_sum($subs) && $evt['paid'] != 0) {
239 $page->trigError("Impossible de te désinscrire complètement ".
240 "parce que tu as fait un paiement par ".
241 "chèque ou par liquide. Contacte un ".
242 "administrateur du groupe si tu es sûr de ".
243 "ne pas venir");
244 return;
245 }
246
247 // update actual inscriptions
248 $updated = false;
249 $total = 0;
250 $paid = $evt['paid'] ? $evt['paid'] : 0;
251 $telepaid= $evt['telepaid'] ? $evt['telepaid'] : 0;
252 foreach ($subs as $j => $nb) {
253 if ($nb >= 0) {
254 XDB::execute(
255 "REPLACE INTO groupex.evenements_participants
256 VALUES ({?}, {?}, {?}, {?}, {?}, {?})",
257 $eid, S::v('uid'), $j, $nb, Env::has('notify_payment') ? 'notify_payment' : '',
258 $j == 1 ? $paid - $telepaid : 0);
259 $updated = $eid;
260 } else {
261 XDB::execute(
262 "DELETE FROM groupex.evenements_participants
263 WHERE eid = {?} AND uid = {?} AND item_id = {?}",
264 $eid, S::v("uid"), $j);
265 $updated = $eid;
266 }
267 $total += $nb;
268 }
269 if ($updated !== false) {
270 $page->trigSuccess('Ton inscription à l\'événement a été mise à jour avec succès.');
271 subscribe_lists_event($total, S::i('uid'), $evt);
272 }
273 $page->assign('event', get_event_detail($eid));
274 }
275
276 function handler_csv(&$page, $eid = null, $item_id = null)
277 {
278 $this->load('xnetevents.inc.php');
279
280 if (!is_numeric($item_id)) {
281 $item_id = null;
282 }
283
284 $evt = get_event_detail($eid, $item_id);
285 if (!$evt) {
286 return PL_NOT_FOUND;
287 }
288
289 header('Content-type: text/x-csv; encoding=UTF-8');
290 header('Pragma: ');
291 header('Cache-Control: ');
292
293 $page->changeTpl('xnetevents/csv.tpl', NO_SKIN);
294
295 $admin = may_update();
296
297 $tri = (Env::v('order') == 'alpha' ? UserFilter::sortByPromo() : UserFilter::sortByName());
298
299 $page->assign('participants',
300 get_event_participants($evt, $item_id, $tri));
301
302 $page->assign('admin', $admin);
303 $page->assign('moments', $evt['moments']);
304 $page->assign('money', $evt['money']);
305 $page->assign('telepayment', $evt['paiement_id']);
306 $page->assign('tout', !Env::v('item_id', false));
307 }
308
309 function handler_ical(&$page, $eid = null)
310 {
311 global $globals;
312
313 $this->load('xnetevents.inc.php');
314 $evt = get_event_detail($eid);
315 if (!$evt) {
316 return PL_FORBIDDEN;
317 }
318 $evt['debut'] = preg_replace('/(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/', "\\1\\2\\3T\\4\\5\\6", $evt['debut']);
319 $evt['fin'] = preg_replace('/(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/', "\\1\\2\\3T\\4\\5\\6", $evt['fin']);
320
321 foreach ($evt['moments'] as $m) {
322 $evt['descriptif'] .= "\n\n** " . $m['titre'] . " **\n" . $m['details'];
323 }
324
325 $page->changeTpl('xnetevents/calendar.tpl', NO_SKIN);
326
327 require_once('ical.inc.php');
328 $page->assign('asso', $globals->asso());
329 $page->assign('timestamp', time());
330 $page->assign('admin', may_update());
331
332 if (may_update()) {
333 $page->assign('participants', get_event_participants($evt, null, UserFilter::sortByPromo()));
334 }
335 $page->register_function('display_ical', 'display_ical');
336 $page->assign_by_ref('e', $evt);
337
338 header('Content-Type: text/calendar; charset=utf-8');
339 }
340
341 function handler_edit(&$page, $eid = null)
342 {
343 global $globals;
344
345 // get eid if the the given one is a short name
346 if (!is_null($eid) && !is_numeric($eid)) {
347 $res = XDB::query("SELECT eid
348 FROM groupex.evenements
349 WHERE asso_id = {?} AND short_name = {?}",
350 $globals->asso('id'), $eid);
351 if ($res->numRows()) {
352 $eid = (int)$res->fetchOneCell();
353 }
354 }
355
356 // check the event is in our group
357 if (!is_null($eid)) {
358 $res = XDB::query("SELECT short_name
359 FROM groupex.evenements
360 WHERE eid = {?} AND asso_id = {?}",
361 $eid, $globals->asso('id'));
362 if ($res->numRows()) {
363 $infos = $res->fetchOneAssoc();
364 } else {
365 return PL_FORBIDDEN;
366 }
367 }
368
369 $page->changeTpl('xnetevents/edit.tpl');
370
371 $moments = range(1, 4);
372 $error = false;
373 $page->assign('moments', $moments);
374
375 if (Post::v('intitule')) {
376 S::assert_xsrf_token();
377
378 $this->load('xnetevents.inc.php');
379 $short_name = event_change_shortname($page, $eid,
380 $infos['short_name'],
381 Env::v('short_name', ''));
382 if ($short_name != Env::v('short_name')) {
383 $error = true;
384 }
385 $evt = array(
386 'eid' => $eid,
387 'asso_id' => $globals->asso('id'),
388 'paiement_id' => Post::v('paiement_id') > 0 ? Post::v('paiement_id') : null,
389 'debut' => Post::v('deb_Year').'-'.Post::v('deb_Month')
390 .'-'.Post::v('deb_Day').' '.Post::v('deb_Hour')
391 .':'.Post::v('deb_Minute').':00',
392 'fin' => Post::v('fin_Year').'-'.Post::v('fin_Month')
393 .'-'.Post::v('fin_Day').' '.Post::v('fin_Hour')
394 .':'.Post::v('fin_Minute').':00',
395 'short_name' => $short_name,
396 );
397
398 $trivial = array('intitule', 'descriptif', 'noinvite',
399 'show_participants', 'accept_nonmembre', 'organisateur_uid');
400 foreach ($trivial as $k) {
401 $evt[$k] = Post::v($k);
402 }
403 if (!$eid) {
404 $evt['organisateur_uid'] = S::v('uid');
405 }
406
407 if (Post::v('deadline')) {
408 $evt['deadline_inscription'] = Post::v('inscr_Year').'-'
409 . Post::v('inscr_Month').'-'
410 . Post::v('inscr_Day');
411 } else {
412 $evt['deadline_inscription'] = null;
413 }
414
415 // Store the modifications in the database
416 XDB::execute('REPLACE INTO groupex.evenements
417 SET eid={?}, asso_id={?}, organisateur_uid={?}, intitule={?},
418 paiement_id = {?}, descriptif = {?}, debut = {?},
419 fin = {?}, show_participants = {?}, short_name = {?},
420 deadline_inscription = {?}, noinvite = {?},
421 accept_nonmembre = {?}',
422 $evt['eid'], $evt['asso_id'], $evt['organisateur_uid'],
423 $evt['intitule'], $evt['paiement_id'], $evt['descriptif'],
424 $evt['debut'], $evt['fin'], $evt['show_participants'],
425 $evt['short_name'], $evt['deadline_inscription'],
426 $evt['noinvite'], $evt['accept_nonmembre']);
427
428 // if new event, get its id
429 if (!$eid) {
430 $eid = XDB::insertId();
431 }
432
433 $nb_moments = 0;
434 $money_defaut = 0;
435
436 foreach ($moments as $i) {
437 if (Post::v('titre'.$i)) {
438 $nb_moments++;
439
440 $montant = strtr(Post::v('montant'.$i), ',', '.');
441 $money_defaut += (float)$montant;
442 XDB::execute("
443 REPLACE INTO groupex.evenements_items
444 VALUES ({?}, {?}, {?}, {?}, {?})",
445 $eid, $i, Post::v('titre'.$i),
446 Post::v('details'.$i), $montant);
447 } else {
448 XDB::execute("DELETE FROM groupex.evenements_items
449 WHERE eid = {?} AND item_id = {?}", $eid, $i);
450 }
451 }
452 // request for a new payment
453 if (Post::v('paiement_id') == -1 && $money_defaut >= 0) {
454 require_once 'validations.inc.php';
455 $p = new PayReq(S::user(),
456 Post::v('intitule')." - ".$globals->asso('nom'),
457 Post::v('site'), $money_defaut,
458 Post::v('confirmation'), 0, 999,
459 $globals->asso('id'), $eid);
460 if ($p->accept()) {
461 $p->submit();
462 } else {
463 $page->assign('paiement_message', Post::v('confirmation'));
464 $page->assign('paiement_site', Post::v('site'));
465 $error = true;
466 }
467 }
468
469 // events with no sub-event: add a sub-event with no name
470 if ($nb_moments == 0) {
471 XDB::execute("INSERT INTO groupex.evenements_items
472 VALUES ({?}, {?}, '', '', 0)", $eid, 1);
473 }
474
475 if (!$error) {
476 pl_redirect('events');
477 }
478 }
479
480 // get a list of all the payment for this asso
481 $res = XDB::iterator("SELECT id, text
482 FROM {$globals->money->mpay_tprefix}paiements
483 WHERE asso_id = {?}", $globals->asso('id'));
484 $paiements = array();
485 while ($a = $res->next()) $paiements[$a['id']] = $a['text']; {
486 $page->assign('paiements', $paiements);
487 }
488
489 // when modifying an old event retreive the old datas
490 if ($eid) {
491 $res = XDB::query(
492 "SELECT eid, intitule, descriptif, debut, fin, organisateur_uid,
493 show_participants, paiement_id, short_name,
494 deadline_inscription, noinvite, accept_nonmembre
495 FROM groupex.evenements
496 WHERE eid = {?}", $eid);
497 $evt = $res->fetchOneAssoc();
498 // find out if there is already a request for a payment for this event
499 require_once 'validations.inc.php';
500 $res = XDB::query("SELECT stamp FROM requests
501 WHERE type = 'paiements' AND data LIKE {?}",
502 PayReq::same_event($eid, $globals->asso('id')));
503 $stamp = $res->fetchOneCell();
504 if ($stamp) {
505 $evt['paiement_id'] = -2;
506 $evt['paiement_req'] = $stamp;
507 }
508 $page->assign('evt', $evt);
509 // get all the different moments infos
510 $res = XDB::iterator(
511 "SELECT item_id, titre, details, montant
512 FROM groupex.evenements_items AS ei
513 INNER JOIN groupex.evenements AS e ON(e.eid = ei.eid)
514 WHERE e.eid = {?}
515 ORDER BY item_id", $eid);
516 $items = array();
517 while ($item = $res->next()) {
518 $items[$item['item_id']] = $item;
519 }
520 $page->assign('items', $items);
521 }
522 $page->assign('url_ref', $eid);
523 }
524
525 function handler_admin(&$page, $eid = null, $item_id = null)
526 {
527 global $globals;
528
529 $this->load('xnetevents.inc.php');
530
531 $evt = get_event_detail($eid, $item_id);
532 if (!$evt) {
533 return PL_NOT_FOUND;
534 }
535
536 $page->changeTpl('xnetevents/admin.tpl');
537 if (!$evt['show_participants'] && !may_update()) {
538 return PL_FORBIDDEN;
539 }
540
541 if (may_update() && Post::v('adm')) {
542 S::assert_xsrf_token();
543
544 $member = get_infos(Post::v('mail'));
545 if (!$member) {
546 $page->trigError("Membre introuvable");
547 }
548
549 // change the price paid by a participant
550 if (Env::v('adm') == 'prix' && $member) {
551 XDB::execute("UPDATE groupex.evenements_participants
552 SET paid = IF(paid + {?} > 0, paid + {?}, 0)
553 WHERE uid = {?} AND eid = {?} AND item_id = 1",
554 strtr(Env::v('montant'), ',', '.'),
555 strtr(Env::v('montant'), ',', '.'),
556 $member['uid'], $evt['eid']);
557 }
558
559 // change the number of personns coming with a participant
560 if (Env::v('adm') == 'nbs' && $member) {
561 $res = XDB::query("SELECT paid
562 FROM groupex.evenements_participants
563 WHERE uid = {?} AND eid = {?}",
564 $member['uid'], $evt['eid']);
565
566 $paid = intval($res->fetchOneCell());
567 $nbs = Post::v('nb', array());
568
569 foreach ($nbs as $id => $nb) {
570 $nb = max(intval($nb), 0);
571 XDB::execute("REPLACE INTO groupex.evenements_participants
572 VALUES ({?}, {?}, {?}, {?}, {?}, {?})",
573 $evt['eid'], $member['uid'], $id, $nb, '', $id == 1 ? $paid : 0);
574 }
575
576 $res = XDB::query("SELECT COUNT(uid) AS cnt, SUM(nb) AS nb
577 FROM groupex.evenements_participants
578 WHERE uid = {?} AND eid = {?}
579 GROUP BY uid",
580 $member['uid'], $evt['eid']);
581 $u = $res->fetchOneAssoc();
582 $u = $u['cnt'] ? $u['nb'] : null;
583 subscribe_lists_event($u, $member['uid'], $evt);
584 }
585
586 $evt = get_event_detail($eid, $item_id);
587 }
588
589 $page->assign_by_ref('evt', $evt);
590 $page->assign('tout', is_null($item_id));
591
592 if (count($evt['moments'])) {
593 $page->assign('moments', $evt['moments']);
594 }
595
596 $page->assign('alphabet', array());
597 if ($evt['paiement_id']) {
598 $infos = User::getBulkUsersWithUIDs(
599 XDB::fetchAllAssoc('SELECT t.uid, t.montant
600 FROM ' . $globals->money->mpay_tprefix . 'transactions AS t
601 LEFT JOIN groupex.evenements_participants AS ep ON(ep.uid = t.uid AND ep.eid = {?})
602 WHERE t.ref = {?} AND ep.uid IS NULL',
603 $evt['eid'], $evt['paiement_id']),
604 'uid', 'user');
605 $page->assign('oublis', count($infos));
606 $page->assign('oubliinscription', $infos);
607 }
608
609 $absents = User::getBulkUsersFromDB('SELECT p.uid
610 FROM groupex.evenements_participants AS p
611 LEFT JOIN groupex.evenements_participants AS p2 ON (p2.uid = p.uid
612 AND p2.eid = p.eid
613 AND p2.nb != 0)
614 WHERE p.eid = {?} AND p2.eid IS NULL
615 GROUP BY p.uid', $evt['eid']);
616
617 $ofs = Env::i('offset');
618 $tot = (Env::v('initiale') ? $tot : $nb_tot);
619 $nbp = ceil($tot / NB_PER_PAGE);
620 if ($nbp > 1) {
621 $links = array();
622 if ($ofs) {
623 $links['précédent'] = $ofs - 1;
624 }
625 for ($i = 1 ; $i <= $nbp; $i++) {
626 $links[(string)$i] = $i - 1;
627 }
628 if ($ofs < $nbp) {
629 $links['suivant'] = $ofs+1;
630 }
631 $page->assign('links', $links);
632 }
633
634 $page->assign('absents', $absents);
635 $page->assign('participants',
636 get_event_participants($evt, $item_id, UserFilter::sortByName(),
637 NB_PER_PAGE, $ofs * NB_PER_PAGE));
638 }
639 }
640
641 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
642 ?>