]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Controllers/PdfController.php
fa464b1c4d792dc93d90da022b1c6a807bc7fb47
[galette.git] / galette / lib / Galette / Controllers / PdfController.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Galette PDF controller
7 *
8 * PHP version 5
9 *
10 * Copyright © 2019 The Galette Team
11 *
12 * This file is part of Galette (http://galette.tuxfamily.org).
13 *
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * @category Entity
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2019 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
33 * @version SVN: $Id$
34 * @link http://galette.tuxfamily.org
35 * @since Available since 0.9.4dev - 2019-12-05
36 */
37
38 namespace Galette\Controllers;
39
40 use Slim\Http\Request;
41 use Slim\Http\Response;
42 use Analog\Analog;
43 use Galette\Core\Links;
44 use Galette\Entity\Adherent;
45 use Galette\Entity\Contribution;
46 use Galette\Entity\PdfModel;
47 use Galette\Filters\MembersList;
48 use Galette\IO\Pdf;
49 use Galette\IO\PdfAttendanceSheet;
50 use Galette\IO\PdfContribution;
51 use Galette\IO\PdfGroups;
52 use Galette\IO\PdfMembersCards;
53 use Galette\IO\PdfMembersLabels;
54 use Galette\Repository\Members;
55 use Galette\Repository\Groups;
56 use Galette\Repository\PdfModels;
57
58 /**
59 * Galette PDF controller
60 *
61 * @category Controllers
62 * @name GaletteController
63 * @package Galette
64 * @author Johan Cwiklinski <johan@x-tnd.be>
65 * @copyright 2019 The Galette Team
66 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
67 * @link http://galette.tuxfamily.org
68 * @since Available since 0.9.4dev - 2019-12-05
69 */
70
71 class PdfController extends AbstractController
72 {
73 /**
74 * Send response
75 *
76 * @param Response $response PSR Response
77 * @param Pdf $pdf PDF to output
78 *
79 * @return Response
80 */
81 protected function sendResponse(Response $response, Pdf $pdf) :Response
82 {
83 return $response
84 ->withHeader('Content-type', 'application/pdf')
85 ->withHeader('Content-Disposition', 'attachment;filename="' . $pdf->getFileName() . '"')
86 ->write($pdf->download());
87 return $response;
88 }
89
90 /**
91 * Members PDF card
92 *
93 * @param Request $request PSR Request
94 * @param Response $response PSR Response
95 * @param array $args Request arguments
96 *
97 * @return Response
98 */
99 public function membersCards(Request $request, Response $response, array $args = []) :Response
100 {
101 if ($this->session->filter_members) {
102 $filters = $this->session->filter_members;
103 } else {
104 $filters = new MembersList();
105 }
106
107 if (isset($args[Adherent::PK])
108 && $args[Adherent::PK] > 0
109 ) {
110 $id_adh = $args[Adherent::PK];
111 $deps = ['dynamics' => true];
112 if ($this->login->id == $id_adh) {
113 $deps['dues'] = true;
114 }
115 $adh = new Adherent(
116 $this->zdb,
117 $id_adh,
118 $deps
119 );
120 if (!$adh->canEdit($this->login)) {
121 $this->flash->addMessage(
122 'error_detected',
123 _T("You do not have permission for requested URL.")
124 );
125
126 return $response
127 ->withStatus(403)
128 ->withHeader(
129 'Location',
130 $this->router->pathFor('me')
131 );
132 }
133
134 //check if member is up to date
135 if ($this->login->id == $id_adh) {
136 if (!$adh->isUp2Date()) {
137 Analog::log(
138 'Member ' . $id_adh . ' is not up to date; cannot get his PDF member card',
139 Analog::WARNING
140 );
141 return $response
142 ->withStatus(301)
143 ->withHeader('Location', $this->router->pathFor('slash'));
144 }
145 }
146
147 // If we are called from a member's card, get unique id value
148 $unique = $id_adh;
149 } else {
150 if (count($filters->selected) == 0) {
151 Analog::log(
152 'No member selected to generate members cards',
153 Analog::INFO
154 );
155 $this->flash->addMessage(
156 'error_detected',
157 _T("No member was selected, please check at least one name.")
158 );
159
160 return $response
161 ->withStatus(301)
162 ->withHeader('Location', $this->router->pathFor('members'));
163 }
164 }
165
166 // Fill array $selected with selected ids
167 $selected = array();
168 if (isset($unique) && $unique) {
169 $selected[] = $unique;
170 } else {
171 $selected = $filters->selected;
172 }
173
174 $m = new Members();
175 $members = $m->getArrayList(
176 $selected,
177 array('nom_adh', 'prenom_adh'),
178 true
179 );
180
181 if (!is_array($members) || count($members) < 1) {
182 Analog::log(
183 'An error has occurred, unable to get members list.',
184 Analog::ERROR
185 );
186
187 $this->flash->addMessage(
188 'error_detected',
189 _T("Unable to get members list.")
190 );
191
192 return $response
193 ->withStatus(301)
194 ->withHeader('Location', $this->router->pathFor('members'));
195 }
196
197 $pdf = new PdfMembersCards($this->preferences);
198 $pdf->drawCards($members);
199
200 return $this->sendResponse($response, $pdf);
201 }
202
203 /**
204 * Members PDF label
205 *
206 * @param Request $request PSR Request
207 * @param Response $response PSR Response
208 *
209 * @return Response
210 */
211 public function membersLabels(Request $request, Response $response) :Response
212 {
213 $post = $request->getParsedBody();
214 $get = $request->getQueryParams();
215
216 $session_var = $post['session_var'] ?? $get['session_var'] ?? 'filter_members';
217
218 if (isset($this->session->$session_var)) {
219 $filters = $this->session->$session_var;
220 } else {
221 $filters = new MembersList();
222 }
223
224 $members = null;
225 if (isset($get['from'])
226 && $get['from'] === 'mailing'
227 ) {
228 //if we're from mailing, we have to retrieve
229 //its unreachables members for labels
230 $mailing = $this->session->mailing;
231 $members = $mailing->unreachables;
232 } else {
233 if (count($filters->selected) == 0) {
234 Analog::log('No member selected to generate labels', Analog::INFO);
235 $this->flash->addMessage(
236 'error_detected',
237 _T("No member was selected, please check at least one name.")
238 );
239
240 return $response
241 ->withStatus(301)
242 ->withHeader('Location', $this->router->pathFor('members'));
243 }
244
245 $m = new Members();
246 $members = $m->getArrayList(
247 $filters->selected,
248 array('nom_adh', 'prenom_adh')
249 );
250 }
251
252 if (!is_array($members) || count($members) < 1) {
253 Analog::log(
254 'An error has occurred, unable to get members list.',
255 Analog::ERROR
256 );
257
258 $this->flash->addMessage(
259 'error_detected',
260 _T("Unable to get members list.")
261 );
262
263 return $response
264 ->withStatus(301)
265 ->withHeader('Location', $this->router->pathFor('members'));
266 }
267
268 $pdf = new PdfMembersLabels($this->preferences);
269 $pdf->drawLabels($members);
270
271 return $this->sendResponse($response, $pdf);
272 }
273
274 /**
275 * PDF adhesion form
276 *
277 * @param Request $request PSR Request
278 * @param Response $response PSR Response
279 * @param array $args Request arguments
280 *
281 * @return Response
282 */
283 public function adhesionForm(Request $request, Response $response, array $args = []) :Response
284 {
285 $id_adh = isset($args[Adherent::PK]) ? (int)$args[Adherent::PK] : null;
286 $adh = new Adherent($this->zdb, $id_adh, ['dynamics' => true]);
287
288 if ($id_adh !== null && !$adh->canEdit($this->login)) {
289 $this->flash->addMessage(
290 'error_detected',
291 _T("You do not have permission for requested URL.")
292 );
293
294 return $response
295 ->withStatus(403)
296 ->withHeader(
297 'Location',
298 $this->router->pathFor('me')
299 );
300 }
301
302 $form = $this->preferences->pref_adhesion_form;
303 $pdf = new $form($adh, $this->zdb, $this->preferences);
304
305 return $this->sendResponse($response, $pdf);
306 }
307
308 /**
309 * PDF attendance sheet configuration page
310 *
311 * @param Request $request PSR Request
312 * @param Response $response PSR Response
313 * @param array $args Request arguments
314 *
315 * @return Response
316 */
317 public function attendanceSheetConfig(Request $request, Response $response, array $args = []) :Response
318 {
319 $post = $request->getParsedBody();
320
321 if ($this->session->filter_members !== null) {
322 $filters = $this->session->filter_members;
323 } else {
324 $filters = new MembersList();
325 }
326
327 // check for ajax mode
328 $ajax = false;
329 if ($request->isXhr()
330 || isset($post['ajax'])
331 && $post['ajax'] == 'true'
332 ) {
333 $ajax = true;
334
335 //retrieve selected members
336 $selection = (isset($post['selection'])) ? $post['selection'] : array();
337
338 $filters->selected = $selection;
339 $this->session->filter_members = $filters;
340 } else {
341 $selection = $filters->selected;
342 }
343
344 // display page
345 $this->view->render(
346 $response,
347 'attendance_sheet_details.tpl',
348 [
349 'page_title' => _T("Attendance sheet configuration"),
350 'ajax' => $ajax,
351 'selection' => $selection
352 ]
353 );
354 return $response;
355 }
356
357 /**
358 * PDF attendance sheet
359 *
360 * @param Request $request PSR Request
361 * @param Response $response PSR Response
362 *
363 * @return Response
364 */
365 public function attendanceSheet(Request $request, Response $response) :Response
366 {
367 $post = $request->getParsedBody();
368
369 if ($this->session->filter_members !== null) {
370 $filters = $this->session->filter_members;
371 } else {
372 $filters = new MembersList();
373 }
374
375 //retrieve selected members
376 $selection = (isset($post['selection'])) ? $post['selection'] : array();
377
378 $filters->selected = $selection;
379 $this->session->filter_members = $filters;
380
381 if (count($filters->selected) == 0) {
382 Analog::log('No member selected to generate attendance sheet', Analog::INFO);
383 $this->flash->addMessage(
384 'error_detected',
385 _T("No member selected to generate attendance sheet")
386 );
387
388 return $response
389 ->withStatus(301)
390 ->withHeader('Location', $this->router->pathFor('members'));
391 }
392
393 $m = new Members();
394 $members = $m->getArrayList(
395 $filters->selected,
396 array('nom_adh', 'prenom_adh'),
397 true
398 );
399
400 if (!is_array($members) || count($members) < 1) {
401 Analog::log('No member selected to generate attendance sheet', Analog::INFO);
402 $this->flash->addMessage(
403 'error_detected',
404 _T("No member selected to generate attendance sheet")
405 );
406
407 return $response
408 ->withStatus(301)
409 ->withHeader('Location', $this->router->pathFor('members'));
410 }
411
412 $doc_title = _T("Attendance sheet");
413 if (isset($post['sheet_type']) && trim($post['sheet_type']) != '') {
414 $doc_title = $post['sheet_type'];
415 }
416
417 $data = [
418 'doc_title' => $doc_title,
419 'title' => $post['sheet_title'] ?? null,
420 'subtitle' => $post['sheet_sub_title'] ?? null,
421 'sheet_date'=> $post['sheet_date'] ?? null
422 ];
423 $pdf = new PdfAttendanceSheet($this->zdb, $this->preferences, $data);
424 //with or without images?
425 if (isset($post['sheet_photos']) && $post['sheet_photos'] === '1') {
426 $pdf->withImages();
427 }
428 $pdf->drawSheet($members);
429
430 return $this->sendResponse($response, $pdf);
431 }
432
433 /**
434 * Contribution PDF
435 *
436 * @param Request $request PSR Request
437 * @param Response $response PSR Response
438 * @param array $args Request arguments
439 *
440 * @return Response
441 */
442 public function contribution(Request $request, Response $response, array $args = []) :Response
443 {
444 $contribution = new Contribution($this->zdb, $this->login, (int)$args['id']);
445 if ($contribution->id == '') {
446 //not possible to load contribution, exit
447 $this->flash->addMessage(
448 'error_detected',
449 str_replace(
450 '%id',
451 $args['id'],
452 _T("Unable to load contribution #%id!")
453 )
454 );
455 return $response
456 ->withStatus(301)
457 ->withHeader('Location', $this->router->pathFor(
458 'contributions',
459 ['type' => 'contributions']
460 ));
461 } else {
462 $pdf = new PdfContribution($contribution, $this->zdb, $this->preferences);
463 return $this->sendResponse($response, $pdf);
464 }
465 }
466
467 /**
468 * Groups PDF
469 *
470 * @param Request $request PSR Request
471 * @param Response $response PSR Response
472 * @param array $args Request arguments
473 *
474 * @return Response
475 */
476 public function group(Request $request, Response $response, array $args = []) :Response
477 {
478 $groups = new Groups($this->zdb, $this->login);
479
480 $groups_list = null;
481 if (isset($args['id'])) {
482 $groups_list = $groups->getList(true, $args['id']);
483 } else {
484 $groups_list = $groups->getList();
485 }
486
487 if (!is_array($groups_list) || count($groups_list) < 1) {
488 Analog::log(
489 'An error has occurred, unable to get groups list.',
490 Analog::ERROR
491 );
492
493 $this->flash->addMessage(
494 'error_detected',
495 _T("Unable to get groups list.")
496 );
497
498 return $response
499 ->withStatus(301)
500 ->withHeader('Location', $this->router->pathFor('groups'));
501 }
502
503 $pdf = new PdfGroups($this->preferences);
504 $pdf->draw($groups_list, $this->login);
505
506 return $this->sendResponse($response, $pdf);
507 }
508
509 /**
510 * PDF models list
511 *
512 * @param Request $request PSR Request
513 * @param Response $response PSR Response
514 * @param array $args Request arguments
515 *
516 * @return Response
517 */
518 public function models(Request $request, Response $response, array $args = []) :Response
519 {
520 $id = 1;
521 if (isset($_POST[PdfModel::PK])) {
522 $id = (int)$_POST[PdfModel::PK];
523 } elseif (isset($args['id'])) {
524 $id = (int)$args['id'];
525 }
526
527
528 $ms = new PdfModels($this->zdb, $this->preferences, $this->login);
529 $models = $ms->getList();
530
531 $model = null;
532 foreach ($models as $m) {
533 if ($m->id === $id) {
534 $model = $m;
535 break;
536 }
537 }
538
539 $tpl = null;
540 $params = [];
541
542 //Render directly template if we called from ajax,
543 //render in a full page otherwise
544 if ($request->isXhr()
545 || isset($request->getQueryParams()['ajax'])
546 && $request->getQueryParams()['ajax'] == 'true'
547 ) {
548 $tpl = 'gestion_pdf_content.tpl';
549 $params['model'] = $model;
550 } else {
551 $tpl = 'gestion_pdf.tpl';
552 $params = [
553 'page_title' => _T("PDF models"),
554 'models' => $models,
555 'model' => $model
556 ];
557 }
558
559 // display page
560 $this->view->render(
561 $response,
562 $tpl,
563 $params
564 );
565 return $response;
566 }
567
568 /**
569 * Store PDF models
570 *
571 * @param Request $request PSR Request
572 * @param Response $response PSR Response
573 * @param array $args Request arguments
574 *
575 * @return Response
576 */
577 public function storeModels(Request $request, Response $response, array $args = []) :Response
578 {
579 $post = $request->getParsedBody();
580 $type = null;
581 if (isset($post['model_type'])) {
582 $type = (int)$post['model_type'];
583 }
584
585 if ($type === null) {
586 $this->flash->addMessage(
587 'error_detected',
588 _T("Missing PDF model type!")
589 );
590 } else {
591 $class = PdfModel::getTypeClass($type);
592 if (isset($post[PdfModel::PK])) {
593 $model = new $class($this->zdb, $this->preferences, (int)$_POST[PdfModel::PK]);
594 } else {
595 $model = new $class($this->zdb, $this->preferences);
596 }
597
598 try {
599 $model->header = $post['model_header'];
600 $model->footer = $post['model_footer'];
601 $model->type = $type;
602 if (isset($post['model_body'])) {
603 $model->body = $post['model_body'];
604 }
605 if (isset($post['model_title'])) {
606 $model->title = $post['model_title'];
607 }
608 if (isset($post['model_body'])) {
609 $model->subtitle = $post['model_subtitle'];
610 }
611 if (isset($post['model_styles'])) {
612 $model->styles = $post['model_styles'];
613 }
614 $res = $model->store();
615 if ($res === true) {
616 $this->flash->addMessage(
617 'success_detected',
618 _T("Model has been successfully stored!")
619 );
620 } else {
621 $this->flash->addMessage(
622 'error_detected',
623 _T("Model has not been stored :(")
624 );
625 }
626 } catch (\Exception $e) {
627 $error_detected[] = $e->getMessage();
628 }
629 }
630
631 return $response
632 ->withStatus(301)
633 ->withHeader('Location', $this->router->pathFor('pdfModels', ['id' => $model->id]));
634 }
635
636
637 /**
638 * Get direct document
639 *
640 * @param Request $request PSR Request
641 * @param Response $response PSR Response
642 * @param array $args Request arguments
643 *
644 * @return Response
645 */
646 public function directlinkDocument(Request $request, Response $response, array $args = []) :Response
647 {
648 $hash = $args['hash'];
649 $post = $request->getParsedBody();
650 $email = $post['email'];
651
652 $links = new Links($this->zdb);
653 $valid = $links->isHashValid($hash, $email);
654
655 if ($valid === false) {
656 $this->flash->addMessage(
657 'error_detected',
658 _T("Invalid link!")
659 );
660
661 return $response->withStatus(301)
662 ->withHeader('Location', $this->router->pathFor('directlink', ['hash' => $hash]));
663 }
664
665 $target = $valid[0];
666 $id = $valid[1];
667
668 if ($target === Links::TARGET_MEMBERCARD) {
669 $m = new Members();
670 $members = $m->getArrayList(
671 [$id],
672 array('nom_adh', 'prenom_adh'),
673 true
674 );
675
676 if (!is_array($members) || count($members) < 1) {
677 Analog::log(
678 'An error has occurred, unable to get members list.',
679 Analog::ERROR
680 );
681
682 $this->flash->addMessage(
683 'error_detected',
684 _T("Unable to get members list.")
685 );
686
687 return $response
688 ->withStatus(301)
689 ->withHeader('Location', $this->router->pathFor('directlink', ['hash' => $hash]));
690 }
691
692 $pdf = new PdfMembersCards($this->preferences);
693 $pdf->drawCards($members);
694 } else {
695 $contribution = new Contribution($this->zdb, $this->login, $id);
696 if ($contribution->id == '') {
697 //not possible to load contribution, exit
698 $this->flash->addMessage(
699 'error_detected',
700 str_replace(
701 '%id',
702 $args['id'],
703 _T("Unable to load contribution #%id!")
704 )
705 );
706 return $response
707 ->withStatus(301)
708 ->withHeader('Location', $this->router->pathFor(
709 'directlink',
710 ['hash' => $hash]
711 ));
712 } else {
713 $pdf = new PdfContribution($contribution, $this->zdb, $this->preferences);
714 }
715 }
716
717 return $this->sendResponse($response, $pdf);
718 }
719 }