]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Controllers/Crud/MembersController.php
Fix none required adding member
[galette.git] / galette / lib / Galette / Controllers / Crud / MembersController.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Galette members controller
7 *
8 * PHP version 5
9 *
10 * Copyright © 2019-2020 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 Controllers
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2019-2020 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-02
35 */
36
37 namespace Galette\Controllers\Crud;
38
39 use Galette\Controllers\CrudController;
40 use Slim\Http\Request;
41 use Slim\Http\Response;
42 use Galette\Core\Authentication;
43 use Galette\Core\GaletteMail;
44 use Galette\Core\Gaptcha;
45 use Galette\Core\Password;
46 use Galette\Core\Picture;
47 use Galette\Entity\Adherent;
48 use Galette\Entity\Contribution;
49 use Galette\Entity\ContributionsTypes;
50 use Galette\Entity\DynamicFieldsHandle;
51 use Galette\Entity\Group;
52 use Galette\Entity\Status;
53 use Galette\Entity\FieldsConfig;
54 use Galette\Filters\AdvancedMembersList;
55 use Galette\Filters\MembersList;
56 use Galette\IO\File;
57 use Galette\IO\MembersCsv;
58 use Galette\Repository\Groups;
59 use Galette\Repository\Members;
60 use Galette\Repository\PaymentTypes;
61 use Galette\Repository\Titles;
62 use Analog\Analog;
63
64 /**
65 * Galette members controller
66 *
67 * @category Controllers
68 * @name GaletteController
69 * @package Galette
70 * @author Johan Cwiklinski <johan@x-tnd.be>
71 * @copyright 2019-2020 The Galette Team
72 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
73 * @link http://galette.tuxfamily.org
74 * @since Available since 0.9.4dev - 2019-12-02
75 */
76
77 class MembersController extends CrudController
78 {
79 /** @var boolean */
80 private $is_self_membership = false;
81
82 // CRUD - Create
83
84 /**
85 * Add page
86 *
87 * @param Request $request PSR Request
88 * @param Response $response PSR Response
89 *
90 * @return Response
91 */
92 public function add(Request $request, Response $response): Response
93 {
94 return $this->edit($request, $response, null, 'add');
95 }
96
97 /**
98 * Self subscription page
99 *
100 * @param Request $request PSR Request
101 * @param Response $response PSR Response
102 *
103 * @return Response
104 */
105 public function selfSubscribe(Request $request, Response $response): Response
106 {
107 if (!$this->preferences->pref_bool_selfsubscribe || $this->login->isLogged()) {
108 return $response
109 ->withStatus(301)
110 ->withHeader('Location', $this->router->pathFor('slash'));
111 }
112
113 if ($this->session->member !== null) {
114 $member = $this->session->member;
115 $this->session->member = null;
116 } else {
117 $deps = [
118 'dynamics' => true
119 ];
120 $member = new Adherent($this->zdb, null, $deps);
121 }
122
123 //mark as self membership
124 $member->setSelfMembership();
125
126 // flagging required fields
127 $fc = $this->fields_config;
128 $form_elements = $fc->getFormElements($this->login, true, true);
129
130 // members
131 $m = new Members();
132 $members = $m->getSelectizedMembers(
133 $this->zdb,
134 $member->hasParent() ? $member->parent->id : null
135 );
136
137 $params = [
138 'members' => [
139 'filters' => $m->getFilters(),
140 'count' => $m->getCount()
141 ]
142 ];
143
144 if (count($members)) {
145 $params['members']['list'] = $members;
146 }
147
148 $gaptcha = new Gaptcha($this->i18n);
149 $this->session->gaptcha = $gaptcha;
150 // display page
151 $this->view->render(
152 $response,
153 'member.tpl',
154 array(
155 'page_title' => _T("Subscription"),
156 'parent_tpl' => 'public_page.tpl',
157 'member' => $member,
158 'self_adh' => true,
159 'autocomplete' => true,
160 // pseudo random int
161 'time' => time(),
162 'titles_list' => Titles::getList($this->zdb),
163 'fieldsets' => $form_elements['fieldsets'],
164 'hidden_elements' => $form_elements['hiddens'],
165 //self_adh specific
166 'gaptcha' => $gaptcha
167 ) + $params
168 );
169 return $response;
170 }
171
172 /**
173 * Add action
174 *
175 * @param Request $request PSR Request
176 * @param Response $response PSR Response
177 *
178 * @return Response
179 */
180 public function doAdd(Request $request, Response $response): Response
181 {
182 return $this->store($request, $response);
183 }
184
185 /**
186 * Self subscription add action
187 *
188 * @param Request $request PSR Request
189 * @param Response $response PSR Response
190 *
191 * @return Response
192 */
193 public function doSelfSubscribe(Request $request, Response $response): Response
194 {
195 $this->setSelfMembership();
196 return $this->doAdd($request, $response);
197 }
198
199
200 /**
201 * Duplicate action
202 *
203 * @param Request $request PSR Request
204 * @param Response $response PSR Response
205 * @param integer $id_adh Member ID to duplicate
206 *
207 * @return Response
208 */
209 public function duplicate(Request $request, Response $response, int $id_adh): Response
210 {
211 $adh = new Adherent($this->zdb, $id_adh, ['dynamics' => true, 'parent' => true]);
212 $adh->setDuplicate();
213
214 //store entity in session
215 $this->session->member = $adh;
216
217 return $response
218 ->withStatus(301)
219 ->withHeader('Location', $this->router->pathFor('addMember'));
220 }
221
222 // /CRUD - Create
223 // CRUD - Read
224
225 /**
226 * Display member card
227 *
228 * @param Request $request PSR Request
229 * @param Response $response PSR Response
230 * @param integer $id Member ID
231 *
232 * @return Response
233 */
234 public function show(Request $request, Response $response, int $id): Response
235 {
236 $deps = array(
237 'picture' => true,
238 'groups' => true,
239 'dues' => true,
240 'parent' => true,
241 'children' => true,
242 'dynamics' => true
243 );
244 $member = new Adherent($this->zdb, $id, $deps);
245
246 if (!$member->canEdit($this->login)) {
247 $this->flash->addMessage(
248 'error_detected',
249 _T("You do not have permission for requested URL.")
250 );
251
252 return $response
253 ->withStatus(301)
254 ->withHeader(
255 'Location',
256 $this->router->pathFor('me')
257 );
258 }
259
260 if ($member->id == null) {
261 //member does not exists!
262 $this->flash->addMessage(
263 'error_detected',
264 str_replace('%id', $id, _T("No member #%id."))
265 );
266
267 return $response
268 ->withStatus(404)
269 ->withHeader(
270 'Location',
271 $this->router->pathFor('slash')
272 );
273 }
274
275 // flagging fields visibility
276 $fc = $this->fields_config;
277 $display_elements = $fc->getDisplayElements($this->login);
278
279 // display page
280 $this->view->render(
281 $response,
282 'voir_adherent.tpl',
283 array(
284 'page_title' => _T("Member Profile"),
285 'member' => $member,
286 'pref_lang' => $this->i18n->getNameFromId($member->language),
287 'pref_card_self' => $this->preferences->pref_card_self,
288 'groups' => Groups::getSimpleList(),
289 'time' => time(),
290 'display_elements' => $display_elements
291 )
292 );
293 return $response;
294 }
295
296 /**
297 * Own card show
298 *
299 * @param Request $request PSR Request
300 * @param Response $response PSR Response
301 *
302 * @return Response
303 */
304 public function showMe(Request $request, Response $response): Response
305 {
306 if ($this->login->isSuperAdmin()) {
307 return $response
308 ->withStatus(301)
309 ->withHeader('Location', $this->router->pathFor('slash'));
310 }
311 return $this->show($request, $response, $this->login->id);
312 }
313
314 /**
315 * Public pages (trombinoscope, public list)
316 *
317 * @param Request $request PSR Request
318 * @param Response $response PSR Response
319 * @param string $option One of 'page' or 'order'
320 * @param string|integer $value Value of the option
321 * @param string $type List type (either list or trombi)
322 *
323 * @return Response
324 */
325 public function publicList(
326 Request $request,
327 Response $response,
328 $option = null,
329 $value = null,
330 $type = null
331 ): Response {
332 $varname = 'public_filter_' . $type;
333 if (isset($this->session->$varname)) {
334 $filters = $this->session->$varname;
335 } else {
336 $filters = new MembersList();
337 }
338
339 if ($option !== null) {
340 switch ($option) {
341 case 'page':
342 $filters->current_page = (int)$value;
343 break;
344 case 'order':
345 $filters->orderby = $value;
346 break;
347 }
348 }
349
350 $m = new Members($filters);
351 $members = $m->getPublicList($type === 'trombi');
352
353 $this->session->$varname = $filters;
354
355 //assign pagination variables to the template and add pagination links
356 $filters->setSmartyPagination($this->router, $this->view->getSmarty(), false);
357
358 // display page
359 $this->view->render(
360 $response,
361 ($type === 'list' ? 'liste_membres' : 'trombinoscope') . '.tpl',
362 array(
363 'page_title' => ($type === 'list' ? _T("Members list") : _T('Trombinoscope')),
364 'additionnal_html_class' => ($type === 'list' ? '' : 'trombinoscope'),
365 'type' => $type,
366 'members' => $members,
367 'nb_members' => $m->getCount(),
368 'filters' => $filters
369 )
370 );
371 return $response;
372 }
373
374 /**
375 * Public pages (trombinoscope, public list)
376 *
377 * @param Request $request PSR Request
378 * @param Response $response PSR Response
379 * @param string $type Type
380 *
381 * @return Response
382 */
383 public function filterPublicList(Request $request, Response $response, string $type): Response
384 {
385 $post = $request->getParsedBody();
386
387 $varname = 'public_filter_' . $type;
388 if (isset($this->session->$varname)) {
389 $filters = $this->session->$varname;
390 } else {
391 $filters = new MembersList();
392 }
393
394 //reintialize filters
395 if (isset($post['clear_filter'])) {
396 $filters->reinit();
397 } else {
398 //number of rows to show
399 if (isset($post['nbshow'])) {
400 $filters->show = $post['nbshow'];
401 }
402 }
403
404 $this->session->$varname = $filters;
405
406 return $response
407 ->withStatus(301)
408 ->withHeader('Location', $this->router->pathFor('publicList', ['type' => $type]));
409 }
410
411 /**
412 * Get a dynamic file
413 *
414 * @param Request $request PSR Request
415 * @param Response $response PSR Response
416 * @param integer $id Member ID
417 * @param integer $fid Dynamic fields ID
418 * @param integer $pos Dynamic field position
419 * @param string $name File name
420 *
421 * @return Response
422 */
423 public function getDynamicFile(
424 Request $request,
425 Response $response,
426 int $id,
427 int $fid,
428 int $pos,
429 string $name
430 ): Response {
431 $deps = array(
432 'picture' => false,
433 'groups' => false,
434 'dues' => false,
435 'parent' => false,
436 'children' => false,
437 'dynamics' => true
438 );
439 $member = new Adherent($this->zdb, $id, $deps);
440
441 $denied = null;
442 if (!$member->canEdit($this->login)) {
443 $fields = $member->getDynamicFields()->getFields();
444 if (!isset($fields[$fid])) {
445 //field does not exists or access is forbidden
446 $denied = true;
447 } else {
448 $denied = false;
449 }
450 }
451
452 if ($denied === true) {
453 $this->flash->addMessage(
454 'error_detected',
455 _T("You do not have permission for requested URL.")
456 );
457
458 return $response
459 ->withStatus(403)
460 ->withHeader(
461 'Location',
462 $this->router->pathFor(
463 'member',
464 ['id' => $id]
465 )
466 );
467 }
468
469 $filename = str_replace(
470 [
471 '%mid',
472 '%fid',
473 '%pos'
474 ],
475 [
476 $id,
477 $fid,
478 $pos
479 ],
480 'member_%mid_field_%fid_value_%pos'
481 );
482
483 if (file_exists(GALETTE_FILES_PATH . $filename)) {
484 $type = File::getMimeType(GALETTE_FILES_PATH . $filename);
485
486 $response = $response->withHeader('Content-Description', 'File Transfer')
487 ->withHeader('Content-Type', $type)
488 ->withHeader('Content-Disposition', 'attachment;filename="' . $name . '"')
489 ->withHeader('Pragma', 'no-cache')
490 ->withHeader('Content-Transfer-Encoding', 'binary')
491 ->withHeader('Expires', '0')
492 ->withHeader('Cache-Control', 'must-revalidate')
493 ->withHeader('Pragma', 'public');
494
495 $stream = fopen('php://memory', 'r+');
496 fwrite($stream, file_get_contents(GALETTE_FILES_PATH . $filename));
497 rewind($stream);
498
499 return $response->withBody(new \Slim\Http\Stream($stream));
500 } else {
501 Analog::log(
502 'A request has been made to get a dynamic file named `' .
503 $filename . '` that does not exists.',
504 Analog::WARNING
505 );
506
507 $this->flash->addMessage(
508 'error_detected',
509 _T("The file does not exists or cannot be read :(")
510 );
511
512 return $response
513 ->withStatus(404)
514 ->withHeader(
515 'Location',
516 $this->router->pathFor('member', ['id' => $id])
517 );
518 }
519 }
520
521 /**
522 * Members list
523 *
524 * @param Request $request PSR Request
525 * @param Response $response PSR Response
526 * @param string $option One of 'page' or 'order'
527 * @param string|integer $value Value of the option
528 *
529 * @return Response
530 */
531 public function list(Request $request, Response $response, $option = null, $value = null): Response
532 {
533 if (isset($this->session->filter_members)) {
534 $filters = $this->session->filter_members;
535 } else {
536 $filters = new MembersList();
537 }
538
539 if ($option !== null) {
540 switch ($option) {
541 case 'page':
542 $filters->current_page = (int)$value;
543 break;
544 case 'order':
545 $filters->orderby = $value;
546 break;
547 }
548 }
549
550 $members = new Members($filters);
551
552 $members_list = array();
553 if ($this->login->isAdmin() || $this->login->isStaff()) {
554 $members_list = $members->getMembersList(true);
555 } else {
556 $members_list = $members->getManagedMembersList(true);
557 }
558
559 $groups = new Groups($this->zdb, $this->login);
560 $groups_list = $groups->getList();
561
562 //assign pagination variables to the template and add pagination links
563 $filters->setSmartyPagination($this->router, $this->view->getSmarty(), false);
564 $filters->setViewCommonsFilters($this->preferences, $this->view->getSmarty());
565
566 $this->session->filter_members = $filters;
567
568 // display page
569 $this->view->render(
570 $response,
571 'gestion_adherents.tpl',
572 array(
573 'page_title' => _T("Members management"),
574 'require_mass' => true,
575 'members' => $members_list,
576 'filter_groups_options' => $groups_list,
577 'nb_members' => $members->getCount(),
578 'filters' => $filters,
579 'adv_filters' => $filters instanceof AdvancedMembersList,
580 'galette_list' => $this->lists_config->getDisplayElements($this->login)
581 )
582 );
583 return $response;
584 }
585
586 /**
587 * Members filtering
588 *
589 * @param Request $request PSR Request
590 * @param Response $response PSR Response
591 *
592 * @return Response
593 */
594 public function filter(Request $request, Response $response): Response
595 {
596 $post = $request->getParsedBody();
597 if (isset($this->session->filter_members)) {
598 //CAUTION: this one may be simple or advanced, display must change
599 $filters = $this->session->filter_members;
600 } else {
601 $filters = new MembersList();
602 }
603
604 //reintialize filters
605 if (isset($post['clear_filter'])) {
606 $filters = new MembersList();
607 } elseif (isset($post['clear_adv_filter'])) {
608 $this->session->filter_members = null;
609 unset($this->session->filter_members);
610
611 return $response
612 ->withStatus(301)
613 ->withHeader('Location', $this->router->pathFor('advanced-search'));
614 } elseif (isset($post['adv_criteria'])) {
615 return $response
616 ->withStatus(301)
617 ->withHeader('Location', $this->router->pathFor('advanced-search'));
618 } else {
619 //string to filter
620 if (isset($post['filter_str'])) { //filter search string
621 $filters->filter_str = stripslashes(
622 htmlspecialchars($post['filter_str'], ENT_QUOTES)
623 );
624 }
625 //field to filter
626 if (isset($post['field_filter'])) {
627 if (is_numeric($post['field_filter'])) {
628 $filters->field_filter = $post['field_filter'];
629 }
630 }
631 //membership to filter
632 if (isset($post['membership_filter'])) {
633 if (is_numeric($post['membership_filter'])) {
634 $filters->membership_filter
635 = $post['membership_filter'];
636 }
637 }
638 //account status to filter
639 if (isset($post['filter_account'])) {
640 if (is_numeric($post['filter_account'])) {
641 $filters->filter_account = $post['filter_account'];
642 }
643 }
644 //email filter
645 if (isset($post['email_filter'])) {
646 $filters->email_filter = (int)$post['email_filter'];
647 }
648 //group filter
649 if (
650 isset($post['group_filter'])
651 && $post['group_filter'] > 0
652 ) {
653 $filters->group_filter = (int)$post['group_filter'];
654 }
655 //number of rows to show
656 if (isset($post['nbshow'])) {
657 $filters->show = $post['nbshow'];
658 }
659
660 if (isset($post['advanced_filtering'])) {
661 if (!$filters instanceof AdvancedMembersList) {
662 $filters = new AdvancedMembersList($filters);
663 }
664 //Advanced filters
665 $filters->reinit();
666 unset($post['advanced_filtering']);
667 $freed = false;
668 foreach ($post as $k => $v) {
669 if (strpos($k, 'free_', 0) === 0) {
670 if (!$freed) {
671 $i = 0;
672 foreach ($post['free_field'] as $f) {
673 if (
674 trim($f) !== ''
675 && trim($post['free_text'][$i]) !== ''
676 ) {
677 $fs_search = $post['free_text'][$i];
678 $log_op
679 = (int)$post['free_logical_operator'][$i];
680 $qry_op
681 = (int)$post['free_query_operator'][$i];
682 $type = (int)$post['free_type'][$i];
683 $fs = array(
684 'idx' => $i,
685 'field' => $f,
686 'type' => $type,
687 'search' => $fs_search,
688 'log_op' => $log_op,
689 'qry_op' => $qry_op
690 );
691 $filters->free_search = $fs;
692 }
693 $i++;
694 }
695 $freed = true;
696 }
697 } elseif ($k == 'groups_search') {
698 $i = 0;
699 $filters->groups_search_log_op = (int)$post['groups_logical_operator'];
700 foreach ($post['groups_search'] as $g) {
701 if (trim($g) !== '') {
702 $gs = array(
703 'idx' => $i,
704 'group' => $g
705 );
706 $filters->groups_search = $gs;
707 }
708 $i++;
709 }
710 } else {
711 switch ($k) {
712 case 'contrib_min_amount':
713 case 'contrib_max_amount':
714 if (trim($v) !== '') {
715 $v = (float)$v;
716 } else {
717 $v = null;
718 }
719 break;
720 }
721 $filters->$k = $v;
722 }
723 }
724 }
725 }
726
727 if (isset($post['savesearch'])) {
728 return $response
729 ->withStatus(301)
730 ->withHeader(
731 'Location',
732 $this->router->pathFor(
733 'saveSearch',
734 $post
735 )
736 );
737 }
738
739 $this->session->filter_members = $filters;
740
741 return $response
742 ->withStatus(301)
743 ->withHeader('Location', $this->router->pathFor('members'));
744 }
745
746 /**
747 * Advanced search page
748 *
749 * @param Request $request PSR Request
750 * @param Response $response PSR Response
751 *
752 * @return Response
753 */
754 public function advancedSearch(Request $request, Response $response): Response
755 {
756 if (isset($this->session->filter_members)) {
757 $filters = $this->session->filter_members;
758 if (!$filters instanceof AdvancedMembersList) {
759 $filters = new AdvancedMembersList($filters);
760 }
761 } else {
762 $filters = new AdvancedMembersList();
763 }
764
765 $groups = new Groups($this->zdb, $this->login);
766 $groups_list = $groups->getList();
767
768 //we want only visibles fields
769 $fields = $this->members_fields;
770 $fc = $this->fields_config;
771 $visibles = $fc->getVisibilities();
772 $access_level = $this->login->getAccessLevel();
773
774 //remove not searchable fields
775 unset($fields['mdp_adh']);
776
777 foreach ($fields as $k => $f) {
778 if (
779 $visibles[$k] == FieldsConfig::NOBODY ||
780 ($visibles[$k] == FieldsConfig::ADMIN &&
781 $access_level < Authentication::ACCESS_ADMIN) ||
782 ($visibles[$k] == FieldsConfig::STAFF &&
783 $access_level < Authentication::ACCESS_STAFF) ||
784 ($visibles[$k] == FieldsConfig::MANAGER &&
785 $access_level < Authentication::ACCESS_MANAGER)
786 ) {
787 unset($fields[$k]);
788 }
789 }
790
791 //add status label search
792 if ($pos = array_search(Status::PK, array_keys($fields))) {
793 $fields = array_slice($fields, 0, $pos, true) +
794 ['status_label' => ['label' => _T('Status label')]] +
795 array_slice($fields, $pos, count($fields) - 1, true);
796 }
797
798 //dynamic fields
799 $deps = array(
800 'picture' => false,
801 'groups' => false,
802 'dues' => false,
803 'parent' => false,
804 'children' => false,
805 'dynamics' => false
806 );
807 $member = new Adherent($this->zdb, $this->login->login, $deps);
808 $adh_dynamics = new DynamicFieldsHandle($this->zdb, $this->login, $member);
809
810 $contrib = new Contribution($this->zdb, $this->login);
811 $contrib_dynamics = new DynamicFieldsHandle($this->zdb, $this->login, $contrib);
812
813 //Status
814 $statuts = new Status($this->zdb);
815
816 //Contributions types
817 $ct = new ContributionsTypes($this->zdb);
818
819 //Payments types
820 $ptypes = new PaymentTypes(
821 $this->zdb,
822 $this->preferences,
823 $this->login
824 );
825 $ptlist = $ptypes->getList();
826
827 $filters->setViewCommonsFilters($this->preferences, $this->view->getSmarty());
828
829 // display page
830 $this->view->render(
831 $response,
832 'advanced_search.tpl',
833 array(
834 'page_title' => _T("Advanced search"),
835 'filter_groups_options' => $groups_list,
836 'search_fields' => $fields,
837 'adh_dynamics' => $adh_dynamics->getFields(),
838 'contrib_dynamics' => $contrib_dynamics->getFields(),
839 'statuts' => $statuts->getList(),
840 'contributions_types' => $ct->getList(),
841 'filters' => $filters,
842 'payments_types' => $ptlist
843 )
844 );
845 return $response;
846 }
847
848 /**
849 * Members list for ajax
850 *
851 * @param Request $request PSR Request
852 * @param Response $response PSR Response
853 * @param string $option One of 'page' or 'order'
854 * @param string|integer $value Value of the option
855 *
856 * @return Response
857 */
858 public function ajaxList(Request $request, Response $response, string $option = null, $value = null): Response
859 {
860 $post = $request->getParsedBody();
861
862 if (isset($this->session->ajax_members_filters)) {
863 $filters = $this->session->ajax_members_filters;
864 } else {
865 $filters = new MembersList();
866 }
867
868 if ($option == 'page') {
869 $filters->current_page = (int)$value;
870 }
871
872 //numbers of rows to display
873 if (isset($post['nbshow']) && is_numeric($post['nbshow'])) {
874 $filters->show = $post['nbshow'];
875 }
876
877 $members = new Members($filters);
878 if (!$this->login->isAdmin() && !$this->login->isStaff()) {
879 if ($this->login->isGroupManager()) {
880 $members_list = $members->getManagedMembersList(true);
881 } else {
882 Analog::log(
883 str_replace(
884 ['%id', '%login'],
885 [$this->login->id, $this->login->login],
886 'Trying to list group members without access from #%id (%login)'
887 ),
888 Analog::ERROR
889 );
890 throw new \Exception('Access denied.');
891 }
892 } else {
893 $members_list = $members->getMembersList(true);
894 }
895
896 //assign pagination variables to the template and add pagination links
897 $filters->setSmartyPagination($this->router, $this->view->getSmarty(), false);
898
899 $this->session->ajax_members_filters = $filters;
900
901 $selected_members = null;
902 $unreachables_members = null;
903 if (!isset($post['from'])) {
904 $mailing = $this->session->mailing;
905 if (!isset($post['members'])) {
906 $selected_members = $mailing->recipients;
907 $unreachables_members = $mailing->unreachables;
908 } else {
909 $m = new Members();
910 $selected_members = $m->getArrayList($post['members']);
911 if (isset($post['unreachables']) && is_array($post['unreachables'])) {
912 $unreachables_members = $m->getArrayList($post['unreachables']);
913 }
914 }
915 } else {
916 switch ($post['from']) {
917 case 'groups':
918 if (!isset($post['gid'])) {
919 Analog::log(
920 'Trying to list group members with no group id provided',
921 Analog::ERROR
922 );
923 throw new \Exception('A group id is required.');
924 }
925 if (!isset($post['members'])) {
926 $group = new Group((int)$post['gid']);
927 $selected_members = array();
928 if (!isset($post['mode']) || $post['mode'] == 'members') {
929 $selected_members = $group->getMembers();
930 } elseif ($post['mode'] == 'managers') {
931 $selected_members = $group->getManagers();
932 } else {
933 Analog::log(
934 'Trying to list group members with unknown mode',
935 Analog::ERROR
936 );
937 throw new \Exception('Unknown mode.');
938 }
939 } else {
940 $m = new Members();
941 $selected_members = $m->getArrayList($post['members']);
942 if (isset($post['unreachables']) && is_array($post['unreachables'])) {
943 $unreachables_members = $m->getArrayList($post['unreachables']);
944 }
945 }
946 break;
947 case 'attach':
948 if (!isset($post['id_adh'])) {
949 throw new \RuntimeException(
950 'Current selected member must be excluded while attaching!'
951 );
952 }
953 break;
954 }
955 }
956
957 $params = [
958 'filters' => $filters,
959 'members_list' => $members_list,
960 'selected_members' => $selected_members,
961 'unreachables_members' => $unreachables_members
962 ];
963
964 if (isset($post['multiple'])) {
965 $params['multiple'] = true;
966 }
967
968 if (isset($post['gid'])) {
969 $params['the_id'] = $post['gid'];
970 }
971
972 if (isset($post['id_adh'])) {
973 $params['excluded'] = $post['id_adh'];
974 }
975
976 // display page
977 $this->view->render(
978 $response,
979 'ajax_members.tpl',
980 $params
981 );
982 return $response;
983 }
984
985 /**
986 * Batch actions handler
987 *
988 * @param Request $request PSR Request
989 * @param Response $response PSR Response
990 *
991 * @return Response
992 */
993 public function handleBatch(Request $request, Response $response): Response
994 {
995 $post = $request->getParsedBody();
996
997 if (isset($post['member_sel'])) {
998 if (isset($this->session->filter_members)) {
999 $filters = $this->session->filter_members;
1000 } else {
1001 $filters = new MembersList();
1002 }
1003
1004 $filters->selected = $post['member_sel'];
1005 $this->session->filter_members = $filters;
1006
1007 if (isset($post['cards'])) {
1008 return $response
1009 ->withStatus(301)
1010 ->withHeader('Location', $this->router->pathFor('pdf-members-cards'));
1011 }
1012
1013 if (isset($post['labels'])) {
1014 return $response
1015 ->withStatus(301)
1016 ->withHeader('Location', $this->router->pathFor('pdf-members-labels'));
1017 }
1018
1019 if (isset($post['mailing'])) {
1020 return $response
1021 ->withStatus(301)
1022 ->withHeader('Location', $this->router->pathFor('mailing') . '?mailing_new=new');
1023 }
1024
1025 if (isset($post['attendance_sheet'])) {
1026 return $response
1027 ->withStatus(301)
1028 ->withHeader('Location', $this->router->pathFor('attendance_sheet_details'));
1029 }
1030
1031 if (isset($post['csv'])) {
1032 return $response
1033 ->withStatus(301)
1034 ->withHeader('Location', $this->router->pathFor('csv-memberslist'));
1035 }
1036
1037 if (isset($post['delete'])) {
1038 return $response
1039 ->withStatus(301)
1040 ->withHeader('Location', $this->router->pathFor('removeMembers'));
1041 }
1042
1043 if (isset($post['masschange'])) {
1044 return $response
1045 ->withStatus(301)
1046 ->withHeader('Location', $this->router->pathFor('masschangeMembers'));
1047 }
1048
1049 throw new \RuntimeException('Does not know what to batch :(');
1050 } else {
1051 $this->flash->addMessage(
1052 'error_detected',
1053 _T("No member was selected, please check at least one name.")
1054 );
1055
1056 return $response
1057 ->withStatus(301)
1058 ->withHeader('Location', $this->router->pathFor('members'));
1059 }
1060 }
1061
1062 // /CRUD - Read
1063 // CRUD - Update
1064
1065 /**
1066 * Edit page
1067 *
1068 * @param Request $request PSR Request
1069 * @param Response $response PSR Response
1070 * @param mixed $id Member id/array of members id
1071 * @param string $action null or 'add'
1072 *
1073 * @return Response
1074 */
1075 public function edit(
1076 Request $request,
1077 Response $response,
1078 $id = null,
1079 $action = 'edit'
1080 ): Response {
1081 $deps = array(
1082 'picture' => true,
1083 'groups' => true,
1084 'dues' => true,
1085 'parent' => true,
1086 'children' => true,
1087 'dynamics' => true
1088 );
1089
1090 if ($this->session->member !== null) {
1091 $member = $this->session->member;
1092 $this->session->member = null;
1093 } else {
1094 $member = new Adherent($this->zdb, $id, $deps);
1095 }
1096
1097 if ($id !== null) {
1098 $member->load($id);
1099 if (!$member->canEdit($this->login)) {
1100 $this->flash->addMessage(
1101 'error_detected',
1102 _T("You do not have permission for requested URL.")
1103 );
1104
1105 return $response
1106 ->withStatus(403)
1107 ->withHeader(
1108 'Location',
1109 $this->router->pathFor('me')
1110 );
1111 }
1112 } else {
1113 if ($member->id != $id) {
1114 $member->load($this->login->id);
1115 }
1116 }
1117
1118 // flagging required fields
1119 $fc = $this->fields_config;
1120
1121 // password required if we create a new member
1122 if ($member->id != '') {
1123 $fc->setNotRequired('mdp_adh');
1124 }
1125
1126 //handle requirements for parent fields
1127 $parent_fields = $member->getParentFields();
1128 $tpl_parent_fields = []; //for JS when detaching
1129 foreach ($parent_fields as $field) {
1130 if ($fc->isRequired($field)) {
1131 $tpl_parent_fields[] = $field;
1132 if ($member->hasParent()) {
1133 $fc->setNotRequired($field);
1134 }
1135 }
1136 }
1137
1138 // flagging required fields invisible to members
1139 if ($this->login->isAdmin() || $this->login->isStaff()) {
1140 $fc->setNotRequired('activite_adh');
1141 $fc->setNotRequired('id_statut');
1142 }
1143
1144 // template variable declaration
1145 $title = _T("Member Profile");
1146 if ($member->id != '') {
1147 $title .= ' (' . _T("modification") . ')';
1148 } else {
1149 $title .= ' (' . _T("creation") . ')';
1150 }
1151
1152 //Status
1153 $statuts = new Status($this->zdb);
1154
1155 //Groups
1156 $groups = new Groups($this->zdb, $this->login);
1157 $groups_list = $groups->getSimpleList(true);
1158
1159 $form_elements = $fc->getFormElements(
1160 $this->login,
1161 $member->id == ''
1162 );
1163
1164 // members
1165 $m = new Members();
1166 $id = null;
1167 if ($member->hasParent()) {
1168 $id = ($member->parent instanceof Adherent ? $member->parent->id : $member->parent);
1169 }
1170 $members = $m->getSelectizedMembers(
1171 $this->zdb,
1172 $id
1173 );
1174
1175 $route_params['members'] = [
1176 'filters' => $m->getFilters(),
1177 'count' => $m->getCount()
1178 ];
1179
1180 if (count($members)) {
1181 $route_params['members']['list'] = $members;
1182 }
1183
1184 // display page
1185 $this->view->render(
1186 $response,
1187 'member.tpl',
1188 array(
1189 'parent_tpl' => 'page.tpl',
1190 'autocomplete' => true,
1191 'page_title' => $title,
1192 'member' => $member,
1193 'self_adh' => false,
1194 // pseudo random int
1195 'time' => time(),
1196 'titles_list' => Titles::getList($this->zdb),
1197 'statuts' => $statuts->getList(),
1198 'groups' => $groups_list,
1199 'fieldsets' => $form_elements['fieldsets'],
1200 'hidden_elements' => $form_elements['hiddens'],
1201 'parent_fields' => $tpl_parent_fields
1202 ) + $route_params
1203 );
1204 return $response;
1205 }
1206
1207 /**
1208 * Edit action
1209 *
1210 * @param Request $request PSR Request
1211 * @param Response $response PSR Response
1212 * @param integer $id Member id
1213 *
1214 * @return Response
1215 */
1216 public function doEdit(Request $request, Response $response, int $id): Response
1217 {
1218 return $this->store($request, $response);
1219 }
1220
1221 /**
1222 * Massive change page
1223 *
1224 * @param Request $request PSR Request
1225 * @param Response $response PSR Response
1226 *
1227 * @return Response
1228 */
1229 public function massChange(Request $request, Response $response): Response
1230 {
1231 $filters = $this->session->filter_members;
1232
1233 $data = [
1234 'id' => $filters->selected,
1235 'redirect_uri' => $this->router->pathFor('members')
1236 ];
1237
1238 $fc = $this->fields_config;
1239 $form_elements = $fc->getMassiveFormElements($this->members_fields, $this->login);
1240
1241 //dynamic fields
1242 $deps = array(
1243 'picture' => false,
1244 'groups' => false,
1245 'dues' => false,
1246 'parent' => false,
1247 'children' => false,
1248 'dynamics' => false
1249 );
1250 $member = new Adherent($this->zdb, null, $deps);
1251
1252 //Status
1253 $statuts = new Status($this->zdb);
1254
1255 // display page
1256 $this->view->render(
1257 $response,
1258 'mass_change_members.tpl',
1259 array(
1260 'mode' => $request->isXhr() ? 'ajax' : '',
1261 'page_title' => str_replace(
1262 '%count',
1263 count($data['id']),
1264 _T('Mass change %count members')
1265 ),
1266 'form_url' => $this->router->pathFor('masschangeMembersReview'),
1267 'cancel_uri' => $this->router->pathFor('members'),
1268 'data' => $data,
1269 'member' => $member,
1270 'fieldsets' => $form_elements['fieldsets'],
1271 'titles_list' => Titles::getList($this->zdb),
1272 'statuts' => $statuts->getList(),
1273 'require_mass' => true
1274 )
1275 );
1276 return $response;
1277 }
1278
1279 /**
1280 * Massive changes validation page
1281 *
1282 * @param Request $request PSR Request
1283 * @param Response $response PSR Response
1284 *
1285 * @return Response
1286 */
1287 public function validateMassChange(Request $request, Response $response): Response
1288 {
1289 $post = $request->getParsedBody();
1290
1291 if (!isset($post['confirm'])) {
1292 $this->flash->addMessage(
1293 'error_detected',
1294 _T("Mass changes has not been confirmed!")
1295 );
1296 } else {
1297 //we want only visibles fields
1298 $fc = $this->fields_config;
1299 $form_elements = $fc->getMassiveFormElements($this->members_fields, $this->login);
1300
1301 $changes = [];
1302 foreach ($form_elements['fieldsets'] as $form_element) {
1303 foreach ($form_element->elements as $field) {
1304 if (
1305 isset($post['mass_' . $field->field_id])
1306 && (isset($post[$field->field_id]) || $field->type === FieldsConfig::TYPE_BOOL)
1307 ) {
1308 $changes[$field->field_id] = [
1309 'label' => $field->label,
1310 'value' => $post[$field->field_id] ?? 0
1311 ];
1312 }
1313 }
1314 }
1315 }
1316
1317 $filters = $this->session->filter_members;
1318 $data = [
1319 'id' => $filters->selected,
1320 'redirect_uri' => $this->router->pathFor('members')
1321 ];
1322
1323 //Status
1324 $statuts = new Status($this->zdb);
1325
1326 // display page
1327 $this->view->render(
1328 $response,
1329 'mass_change_members.tpl',
1330 array(
1331 'mode' => $request->isXhr() ? 'ajax' : '',
1332 'page_title' => str_replace(
1333 '%count',
1334 count($data['id']),
1335 _T('Review mass change %count members')
1336 ),
1337 'form_url' => $this->router->pathFor('massstoremembers'),
1338 'cancel_uri' => $this->router->pathFor('members'),
1339 'data' => $data,
1340 'titles_list' => Titles::getList($this->zdb),
1341 'statuts' => $statuts->getList(),
1342 'changes' => $changes
1343 )
1344 );
1345 return $response;
1346 }
1347
1348 /**
1349 * Do massive changes
1350 *
1351 * @param Request $request PSR Request
1352 * @param Response $response PSR Response
1353 *
1354 * @return Response
1355 */
1356 public function doMassChange(Request $request, Response $response): Response
1357 {
1358 $post = $request->getParsedBody();
1359 $redirect_url = $post['redirect_uri'];
1360 $error_detected = [];
1361 $mass = 0;
1362
1363 unset($post['redirect_uri']);
1364 if (!isset($post['confirm'])) {
1365 $error_detected[] = _T("Mass changes has not been confirmed!");
1366 } else {
1367 unset($post['confirm']);
1368 $ids = $post['id'];
1369 unset($post['id']);
1370
1371 $fc = $this->fields_config;
1372 $form_elements = $fc->getMassiveFormElements($this->members_fields, $this->login);
1373 $disabled = $this->members_fields;
1374 foreach (array_keys($post) as $key) {
1375 $found = false;
1376 foreach ($form_elements['fieldsets'] as $fieldset) {
1377 if (isset($fieldset->elements[$key])) {
1378 $found = true;
1379 continue;
1380 }
1381 }
1382 if (!$found) {
1383 Analog::log(
1384 'Permission issue mass editing field ' . $key,
1385 Analog::WARNING
1386 );
1387 unset($post[$key]);
1388 } else {
1389 unset($disabled[$key]);
1390 }
1391 }
1392
1393 if (!count($post)) {
1394 $error_detected[] = _T("Nothing to do!");
1395 } else {
1396 foreach ($ids as $id) {
1397 $is_manager = !$this->login->isAdmin()
1398 && !$this->login->isStaff()
1399 && $this->login->isGroupManager();
1400 $deps = array(
1401 'picture' => false,
1402 'groups' => $is_manager,
1403 'dues' => false,
1404 'parent' => false,
1405 'children' => false,
1406 'dynamics' => false
1407 );
1408 $member = new Adherent($this->zdb, (int)$id, $deps);
1409 $member->setDependencies(
1410 $this->preferences,
1411 $this->members_fields,
1412 $this->history
1413 );
1414 if (!$member->canEdit($this->login)) {
1415 continue;
1416 }
1417
1418 $valid = $member->check($post, [], $disabled);
1419 if ($valid === true) {
1420 $done = $member->store();
1421 if (!$done) {
1422 $error_detected[] = _T("An error occurred while storing the member.");
1423 } else {
1424 ++$mass;
1425 }
1426 } else {
1427 $error_detected = array_merge($error_detected, $valid);
1428 }
1429 }
1430 }
1431 }
1432
1433 if ($mass == 0 && !count($error_detected)) {
1434 $error_detected[] = _T('Something went wront during mass edition!');
1435 } else {
1436 $this->flash->addMessage(
1437 'success_detected',
1438 str_replace(
1439 '%count',
1440 $mass,
1441 _T('%count members has been changed successfully!')
1442 )
1443 );
1444 }
1445
1446 if (count($error_detected) > 0) {
1447 foreach ($error_detected as $error) {
1448 $this->flash->addMessage(
1449 'error_detected',
1450 $error
1451 );
1452 }
1453 }
1454
1455 if (!$request->isXhr()) {
1456 return $response
1457 ->withStatus(301)
1458 ->withHeader('Location', $redirect_url);
1459 } else {
1460 return $response->withJson(
1461 [
1462 'success' => count($error_detected) === 0
1463 ]
1464 );
1465 }
1466 }
1467
1468 /**
1469 * Store
1470 *
1471 * @param Request $request PSR Request
1472 * @param Response $response PSR Response
1473 *
1474 * @return Response
1475 */
1476 public function store(Request $request, Response $response): Response
1477 {
1478 if (!$this->preferences->pref_bool_selfsubscribe && !$this->login->isLogged()) {
1479 return $response
1480 ->withStatus(301)
1481 ->withHeader('Location', $this->router->pathFor('slash'));
1482 }
1483
1484 $post = $request->getParsedBody();
1485 $deps = array(
1486 'picture' => true,
1487 'groups' => true,
1488 'dues' => true,
1489 'parent' => true,
1490 'children' => true,
1491 'dynamics' => true
1492 );
1493 $member = new Adherent($this->zdb, null, $deps);
1494 $member->setDependencies(
1495 $this->preferences,
1496 $this->members_fields,
1497 $this->history
1498 );
1499
1500 $success_detected = [];
1501 $warning_detected = [];
1502 $error_detected = [];
1503
1504 if ($this->isSelfMembership() && !isset($post[Adherent::PK])) {
1505 //mark as self membership
1506 $member->setSelfMembership();
1507
1508 //check captcha
1509 $gaptcha = $this->session->gaptcha;
1510 if (!$gaptcha->check($post['gaptcha'])) {
1511 $error_detected[] = _T('Invalid captcha');
1512 }
1513 }
1514
1515 // new or edit
1516 if ($this->login->isAdmin() || $this->login->isStaff() || $this->login->isGroupManager()) {
1517 if (isset($post['id_adh'])) {
1518 $member->load((int)$post['id_adh']);
1519 if (!$member->canEdit($this->login)) {
1520 //redirection should have been done before. Just throw an Exception.
1521 throw new \RuntimeException(
1522 str_replace(
1523 '%id',
1524 $member->id,
1525 'No right to store member #%id'
1526 )
1527 );
1528 }
1529 }
1530 } else {
1531 $member->load($this->login->id);
1532 }
1533
1534 // flagging required fields
1535 $fc = $this->fields_config;
1536
1537 // password required if we create a new member but not from self subscription
1538 if ($member->id != '' || $this->isSelfMembership()) {
1539 $fc->setNotRequired('mdp_adh');
1540 }
1541
1542 if (
1543 $member->hasParent() && !isset($post['detach_parent'])
1544 || isset($post['parent_id']) && !empty($post['parent_id'])
1545 ) {
1546 $parent_fields = $member->getParentFields();
1547 foreach ($parent_fields as $field) {
1548 if ($fc->isRequired($field)) {
1549 $fc->setNotRequired($field);
1550 }
1551 }
1552 }
1553
1554 // flagging required fields invisible to members
1555 if ($this->login->isAdmin() || $this->login->isStaff()) {
1556 $fc->setNotRequired('activite_adh');
1557 $fc->setNotRequired('id_statut');
1558 }
1559
1560 $form_elements = $fc->getFormElements(
1561 $this->login,
1562 $member->id == '',
1563 $this->isSelfMembership()
1564 );
1565 $fieldsets = $form_elements['fieldsets'];
1566 $required = array();
1567 $disabled = array();
1568
1569 foreach ($fieldsets as $category) {
1570 foreach ($category->elements as $field) {
1571 if ($field->required == true) {
1572 $required[$field->field_id] = true;
1573 }
1574 if ($field->disabled == true) {
1575 $disabled[$field->field_id] = true;
1576 } elseif (!isset($post[$field->field_id])) {
1577 switch ($field->field_id) {
1578 //unchecked booleans are not sent from form
1579 case 'bool_admin_adh':
1580 case 'bool_exempt_adh':
1581 case 'bool_display_info':
1582 $post[$field->field_id] = 0;
1583 break;
1584 }
1585 }
1586 }
1587 }
1588
1589 $real_requireds = array_diff(array_keys($required), array_keys($disabled));
1590
1591 // Validation
1592 $redirect_url = $this->router->pathFor('member', ['id' => $member->id]);
1593 if (!count($real_requireds) || isset($post[array_shift($real_requireds)])) {
1594 // regular fields
1595 $valid = $member->check($post, $required, $disabled);
1596 if ($valid !== true) {
1597 $error_detected = array_merge($error_detected, $valid);
1598 }
1599
1600 if (count($error_detected) == 0) {
1601 //all goes well, we can proceed
1602
1603 $new = false;
1604 if ($member->id == '') {
1605 $new = true;
1606 }
1607
1608 // send email to member
1609 if ($this->isSelfMembership() || isset($post['mail_confirm']) && $post['mail_confirm'] == '1') {
1610 $member->setSendmail(); //flag to send creation email
1611 }
1612
1613 $store = $member->store();
1614 if ($store === true) {
1615 //member has been stored :)
1616 if ($new) {
1617 if ($this->isSelfMembership()) {
1618 $success_detected[] = _T("Your account has been created!");
1619 if (
1620 $this->preferences->pref_mail_method > GaletteMail::METHOD_DISABLED
1621 && $member->getEmail() != ''
1622 ) {
1623 $success_detected[] = _T("An email has been sent to you, check your inbox.");
1624 }
1625 } else {
1626 $success_detected[] = _T("New member has been successfully added.");
1627 }
1628 } else {
1629 $success_detected[] = _T("Member account has been modified.");
1630 }
1631
1632 //store requested groups
1633 $groups_adh = $post['groups_adh'] ?? null;
1634 $managed_groups_adh = $post['groups_managed_adh'] ?? null;
1635
1636 //add/remove user from groups
1637 $add_groups = Groups::addMemberToGroups(
1638 $member,
1639 $groups_adh
1640 );
1641
1642 if ($add_groups === false) {
1643 $error_detected[] = _T("An error occurred adding member to its groups.");
1644 }
1645
1646 //add/remove manager from groups
1647 $add_groups = Groups::addMemberToGroups(
1648 $member,
1649 $managed_groups_adh,
1650 true
1651 );
1652 $member->loadGroups();
1653
1654 if ($add_groups === false) {
1655 $error_detected[] = _T("An error occurred adding member to its groups as manager.");
1656 }
1657 } else {
1658 //something went wrong :'(
1659 $error_detected[] = _T("An error occurred while storing the member.");
1660 }
1661 }
1662
1663 if (count($error_detected) === 0) {
1664 $files_res = $member->handleFiles($_FILES);
1665 if (is_array($files_res)) {
1666 $error_detected = array_merge($error_detected, $files_res);
1667 }
1668
1669 if (isset($post['del_photo'])) {
1670 if (!$member->picture->delete($member->id)) {
1671 $error_detected[] = _T("Delete failed");
1672 $str_adh = $member->id . ' (' . $member->sname . ' ' . ')';
1673 Analog::log(
1674 'Unable to delete picture for member ' . $str_adh,
1675 Analog::ERROR
1676 );
1677 }
1678 }
1679 }
1680
1681 if (count($error_detected) > 0) {
1682 foreach ($error_detected as $error) {
1683 if (strpos($error, '%member_url_') !== false) {
1684 preg_match('/%member_url_(\d+)/', $error, $matches);
1685 $url = $this->router->pathFor('member', ['id' => $matches[1]]);
1686 $error = str_replace(
1687 '%member_url_' . $matches[1],
1688 $url,
1689 $error
1690 );
1691 }
1692 $this->flash->addMessage(
1693 'error_detected',
1694 $error
1695 );
1696 }
1697 }
1698
1699 if (count($warning_detected) > 0) {
1700 foreach ($warning_detected as $warning) {
1701 $this->flash->addMessage(
1702 'warning_detected',
1703 $warning
1704 );
1705 }
1706 }
1707 if (count($success_detected) > 0) {
1708 foreach ($success_detected as $success) {
1709 $this->flash->addMessage(
1710 'success_detected',
1711 $success
1712 );
1713 }
1714 }
1715
1716 if (count($error_detected) === 0) {
1717 if ($this->isSelfMembership()) {
1718 $redirect_url = $this->router->pathFor('login');
1719 } elseif (
1720 isset($post['redirect_on_create'])
1721 && $post['redirect_on_create'] > Adherent::AFTER_ADD_DEFAULT
1722 ) {
1723 switch ($post['redirect_on_create']) {
1724 case Adherent::AFTER_ADD_TRANS:
1725 $redirect_url = $this->router->pathFor('addTransaction');
1726 break;
1727 case Adherent::AFTER_ADD_NEW:
1728 $redirect_url = $this->router->pathFor('addMember');
1729 break;
1730 case Adherent::AFTER_ADD_SHOW:
1731 $redirect_url = $this->router->pathFor('member', ['id' => $member->id]);
1732 break;
1733 case Adherent::AFTER_ADD_LIST:
1734 $redirect_url = $this->router->pathFor('members');
1735 break;
1736 case Adherent::AFTER_ADD_HOME:
1737 $redirect_url = $this->router->pathFor('slash');
1738 break;
1739 }
1740 } elseif (!isset($post['id_adh']) && !$member->isDueFree()) {
1741 $redirect_url = $this->router->pathFor(
1742 'addContribution',
1743 ['type' => 'fee']
1744 ) . '?id_adh=' . $member->id;
1745 } else {
1746 $redirect_url = $this->router->pathFor('member', ['id' => $member->id]);
1747 }
1748 } else {
1749 //store entity in session
1750 $this->session->member = $member;
1751
1752 if ($this->isSelfMembership()) {
1753 $redirect_url = $this->router->pathFor('subscribe');
1754 } else {
1755 if ($member->id) {
1756 $redirect_url = $this->router->pathFor(
1757 'editMember',
1758 ['id' => $member->id]
1759 );
1760 } else {
1761 $redirect_url = $this->router->pathFor('addMember');
1762 }
1763 }
1764 }
1765 }
1766
1767 return $response
1768 ->withStatus(301)
1769 ->withHeader('Location', $redirect_url);
1770 }
1771
1772
1773 // /CRUD - Update
1774 // CRUD - Delete
1775
1776 /**
1777 * Get redirection URI
1778 *
1779 * @param array $args Route arguments
1780 *
1781 * @return string
1782 */
1783 public function redirectUri(array $args)
1784 {
1785 return $this->router->pathFor('members');
1786 }
1787
1788 /**
1789 * Get form URI
1790 *
1791 * @param array $args Route arguments
1792 *
1793 * @return string
1794 */
1795 public function formUri(array $args)
1796 {
1797 return $this->router->pathFor(
1798 'doRemoveMember',
1799 $args
1800 );
1801 }
1802
1803
1804 /**
1805 * Get ID to remove
1806 *
1807 * In simple cases, we get the ID in the route arguments; but for
1808 * batchs, it should be found elsewhere.
1809 * In post values, we look for id key, as well as all {sthing}_sel keys (like members_sel or contrib_sel)
1810 *
1811 * @param array $args Request arguments
1812 * @param array $post POST values
1813 *
1814 * @return null|integer|integer[]
1815 */
1816 protected function getIdsToRemove(&$args, $post)
1817 {
1818 if (isset($args['id'])) {
1819 return $args['id'];
1820 } else {
1821 $filters = $this->session->filter_members;
1822 return $filters->selected;
1823 }
1824 }
1825
1826 /**
1827 * Get confirmation removal page title
1828 *
1829 * @param array $args Route arguments
1830 *
1831 * @return string
1832 */
1833 public function confirmRemoveTitle(array $args)
1834 {
1835 if (isset($args['id_adh']) || isset($args['id'])) {
1836 //one member removal
1837 $id_adh = $args['id_adh'] ?? $args['id'];
1838 $adh = new Adherent($this->zdb, (int)$id_adh);
1839 return sprintf(
1840 _T('Remove member %1$s'),
1841 $adh->sfullname
1842 );
1843 } else {
1844 //batch members removal
1845 $filters = $this->session->filter_members;
1846 return str_replace(
1847 '%count',
1848 count($filters->selected),
1849 _T('You are about to remove %count members.')
1850 );
1851 }
1852 }
1853
1854 /**
1855 * Remove object
1856 *
1857 * @param array $args Route arguments
1858 * @param array $post POST values
1859 *
1860 * @return boolean
1861 */
1862 protected function doDelete(array $args, array $post)
1863 {
1864 if (isset($this->session->filter_members)) {
1865 $filters = $this->session->filter_members;
1866 } else {
1867 $filters = new MembersList();
1868 }
1869 $members = new Members($filters);
1870
1871 if (!is_array($post['id'])) {
1872 $ids = (array)$post['id'];
1873 } else {
1874 $ids = $post['id'];
1875 }
1876
1877 return $members->removeMembers($ids);
1878 }
1879
1880 // CRUD - Delete
1881
1882 /**
1883 * Set self memebrship flag
1884 *
1885 * @return MembersController
1886 */
1887 private function setSelfMembership(): MembersController
1888 {
1889 $this->is_self_membership = true;
1890 return $this;
1891 }
1892
1893 /**
1894 * Is self membership?
1895 *
1896 * @return boolean
1897 */
1898 private function isSelfMembership(): bool
1899 {
1900 return $this->is_self_membership;
1901 }
1902 }