]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Controllers/PdfController.php
4efdf2538ca29a97a7f08cab74484859d8109ef1
[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 * @link http://galette.tuxfamily.org
34 * @since Available since 0.9.4dev - 2019-12-05
35 */
36
37 namespace Galette\Controllers;
38
39 use Slim\Http\Request;
40 use Slim\Http\Response;
41 use Analog\Analog;
42 use Galette\Core\Links;
43 use Galette\Entity\Adherent;
44 use Galette\Entity\Contribution;
45 use Galette\Entity\PdfModel;
46 use Galette\Filters\MembersList;
47 use Galette\IO\Pdf;
48 use Galette\IO\PdfAttendanceSheet;
49 use Galette\IO\PdfContribution;
50 use Galette\IO\PdfGroups;
51 use Galette\IO\PdfMembersCards;
52 use Galette\IO\PdfMembersLabels;
53 use Galette\Repository\Members;
54 use Galette\Repository\Groups;
55 use Galette\Repository\PdfModels;
56
57 /**
58 * Galette PDF controller
59 *
60 * @category Controllers
61 * @name GaletteController
62 * @package Galette
63 * @author Johan Cwiklinski <johan@x-tnd.be>
64 * @copyright 2019 The Galette Team
65 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
66 * @link http://galette.tuxfamily.org
67 * @since Available since 0.9.4dev - 2019-12-05
68 */
69
70 class PdfController extends AbstractController
71 {
72 /**
73 * Send response
74 *
75 * @param Response $response PSR Response
76 * @param Pdf $pdf PDF to output
77 *
78 * @return Response
79 */
80 protected function sendResponse(Response $response, Pdf $pdf): Response
81 {
82 return $response
83 ->withHeader('Content-type', 'application/pdf')
84 ->withHeader('Content-Disposition', 'attachment;filename="' . $pdf->getFileName() . '"')
85 ->write($pdf->download());
86 return $response;
87 }
88
89 /**
90 * Members PDF card
91 *
92 * @param Request $request PSR Request
93 * @param Response $response PSR Response
94 * @param array $args Request arguments
95 *
96 * @return Response
97 */
98 public function membersCards(Request $request, Response $response, array $args = []): Response
99 {
100 if ($this->session->filter_members) {
101 $filters = $this->session->filter_members;
102 } else {
103 $filters = new MembersList();
104 }
105
106 if (
107 isset($args[Adherent::PK])
108 && $args[Adherent::PK] > 0
109 ) {
110 $id_adh = (int)$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 (
226 isset($get['from'])
227 && $get['from'] === 'mailing'
228 ) {
229 //if we're from mailing, we have to retrieve
230 //its unreachables members for labels
231 $mailing = $this->session->mailing;
232 $members = $mailing->unreachables;
233 } else {
234 if (count($filters->selected) == 0) {
235 Analog::log('No member selected to generate labels', Analog::INFO);
236 $this->flash->addMessage(
237 'error_detected',
238 _T("No member was selected, please check at least one name.")
239 );
240
241 return $response
242 ->withStatus(301)
243 ->withHeader('Location', $this->router->pathFor('members'));
244 }
245
246 $m = new Members();
247 $members = $m->getArrayList(
248 $filters->selected,
249 array('nom_adh', 'prenom_adh')
250 );
251 }
252
253 if (!is_array($members) || count($members) < 1) {
254 Analog::log(
255 'An error has occurred, unable to get members list.',
256 Analog::ERROR
257 );
258
259 $this->flash->addMessage(
260 'error_detected',
261 _T("Unable to get members list.")
262 );
263
264 return $response
265 ->withStatus(301)
266 ->withHeader('Location', $this->router->pathFor('members'));
267 }
268
269 $pdf = new PdfMembersLabels($this->preferences);
270 $pdf->drawLabels($members);
271
272 return $this->sendResponse($response, $pdf);
273 }
274
275 /**
276 * PDF adhesion form
277 *
278 * @param Request $request PSR Request
279 * @param Response $response PSR Response
280 * @param array $args Request arguments
281 *
282 * @return Response
283 */
284 public function adhesionForm(Request $request, Response $response, array $args = []): Response
285 {
286 $id_adh = isset($args[Adherent::PK]) ? (int)$args[Adherent::PK] : null;
287 $adh = new Adherent($this->zdb, $id_adh, ['dynamics' => true]);
288
289 if ($id_adh !== null && !$adh->canEdit($this->login)) {
290 $this->flash->addMessage(
291 'error_detected',
292 _T("You do not have permission for requested URL.")
293 );
294
295 return $response
296 ->withStatus(403)
297 ->withHeader(
298 'Location',
299 $this->router->pathFor('me')
300 );
301 }
302
303 $form = $this->preferences->pref_adhesion_form;
304 $pdf = new $form($adh, $this->zdb, $this->preferences);
305
306 return $this->sendResponse($response, $pdf);
307 }
308
309 /**
310 * PDF attendance sheet configuration page
311 *
312 * @param Request $request PSR Request
313 * @param Response $response PSR Response
314 * @param array $args Request arguments
315 *
316 * @return Response
317 */
318 public function attendanceSheetConfig(Request $request, Response $response, array $args = []): Response
319 {
320 $post = $request->getParsedBody();
321
322 if ($this->session->filter_members !== null) {
323 $filters = $this->session->filter_members;
324 } else {
325 $filters = new MembersList();
326 }
327
328 // check for ajax mode
329 $ajax = false;
330 if (
331 $request->isXhr()
332 || isset($post['ajax'])
333 && $post['ajax'] == 'true'
334 ) {
335 $ajax = true;
336
337 //retrieve selected members
338 $selection = (isset($post['selection'])) ? $post['selection'] : array();
339
340 $filters->selected = $selection;
341 $this->session->filter_members = $filters;
342 } else {
343 $selection = $filters->selected;
344 }
345
346 // display page
347 $this->view->render(
348 $response,
349 'attendance_sheet_details.tpl',
350 [
351 'page_title' => _T("Attendance sheet configuration"),
352 'ajax' => $ajax,
353 'selection' => $selection
354 ]
355 );
356 return $response;
357 }
358
359 /**
360 * PDF attendance sheet
361 *
362 * @param Request $request PSR Request
363 * @param Response $response PSR Response
364 *
365 * @return Response
366 */
367 public function attendanceSheet(Request $request, Response $response): Response
368 {
369 $post = $request->getParsedBody();
370
371 if ($this->session->filter_members !== null) {
372 $filters = $this->session->filter_members;
373 } else {
374 $filters = new MembersList();
375 }
376
377 //retrieve selected members
378 $selection = (isset($post['selection'])) ? $post['selection'] : array();
379
380 $filters->selected = $selection;
381 $this->session->filter_members = $filters;
382
383 if (count($filters->selected) == 0) {
384 Analog::log('No member selected to generate attendance sheet', Analog::INFO);
385 $this->flash->addMessage(
386 'error_detected',
387 _T("No member selected to generate attendance sheet")
388 );
389
390 return $response
391 ->withStatus(301)
392 ->withHeader('Location', $this->router->pathFor('members'));
393 }
394
395 $m = new Members();
396 $members = $m->getArrayList(
397 $filters->selected,
398 array('nom_adh', 'prenom_adh'),
399 true
400 );
401
402 if (!is_array($members) || count($members) < 1) {
403 Analog::log('No member selected to generate attendance sheet', Analog::INFO);
404 $this->flash->addMessage(
405 'error_detected',
406 _T("No member selected to generate attendance sheet")
407 );
408
409 return $response
410 ->withStatus(301)
411 ->withHeader('Location', $this->router->pathFor('members'));
412 }
413
414 $doc_title = _T("Attendance sheet");
415 if (isset($post['sheet_type']) && trim($post['sheet_type']) != '') {
416 $doc_title = $post['sheet_type'];
417 }
418
419 $data = [
420 'doc_title' => $doc_title,
421 'title' => $post['sheet_title'] ?? null,
422 'subtitle' => $post['sheet_sub_title'] ?? null,
423 'sheet_date' => $post['sheet_date'] ?? null
424 ];
425 $pdf = new PdfAttendanceSheet($this->zdb, $this->preferences, $data);
426 //with or without images?
427 if (isset($post['sheet_photos']) && $post['sheet_photos'] === '1') {
428 $pdf->withImages();
429 }
430 $pdf->drawSheet($members);
431
432 return $this->sendResponse($response, $pdf);
433 }
434
435 /**
436 * Contribution PDF
437 *
438 * @param Request $request PSR Request
439 * @param Response $response PSR Response
440 * @param array $args Request arguments
441 *
442 * @return Response
443 */
444 public function contribution(Request $request, Response $response, array $args = []): Response
445 {
446 $contribution = new Contribution($this->zdb, $this->login, (int)$args['id']);
447 if ($contribution->id == '') {
448 //not possible to load contribution, exit
449 $this->flash->addMessage(
450 'error_detected',
451 str_replace(
452 '%id',
453 $args['id'],
454 _T("Unable to load contribution #%id!")
455 )
456 );
457 return $response
458 ->withStatus(301)
459 ->withHeader('Location', $this->router->pathFor(
460 'contributions',
461 ['type' => 'contributions']
462 ));
463 } else {
464 $pdf = new PdfContribution($contribution, $this->zdb, $this->preferences);
465 return $this->sendResponse($response, $pdf);
466 }
467 }
468
469 /**
470 * Groups PDF
471 *
472 * @param Request $request PSR Request
473 * @param Response $response PSR Response
474 * @param array $args Request arguments
475 *
476 * @return Response
477 */
478 public function group(Request $request, Response $response, array $args = []): Response
479 {
480 $groups = new Groups($this->zdb, $this->login);
481
482 $groups_list = null;
483 if (isset($args['id'])) {
484 $groups_list = $groups->getList(true, $args['id']);
485 } else {
486 $groups_list = $groups->getList();
487 }
488
489 if (!is_array($groups_list) || count($groups_list) < 1) {
490 Analog::log(
491 'An error has occurred, unable to get groups list.',
492 Analog::ERROR
493 );
494
495 $this->flash->addMessage(
496 'error_detected',
497 _T("Unable to get groups list.")
498 );
499
500 return $response
501 ->withStatus(301)
502 ->withHeader('Location', $this->router->pathFor('groups'));
503 }
504
505 $pdf = new PdfGroups($this->preferences);
506 $pdf->draw($groups_list, $this->login);
507
508 return $this->sendResponse($response, $pdf);
509 }
510
511 /**
512 * PDF models list
513 *
514 * @param Request $request PSR Request
515 * @param Response $response PSR Response
516 * @param array $args Request arguments
517 *
518 * @return Response
519 */
520 public function models(Request $request, Response $response, array $args = []): Response
521 {
522 $id = 1;
523 if (isset($_POST[PdfModel::PK])) {
524 $id = (int)$_POST[PdfModel::PK];
525 } elseif (isset($args['id'])) {
526 $id = (int)$args['id'];
527 }
528
529
530 $ms = new PdfModels($this->zdb, $this->preferences, $this->login);
531 $models = $ms->getList();
532
533 $model = null;
534 foreach ($models as $m) {
535 if ($m->id === $id) {
536 $model = $m;
537 break;
538 }
539 }
540
541 $tpl = null;
542 $params = [];
543
544 //Render directly template if we called from ajax,
545 //render in a full page otherwise
546 if (
547 $request->isXhr()
548 || isset($request->getQueryParams()['ajax'])
549 && $request->getQueryParams()['ajax'] == 'true'
550 ) {
551 $tpl = 'gestion_pdf_content.tpl';
552 $params['model'] = $model;
553 } else {
554 $tpl = 'gestion_pdf.tpl';
555 $params = [
556 'page_title' => _T("PDF models"),
557 'models' => $models,
558 'model' => $model
559 ];
560 }
561
562 // display page
563 $this->view->render(
564 $response,
565 $tpl,
566 $params
567 );
568 return $response;
569 }
570
571 /**
572 * Store PDF models
573 *
574 * @param Request $request PSR Request
575 * @param Response $response PSR Response
576 * @param array $args Request arguments
577 *
578 * @return Response
579 */
580 public function storeModels(Request $request, Response $response, array $args = []): Response
581 {
582 $post = $request->getParsedBody();
583 $type = null;
584 if (isset($post['model_type'])) {
585 $type = (int)$post['model_type'];
586 }
587
588 $error_detected = [];
589 if ($type === null) {
590 $error_detected[] = _T("Missing PDF model type!");
591 } else {
592 $class = PdfModel::getTypeClass($type);
593 if (isset($post[PdfModel::PK])) {
594 $model = new $class($this->zdb, $this->preferences, (int)$_POST[PdfModel::PK]);
595 } else {
596 $model = new $class($this->zdb, $this->preferences);
597 }
598
599 try {
600 $model->header = $post['model_header'];
601 $model->footer = $post['model_footer'];
602 $model->type = $type;
603 if (isset($post['model_body'])) {
604 $model->body = $post['model_body'];
605 }
606 if (isset($post['model_title'])) {
607 $model->title = $post['model_title'];
608 }
609 if (isset($post['model_body'])) {
610 $model->subtitle = $post['model_subtitle'];
611 }
612 if (isset($post['model_styles'])) {
613 $model->styles = $post['model_styles'];
614 }
615 $res = $model->store();
616 if ($res === true) {
617 $this->flash->addMessage(
618 'success_detected',
619 _T("Model has been successfully stored!")
620 );
621 } else {
622 $error_detected[] = _T("Model has not been stored :(");
623 }
624 } catch (\Exception $e) {
625 $error_detected[] = $e->getMessage();
626 }
627 }
628
629 if (count($error_detected) > 0) {
630 foreach ($error_detected as $error) {
631 $this->flash->addMessage(
632 'error_detected',
633 $error
634 );
635 }
636 }
637
638 return $response
639 ->withStatus(301)
640 ->withHeader('Location', $this->router->pathFor('pdfModels', ['id' => $model->id]));
641 }
642
643
644 /**
645 * Get direct document
646 *
647 * @param Request $request PSR Request
648 * @param Response $response PSR Response
649 * @param array $args Request arguments
650 *
651 * @return Response
652 */
653 public function directlinkDocument(Request $request, Response $response, array $args = []): Response
654 {
655 $hash = $args['hash'];
656 $post = $request->getParsedBody();
657 $email = $post['email'];
658
659 $links = new Links($this->zdb);
660 $valid = $links->isHashValid($hash, $email);
661
662 if ($valid === false) {
663 $this->flash->addMessage(
664 'error_detected',
665 _T("Invalid link!")
666 );
667
668 return $response->withStatus(301)
669 ->withHeader('Location', $this->router->pathFor('directlink', ['hash' => $hash]));
670 }
671
672 $target = $valid[0];
673 $id = $valid[1];
674
675 if ($target === Links::TARGET_MEMBERCARD) {
676 $m = new Members();
677 $members = $m->getArrayList(
678 [$id],
679 array('nom_adh', 'prenom_adh'),
680 true
681 );
682
683 if (!is_array($members) || count($members) < 1) {
684 Analog::log(
685 'An error has occurred, unable to get members list.',
686 Analog::ERROR
687 );
688
689 $this->flash->addMessage(
690 'error_detected',
691 _T("Unable to get members list.")
692 );
693
694 return $response
695 ->withStatus(301)
696 ->withHeader('Location', $this->router->pathFor('directlink', ['hash' => $hash]));
697 }
698
699 $pdf = new PdfMembersCards($this->preferences);
700 $pdf->drawCards($members);
701 } else {
702 $contribution = new Contribution($this->zdb, $this->login, $id);
703 if ($contribution->id == '') {
704 //not possible to load contribution, exit
705 $this->flash->addMessage(
706 'error_detected',
707 str_replace(
708 '%id',
709 $args['id'],
710 _T("Unable to load contribution #%id!")
711 )
712 );
713 return $response
714 ->withStatus(301)
715 ->withHeader('Location', $this->router->pathFor(
716 'directlink',
717 ['hash' => $hash]
718 ));
719 } else {
720 $pdf = new PdfContribution($contribution, $this->zdb, $this->preferences);
721 }
722 }
723
724 return $this->sendResponse($response, $pdf);
725 }
726 }