3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
6 * Members related routes
10 * Copyright © 2014-2018 The Galette Team
12 * This file is part of Galette (http://galette.tuxfamily.org).
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.
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.
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/>.
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2014-2018 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
34 * @link http://galette.tuxfamily.org
35 * @since 0.8.2dev 2014-11-27
39 use Galette\Entity\DynamicFieldsHandle
;
40 use Galette\Core\Password
;
41 use Galette\Core\PasswordImage
;
42 use Galette\Core\Mailing
;
43 use Galette\Core\GaletteMail
;
44 use Galette\Repository\Members
;
45 use Galette\Filters\MembersList
;
46 use Galette\Filters\SavedSearchesList
;
47 use Galette\Filters\AdvancedMembersList
;
48 use Galette\Entity\FieldsConfig
;
49 use Galette\Entity\Contribution
;
50 use Galette\Repository\Groups
;
51 use Galette\Repository\Reminders
;
52 use Galette\Entity\Adherent
;
53 use Galette\IO\PdfMembersCards
;
54 use Galette\IO\PdfMembersLabels
;
56 use Galette\IO\CsvOut
;
57 use Galette\Entity\Status
;
58 use Galette\Repository\Titles
;
59 use Galette\Entity\Texts
;
61 use Galette\Core\MailingHistory
;
62 use Galette\Entity\Group
;
64 use Galette\Core\Authentication
;
65 use Galette\Repository\PaymentTypes
;
66 use Galette\Repository\SavedSearches
;
71 function ($request, $response) {
72 if (!$this->preferences
->pref_bool_selfsubscribe ||
$this->login
->isLogged()) {
75 ->withHeader('Location', $this->router
->pathFor('slash'));
78 if ($this->session
->member
!== null) {
79 $member = $this->session
->member
;
80 $this->session
->member
= null;
85 $member = new Adherent($this->zdb
, null, $deps);
88 //mark as self membership
89 $member->setSelfMembership();
91 // flagging required fields
92 $fc = $this->fields_config
;
93 $form_elements = $fc->getFormElements($this->login
, true, true);
95 //image to defeat mass filling forms
96 $spam = new PasswordImage();
97 $spam_pass = $spam->newImage();
98 $spam_img = $spam->getImage();
103 $required_fields = array(
108 $list_members = $m->getList(false, $required_fields, true);
110 if (count($list_members) > 0) {
111 foreach ($list_members as $lmember) {
113 $sname = mb_strtoupper($lmember->nom_adh
, 'UTF-8') .
114 ' ' . ucwords(mb_strtolower($lmember->prenom_adh
, 'UTF-8')) .
115 ' (' . $lmember->id_adh
. ')';
116 $members[$lmember->$pk] = $sname;
120 $params['members'] = [
121 'filters' => $m->getFilters(),
122 'count' => $m->getCount()
125 //check if current attached member is part of the list
126 if ($member->hasParent()) {
127 if (!isset($members[$member->parent
->id
])) {
129 [$member->parent
->id
=> $member->parent
->getSName()] +
135 if (count($members)) {
136 $params['members']['list'] = $members;
144 'page_title' => _T("Subscription"),
145 'parent_tpl' => 'public_page.tpl',
148 'languages' => $this->i18n
->getList(),
149 'require_calendar' => true,
150 'autocomplete' => true,
153 'titles_list' => Titles
::getList($this->zdb
),
155 'spam_pass' => $spam_pass,
156 'spam_img' => $spam_img,
157 'fieldsets' => $form_elements['fieldsets'],
158 'hidden_elements' => $form_elements['hiddens']
163 )->setName('subscribe');
165 //members list CSV export
167 '/members/export/csv',
168 function ($request, $response) {
171 if (isset($this->session
->filter_members
)) {
172 //CAUTION: this one may be simple or advanced, display must change
173 $filters = $this->session
->filter_members
;
175 $filters = new MembersList();
178 $export_fields = null;
179 if (file_exists(GALETTE_CONFIG_PATH
. 'local_export_fields.inc.php')) {
180 include_once GALETTE_CONFIG_PATH
. 'local_export_fields.inc.php';
181 $export_fields = $fields;
185 $fc = $this->fields_config
;
186 $visibles = $fc->getVisibilities();
187 //hack for id_adh and parent_id
188 $hacks = ['id_adh', 'parent_id'];
189 foreach ($hacks as $hack) {
190 if ($visibles[$hack] == FieldsConfig
::NOBODY
) {
191 $visibles[$hack] = FieldsConfig
::MANAGER
;
194 $access_level = $this->login
->getAccessLevel();
197 foreach ($this->members_fields
as $k => $f) {
198 // skip fields blacklisted for export
199 if ($k === 'mdp_adh' ||
200 ($export_fields !== null &&
201 (is_array($export_fields) && !in_array($k, $export_fields)))
206 // skip fields according to access control
207 if ($visibles[$k] == FieldsConfig
::NOBODY ||
208 ($visibles[$k] == FieldsConfig
::ADMIN
&&
209 $access_level < Authentication
::ACCESS_ADMIN
) ||
210 ($visibles[$k] == FieldsConfig
::STAFF
&&
211 $access_level < Authentication
::ACCESS_STAFF
) ||
212 ($visibles[$k] == FieldsConfig
::MANAGER
&&
213 $access_level < Authentication
::ACCESS_MANAGER
)
219 $labels[] = $f['label'];
222 $members = new Members($filters);
223 $members_list = $members->getArrayList(
232 $s = new Status($this->zdb
);
233 $statuses = $s->getList();
236 $titles = $t->getList($this->zdb
);
238 foreach ($members_list as &$member) {
239 if (isset($member->id_statut
)) {
241 $member->id_statut
= $statuses[$member->id_statut
];
244 if (isset($member->titre_adh
)) {
246 $member->titre_adh
= $titles[$member->titre_adh
]->short
;
250 if (isset($member->date_crea_adh
)) {
251 if ($member->date_crea_adh
!= ''
252 && $member->date_crea_adh
!= '1901-01-01'
254 $dcrea = new DateTime($member->date_crea_adh
);
255 $member->date_crea_adh
= $dcrea->format(__("Y-m-d"));
257 $member->date_crea_adh
= '';
261 if (isset($member->date_modif_adh
)) {
262 if ($member->date_modif_adh
!= ''
263 && $member->date_modif_adh
!= '1901-01-01'
265 $dmodif = new DateTime($member->date_modif_adh
);
266 $member->date_modif_adh
= $dmodif->format(__("Y-m-d"));
268 $member->date_modif_adh
= '';
272 if (isset($member->date_echeance
)) {
273 if ($member->date_echeance
!= ''
274 && $member->date_echeance
!= '1901-01-01'
276 $dech = new DateTime($member->date_echeance
);
277 $member->date_echeance
= $dech->format(__("Y-m-d"));
279 $member->date_echeance
= '';
283 if (isset($member->ddn_adh
)) {
284 if ($member->ddn_adh
!= ''
285 && $member->ddn_adh
!= '1901-01-01'
287 $ddn = new DateTime($member->ddn_adh
);
288 $member->ddn_adh
= $ddn->format(__("Y-m-d"));
290 $member->ddn_adh
= '';
294 if (isset($member->sexe_adh
)) {
296 switch ($member->sexe_adh
) {
298 $member->sexe_adh
= _T("Man");
300 case Adherent
::WOMAN
:
301 $member->sexe_adh
= _T("Woman");
304 $member->sexe_adh
= _T("Unspecified");
310 if (isset($member->activite_adh
)) {
311 $member->activite_adh
312 = ($member->activite_adh
) ?
_T("Yes") : _T("No");
314 if (isset($member->bool_admin_adh
)) {
315 $member->bool_admin_adh
316 = ($member->bool_admin_adh
) ?
_T("Yes") : _T("No");
318 if (isset($member->bool_exempt_adh
)) {
319 $member->bool_exempt_adh
320 = ($member->bool_exempt_adh
) ?
_T("Yes") : _T("No");
322 if (isset($member->bool_display_info
)) {
323 $member->bool_display_info
324 = ($member->bool_display_info
) ?
_T("Yes") : _T("No");
327 $filename = 'filtered_memberslist.csv';
328 $filepath = CsvOut
::DEFAULT_DIRECTORY
. $filename;
329 $fp = fopen($filepath, 'w');
333 Csv
::DEFAULT_SEPARATOR
,
345 $filepath = CsvOut
::DEFAULT_DIRECTORY
. $filename;
346 if (file_exists($filepath)) {
347 $response = $this->response
->withHeader('Content-Description', 'File Transfer')
348 ->withHeader('Content-Type', 'text/csv')
349 ->withHeader('Content-Disposition', 'attachment;filename="' . $filename . '"')
350 ->withHeader('Pragma', 'no-cache')
351 ->withHeader('Content-Transfer-Encoding', 'binary')
352 ->withHeader('Expires', '0')
353 ->withHeader('Cache-Control', 'must-revalidate')
354 ->withHeader('Pragma', 'public')
355 ->withHeader('Content-Length', filesize($filepath));
357 $stream = fopen('php://memory', 'r+');
358 fwrite($stream, file_get_contents($filepath));
361 return $response->withBody(new \Slim\Http\
Stream($stream));
364 'A request has been made to get an exported file named `' .
365 $filename .'` that does not exists.',
368 $notFound = $this->notFoundHandler
;
369 return $notFound($request, $response);
373 )->setName('csv-memberslist')->add($authenticate);
377 '/members[/{option:page|order}/{value:\d+}]',
378 function ($request, $response, $args = []) {
380 if (isset($args['option'])) {
381 $option = $args['option'];
384 if (isset($args['value'])) {
385 $value = $args['value'];
388 if (isset($this->session
->filter_members
)) {
389 $filters = $this->session
->filter_members
;
391 $filters = new MembersList();
394 if ($option !== null) {
397 $filters->current_page
= (int)$value;
400 $filters->orderby
= $value;
405 $members = new Members($filters);
407 $members_list = array();
408 if ($this->login
->isAdmin() ||
$this->login
->isStaff()) {
409 $members_list = $members->getMembersList(true);
411 $members_list = $members->getManagedMembersList(true);
414 $groups = new Groups($this->zdb
, $this->login
);
415 $groups_list = $groups->getList();
417 //assign pagination variables to the template and add pagination links
418 $filters->setSmartyPagination($this->router
, $this->view
->getSmarty(), false);
419 $filters->setViewCommonsFilters($this->preferences
, $this->view
->getSmarty());
421 $this->session
->filter_members
= $filters;
426 'gestion_adherents.tpl',
428 'page_title' => _T("Members management"),
429 'require_dialog' => true,
430 'require_calendar' => true,
431 'require_mass' => true,
432 'members' => $members_list,
433 'filter_groups_options' => $groups_list,
434 'nb_members' => $members->getCount(),
435 'filters' => $filters,
436 'adv_filters' => $filters instanceof AdvancedMembersList
443 )->add($authenticate);
445 //members list filtering
448 function ($request, $response) {
449 $post = $request->getParsedBody();
450 if (isset($this->session
->filter_members
)) {
451 //CAUTION: this one may be simple or advanced, display must change
452 $filters = $this->session
->filter_members
;
454 $filters = new MembersList();
457 //reintialize filters
458 if (isset($post['clear_filter'])) {
459 $filters = new MembersList();
460 } elseif (isset($post['clear_adv_filter'])) {
461 $this->session
->filter_members
= null;
462 unset($this->session
->filter_members
);
466 ->withHeader('Location', $this->router
->pathFor('advanced-search'));
467 } elseif (isset($post['adv_criteria'])) {
470 ->withHeader('Location', $this->router
->pathFor('advanced-search'));
473 if (isset($post['filter_str'])) { //filter search string
474 $filters->filter_str
= stripslashes(
475 htmlspecialchars($post['filter_str'], ENT_QUOTES
)
479 if (isset($post['field_filter'])) {
480 if (is_numeric($post['field_filter'])) {
481 $filters->field_filter
= $post['field_filter'];
484 //membership to filter
485 if (isset($post['membership_filter'])) {
486 if (is_numeric($post['membership_filter'])) {
487 $filters->membership_filter
488 = $post['membership_filter'];
491 //account status to filter
492 if (isset($post['filter_account'])) {
493 if (is_numeric($post['filter_account'])) {
494 $filters->filter_account
= $post['filter_account'];
498 if (isset($post['email_filter'])) {
499 $filters->email_filter
= (int)$post['email_filter'];
502 if (isset($post['group_filter'])
503 && $post['group_filter'] > 0
505 $filters->group_filter
= (int)$post['group_filter'];
507 //number of rows to show
508 if (isset($post['nbshow'])) {
509 $filters->show
= $post['nbshow'];
512 if (isset($post['advanced_filtering'])) {
513 if (!$filters instanceof AdvancedMembersList
) {
514 $filters = new AdvancedMembersList($filters);
518 unset($post['advanced_filtering']);
520 foreach ($post as $k => $v) {
521 if (strpos($k, 'free_', 0) === 0) {
524 foreach ($post['free_field'] as $f) {
526 && trim($post['free_text'][$i]) !== ''
528 $fs_search = $post['free_text'][$i];
530 = (int)$post['free_logical_operator'][$i];
532 = (int)$post['free_query_operator'][$i];
533 $type = (int)$post['free_type'][$i];
538 'search' => $fs_search,
542 $filters->free_search
= $fs;
550 case 'contrib_min_amount':
551 case 'contrib_max_amount':
552 if (trim($v) !== '') {
565 if (isset($post['savesearch'])) {
570 $this->router
->pathFor(
577 $this->session
->filter_members
= $filters;
581 ->withHeader('Location', $this->router
->pathFor('members'));
583 )->setName('filter-memberslist')->add($authenticate);
588 function ($request, $response) {
589 if ($this->login
->isSuperAdmin()) {
592 ->withHeader('Location', $this->router
->pathFor('slash'));
603 $member = new Adherent($this->zdb
, $this->login
->login
, $deps);
606 $fc = $this->fields_config
;
607 $display_elements = $fc->getDisplayElements($this->login
);
614 'page_title' => _T("Member Profile"),
615 'require_dialog' => true,
617 'pref_lang_img' => $this->i18n
->getFlagFromId($member->language
),
618 'pref_lang' => ucfirst($this->i18n
->getNameFromId($member->language
)),
619 'pref_card_self' => $this->preferences
->pref_card_self
,
620 'groups' => Groups
::getSimpleList(),
622 'display_elements' => $display_elements
626 )->setName('me')->add($authenticate);
631 function ($request, $response, $args) {
642 $member = new Adherent($this->zdb
, (int)$id, $deps);
644 if ($this->login
->id
!= $id && !$this->login
->isAdmin() && !$this->login
->isStaff()) {
645 //check if requested member is part of managed groups
646 $groups = $member->groups
;
648 foreach ($groups as $g) {
649 if ($this->login
->isGroupManager($g->getId())) {
654 if ($is_managed !== true) {
655 //requested member is not part of managed groups,
656 //fall back to logged in member
658 'Trying to display member #' . $id . ' without appropriate ACLs',
666 $this->router
->pathFor(
668 ['id' => $this->login
->id
]
674 if ($member->id
== null) {
675 //member does not exists!
676 $this->flash
->addMessage(
678 str_replace('%id', $args['id'], _T("No member #%id."))
685 $this->router
->pathFor('slash')
689 // flagging fields visibility
690 $fc = $this->fields_config
;
691 $display_elements = $fc->getDisplayElements($this->login
);
698 'page_title' => _T("Member Profile"),
699 'require_dialog' => true,
701 'pref_lang_img' => $this->i18n
->getFlagFromId($member->language
),
702 'pref_lang' => ucfirst($this->i18n
->getNameFromId($member->language
)),
703 'pref_card_self' => $this->preferences
->pref_card_self
,
704 'groups' => Groups
::getSimpleList(),
706 'display_elements' => $display_elements
711 )->setName('member')->add($authenticate)->add($navMiddleware);
714 '/member/{action:edit|add}[/{id:\d+}]',
715 function ($request, $response, $args) {
716 $action = $args['action'];
718 if (isset($args['id'])) {
722 if ($action === 'edit' && $id === null) {
723 throw new \
RuntimeException(
724 _T("Member ID cannot ben null calling edit route!")
726 } elseif ($action === 'add' && $id !== null) {
729 ->withHeader('Location', $this->router
->pathFor('editmember', ['action' => 'add']));
741 if ($this->session
->member
!== null) {
742 $member = $this->session
->member
;
743 $this->session
->member
= null;
745 $member = new Adherent($this->zdb
, null, $deps);
748 if ($this->login
->isAdmin() ||
$this->login
->isStaff() ||
$this->login
->isGroupManager()) {
750 if ($member->id
!= $id) {
753 if (!$this->login
->isAdmin() && !$this->login
->isStaff() && $this->login
->isGroupManager()) {
754 //check if current logged in user can manage loaded member
755 $groups = $member->groups
;
757 foreach ($groups as $group) {
758 if ($this->login
->isGroupManager($group->getId())) {
763 if ($can_manage !== true) {
765 'Logged in member ' . $this->login
->login
.
766 ' has tried to load member #' . $member->id
.
767 ' but do not manage any groups he belongs to.',
770 $member->load($this->login
->id
);
775 if ($member->id
!= $id) {
776 $member->load($this->login
->id
);
780 // flagging required fields
781 $fc = $this->fields_config
;
783 // password required if we create a new member
784 if ($member->id
!= '') {
785 $fc->setNotRequired('mdp_adh');
788 //handle requirements for parent fields
789 $parent_fields = $member->getParentFields();
790 foreach ($parent_fields as $key => $field) {
791 if ($fc->isRequired($field) && $member->hasParent()) {
792 $fc->setNotRequired($field);
793 } elseif (!$fc->isRequired($field)) {
794 unset($parent_fields[$key]);
797 $route_params['parent_fields'] = $parent_fields;
799 // flagging required fields invisible to members
800 if ($this->login
->isAdmin() ||
$this->login
->isStaff()) {
801 $fc->setNotRequired('activite_adh');
802 $fc->setNotRequired('id_statut');
805 // template variable declaration
806 $title = _T("Member Profile");
807 if ($member->id
!= '') {
808 $title .= ' (' . _T("modification") . ')';
810 $title .= ' (' . _T("creation") . ')';
814 $statuts = new Status($this->zdb
);
817 $groups = new Groups($this->zdb
, $this->login
);
818 $groups_list = $groups->getSimpleList(true);
820 $form_elements = $fc->getFormElements(
828 $required_fields = array(
833 $list_members = $m->getList(false, $required_fields, true);
835 if (count($list_members) > 0) {
836 foreach ($list_members as $lmember) {
838 $sname = mb_strtoupper($lmember->nom_adh
, 'UTF-8') .
839 ' ' . ucwords(mb_strtolower($lmember->prenom_adh
, 'UTF-8')) .
840 ' (' . $lmember->id_adh
. ')';
841 $members[$lmember->$pk] = $sname;
845 $route_params['members'] = [
846 'filters' => $m->getFilters(),
847 'count' => $m->getCount()
850 //check if current attached member is part of the list
851 if ($member->hasParent()) {
852 if (!isset($members[$member->parent
->id
])) {
854 [$member->parent
->id
=> $member->parent
->getSName()] +
860 if (count($members)) {
861 $route_params['members']['list'] = $members;
871 'parent_tpl' => 'page.tpl',
872 'require_dialog' => true,
873 'autocomplete' => true,
874 'page_title' => $title,
877 'languages' => $this->i18n
->getList(),
878 'require_calendar' => true,
881 'titles_list' => Titles
::getList($this->zdb
),
882 'statuts' => $statuts->getList(),
883 'groups' => $groups_list,
884 'fieldsets' => $form_elements['fieldsets'],
885 'hidden_elements' => $form_elements['hiddens']
893 )->add($authenticate)->add($navMiddleware);
896 '/member/store[/{self:subscribe}]',
897 function ($request, $response, $args) {
898 if (!$this->preferences
->pref_bool_selfsubscribe
&& !$this->login
->isLogged()) {
901 ->withHeader('Location', $this->router
->pathFor('slash'));
904 $post = $request->getParsedBody();
913 $member = new Adherent($this->zdb
, null, $deps);
914 $member->setDependencies(
916 $this->members_fields
,
919 if (isset($args['self'])) {
920 //mark as self membership
921 $member->setSelfMembership();
924 $success_detected = [];
925 $warning_detected = [];
926 $error_detected = [];
929 $adherent['id_adh'] = get_numeric_form_value('id_adh', '');
931 if ($this->login
->isAdmin() ||
$this->login
->isStaff() ||
$this->login
->isGroupManager()) {
932 if ($adherent['id_adh']) {
933 $member->load($adherent['id_adh']);
934 if (!$this->login
->isAdmin() && !$this->login
->isStaff() && $this->login
->isGroupManager()) {
935 //check if current logged in user can manage loaded member
936 $groups = $member->groups
;
938 foreach ($groups as $group) {
939 if ($this->login
->isGroupManager($group->getId())) {
944 if ($can_manage !== true) {
946 'Logged in member ' . $this->login
->login
.
947 ' has tried to load member #' . $member->id
.
948 ' but do not manage any groups he belongs to.',
951 $member->load($this->login
->id
);
956 $member->load($this->login
->id
);
957 $adherent['id_adh'] = $this->login
->id
;
960 // flagging required fields
961 $fc = $this->fields_config
;
963 // password required if we create a new member
964 if ($member->id
!= '') {
965 $fc->setNotRequired('mdp_adh');
968 if ($member->hasParent() && !isset($post['detach_parent'])
969 ||
isset($post['parent_id']) && !empty($post['parent_id'])
971 $parent_fields = $member->getParentFields();
972 foreach ($parent_fields as $field) {
973 if ($fc->isRequired($field)) {
974 $fc->setNotRequired($field);
979 // flagging required fields invisible to members
980 if ($this->login
->isAdmin() ||
$this->login
->isStaff()) {
981 $fc->setNotRequired('activite_adh');
982 $fc->setNotRequired('id_statut');
985 $form_elements = $fc->getFormElements(
990 $fieldsets = $form_elements['fieldsets'];
994 foreach ($fieldsets as $category) {
995 foreach ($category->elements
as $field) {
996 if ($field->required
== true) {
997 $required[$field->field_id
] = true;
999 if ($field->disabled
== true) {
1000 $disabled[$field->field_id
] = true;
1001 } elseif (!isset($post[$field->field_id
])) {
1002 switch ($field->field_id
) {
1003 //unchecked booleans are not sent from form
1004 case 'bool_admin_adh':
1005 case 'bool_exempt_adh':
1006 case 'bool_display_info':
1007 $post[$field->field_id
] = 0;
1014 $real_requireds = array_diff(array_keys($required), array_keys($disabled));
1017 if (isset($post[array_shift($real_requireds)])) {
1019 $valid = $member->check($post, $required, $disabled);
1020 if ($valid !== true) {
1021 $error_detected = array_merge($error_detected, $valid);
1024 if (count($error_detected) == 0) {
1025 //all goes well, we can proceed
1028 if ($member->id
== '') {
1031 $store = $member->store();
1032 if ($store === true) {
1033 //member has been stored :)
1035 if (isset($args['self'])) {
1036 $success_detected[] = _T("Your account has been created!");
1037 if ($this->preferences
->pref_mail_method
> GaletteMail
::METHOD_DISABLED
1038 && $member->getEmail() != ''
1040 $success_detected[] = _T("An email has been sent to you, check your inbox.");
1043 $success_detected[] = _T("New member has been successfully added.");
1045 //Send email to admin if preference checked
1046 if ($this->preferences
->pref_mail_method
> GaletteMail
::METHOD_DISABLED
1047 && $this->preferences
->pref_bool_mailadh
1050 $this->texts_fields
,
1054 'name_adh' => custom_html_entity_decode(
1057 'firstname_adh' => custom_html_entity_decode(
1060 'lastname_adh' => custom_html_entity_decode(
1063 'mail_adh' => custom_html_entity_decode(
1066 'login_adh' => custom_html_entity_decode(
1071 $mtxt = $texts->getTexts(
1072 (isset($args['self']) ?
'newselfadh' : 'newadh'),
1073 $this->preferences
->pref_lang
1076 $mail = new GaletteMail($this->preferences
);
1077 $mail->setSubject($texts->getSubject());
1079 foreach ($this->preferences
->vpref_email
as $pref_email) {
1080 $recipients[$pref_email] = $this->preferences
->pref_email_nom
;
1082 $mail->setRecipients($recipients);
1083 $mail->setMessage($texts->getBody());
1084 $sent = $mail->send();
1086 if ($sent == GaletteMail
::MAIL_SENT
) {
1087 $this->history
->add(
1090 $member->sname
. ' (' . $member->email
. ')',
1091 _T("New account mail sent to admin for '%s'.")
1097 $member->sname
. ' (' . $member->email
. ')',
1098 _T("A problem happened while sending email to admin for account '%s'.")
1100 $this->history
->add($str);
1101 $warning_detected[] = $str;
1106 $success_detected[] = _T("Member account has been modified.");
1109 // send mail to member
1110 if (isset($args['self']) ||
isset($post['mail_confirm']) && $post['mail_confirm'] == '1') {
1111 if ($this->preferences
->pref_mail_method
> GaletteMail
::METHOD_DISABLED
) {
1112 if ($member->getEmail() == '' && !isset($args['self'])) {
1113 $error_detected[] = _T("- You can't send a confirmation by email if the member hasn't got an address!");
1116 'name_adh' => custom_html_entity_decode(
1119 'firstname_adh' => custom_html_entity_decode(
1122 'lastname_adh' => custom_html_entity_decode(
1125 'mail_adh' => custom_html_entity_decode(
1128 'login_adh' => custom_html_entity_decode(
1133 $password = new Password($this->zdb
);
1134 $res = $password->generateNewPassword($member->id
);
1136 $link_validity = new DateTime();
1137 $link_validity->add(new DateInterval('PT24H'));
1138 $mreplaces['change_pass_uri'] = $this->preferences
->getURL() .
1139 $this->router
->pathFor(
1140 'password-recovery',
1141 ['hash' => base64_encode($password->getHash())]
1143 $mreplaces['link_validity'] = $link_validity->format(_T("Y-m-d H:i:s"));
1148 _T("An error occurred storing temporary password for %s. Please inform an admin.")
1150 $this->history
->add($str);
1151 $this->flash
->addMessage(
1158 //send mail to member
1159 // Get email text in database
1161 $this->texts_fields
,
1166 $mlang = $this->preferences
->pref_lang
;
1167 if (isset($post['pref_lang'])) {
1168 $mlang = $post['pref_lang'];
1170 $mtxt = $texts->getTexts(
1171 (($new) ?
'sub' : 'accountedited'),
1175 $mail = new GaletteMail($this->preferences
);
1176 $mail->setSubject($texts->getSubject());
1177 $mail->setRecipients(
1179 $member->getEmail() => $member->sname
1182 $mail->setMessage($texts->getBody());
1183 $sent = $mail->send();
1185 if ($sent == GaletteMail
::MAIL_SENT
) {
1188 $member->sname
. ' (' . $member->getEmail() . ')',
1190 _T("New account mail sent to '%s'.") :
1191 _T("Account modification mail sent to '%s'.")
1193 $this->history
->add($msg);
1194 $success_detected[] = $msg;
1198 $member->sname
. ' (' . $member->getEmail() . ')',
1199 _T("A problem happened while sending account mail to '%s'")
1201 $this->history
->add($str);
1202 $error_detected[] = $str;
1205 } elseif ($this->preferences
->pref_mail_method
== GaletteMail
::METHOD_DISABLED
) {
1206 //if mail has been disabled in the preferences, we should not be here ;
1207 //we do not throw an error, just a simple warning that will be show later
1208 $msg = _T("You asked Galette to send a confirmation mail to the member, but mail has been disabled in the preferences.");
1209 $warning_detected[] = $msg;
1213 // send mail to admin
1214 if ($this->preferences
->pref_mail_method
> GaletteMail
::METHOD_DISABLED
1215 && $this->preferences
->pref_bool_mailadh
1217 && $member->id
== $this->login
->id
1220 'name_adh' => custom_html_entity_decode(
1223 'firstname_adh' => custom_html_entity_decode(
1226 'lastname_adh' => custom_html_entity_decode(
1229 'mail_adh' => custom_html_entity_decode(
1232 'login_adh' => custom_html_entity_decode(
1237 //send mail to member
1238 // Get email text in database
1240 $this->texts_fields
,
1245 $mlang = $this->preferences
->pref_lang
;
1247 $mtxt = $texts->getTexts(
1252 $mail = new GaletteMail($this->preferences
);
1253 $mail->setSubject($texts->getSubject());
1255 foreach ($this->preferences
->vpref_email_newadh
as $pref_email) {
1256 $recipients[$pref_email] = $this->preferences
->pref_email_nom
;
1258 $mail->setRecipients($recipients);
1260 $mail->setMessage($texts->getBody());
1261 $sent = $mail->send();
1263 if ($sent == GaletteMail
::MAIL_SENT
) {
1264 $msg = _T("Account modification mail sent to admin.");
1265 $this->history
->add($msg);
1266 $success_detected[] = $msg;
1268 $str = _T("A problem happened while sending account mail to admin");
1269 $this->history
->add($str);
1270 $error_detected[] = $str;
1274 //store requested groups
1277 $managed_groups_adh = null;
1279 //add/remove user from groups
1280 if (isset($post['groups_adh'])) {
1281 $groups_adh = $post['groups_adh'];
1283 $add_groups = Groups
::addMemberToGroups(
1288 if ($add_groups === false) {
1289 $error_detected[] = _T("An error occurred adding member to its groups.");
1292 //add/remove manager from groups
1293 if (isset($post['groups_managed_adh'])) {
1294 $managed_groups_adh = $post['groups_managed_adh'];
1296 $add_groups = Groups
::addMemberToGroups(
1298 $managed_groups_adh,
1301 $member->loadGroups();
1303 if ($add_groups === false) {
1304 $error_detected[] = _T("An error occurred adding member to its groups as manager.");
1307 //something went wrong :'(
1308 $error_detected[] = _T("An error occurred while storing the member.");
1312 if (count($error_detected) == 0) {
1313 $files_res = $member->handleFiles($_FILES);
1314 if (is_array($files_res)) {
1315 $error_detected = array_merge($error_detected, $files_res);
1318 if (isset($post['del_photo'])) {
1319 if (!$member->picture
->delete($member->id
)) {
1320 $error_detected[] = _T("Delete failed");
1321 $str_adh = $member->id
. ' (' . $member->sname
. ' ' . ')';
1323 'Unable to delete picture for member ' . $str_adh,
1330 if (count($error_detected) > 0) {
1331 foreach ($error_detected as $error) {
1332 if (strpos($error, '%member_url_') !== false) {
1333 preg_match('/%member_url_(\d+)/', $error, $matches);
1334 $url = $this->router
->pathFor('member', ['id' => $matches[1]]);
1335 $error = str_replace(
1336 '%member_url_' . $matches[1],
1341 $this->flash
->addMessage(
1348 if (count($warning_detected) > 0) {
1349 foreach ($warning_detected as $warning) {
1350 $this->flash
->addMessage(
1356 if (count($success_detected) > 0) {
1357 foreach ($success_detected as $success) {
1358 $this->flash
->addMessage(
1365 if (count($error_detected) == 0) {
1366 $redirect_url = null;
1367 if (isset($args['self'])) {
1368 $redirect_url = $this->router
->pathFor('login');
1369 } elseif (isset($post['redirect_on_create'])
1370 && $post['redirect_on_create'] > Adherent
::AFTER_ADD_DEFAULT
1372 switch ($post['redirect_on_create']) {
1373 case Adherent
::AFTER_ADD_TRANS
:
1374 $redirect_url = $this->router
->pathFor('transaction', ['action' => 'add']);
1376 case Adherent
::AFTER_ADD_NEW
:
1377 $redirect_url = $this->router
->pathFor('editmember', ['action' => 'add']);
1379 case Adherent
::AFTER_ADD_SHOW
:
1380 $redirect_url = $this->router
->pathFor('member', ['id' => $member->id
]);
1382 case Adherent
::AFTER_ADD_LIST
:
1383 $redirect_url = $this->router
->pathFor('members');
1385 case Adherent
::AFTER_ADD_HOME
:
1386 $redirect_url = $this->router
->pathFor('slash');
1389 } elseif (!isset($post['id_adh']) && !$member->isDueFree()) {
1390 $redirect_url = $this->router
->pathFor(
1396 ) . '?id_adh=' . $member->id
;
1398 $redirect_url = $this->router
->pathFor('member', ['id' => $member->id
]);
1403 ->withHeader('Location', $redirect_url);
1405 //store entity in session
1406 $this->session
->member
= $member;
1408 if (isset($args['self'])) {
1409 $redirect_url = $this->router
->pathFor('subscribe');
1413 'id' => $member->id
,
1417 $rparams = ['action' => 'add'];
1419 $redirect_url = $this->router
->pathFor(
1427 ->withHeader('Location', $redirect_url);
1431 )->setName('storemembers');
1434 '/member/remove/{id:\d+}',
1435 function ($request, $response, $args) {
1436 $adh = new Adherent($this->zdb
, (int)$args['id']);
1439 'id' => $args['id'],
1440 'redirect_uri' => $this->router
->pathFor('members')
1444 $this->view
->render(
1446 'confirm_removal.tpl',
1448 'type' => _T("Member"),
1449 'mode' => $request->isXhr() ?
'ajax' : '',
1450 'page_title' => sprintf(
1451 _T('Remove member %1$s'),
1454 'form_url' => $this->router
->pathFor('doRemoveMember', ['id' => $adh->id
]),
1455 'cancel_uri' => $this->router
->pathFor('members'),
1461 )->setName('removeMember')->add($authenticate);
1465 function ($request, $response) {
1466 $filters = $this->session
->filter_members
;
1469 'id' => $filters->selected
,
1470 'redirect_uri' => $this->router
->pathFor('members')
1474 $this->view
->render(
1476 'confirm_removal.tpl',
1478 'type' => _T("Member"),
1479 'mode' => $request->isXhr() ?
'ajax' : '',
1480 'page_title' => _T('Remove members'),
1481 'message' => str_replace(
1484 _T('You are about to remove %count members.')
1486 'form_url' => $this->router
->pathFor('doRemoveMember'),
1487 'cancel_uri' => $this->router
->pathFor('members'),
1493 )->setName('removeMembers')->add($authenticate);
1496 '/member/remove' . '[/{id:\d+}]',
1497 function ($request, $response) {
1498 $post = $request->getParsedBody();
1499 $ajax = isset($post['ajax']) && $post['ajax'] === 'true';
1502 $uri = isset($post['redirect_uri']) ?
1503 $post['redirect_uri'] :
1504 $this->router
->pathFor('slash');
1506 if (!isset($post['confirm'])) {
1507 $this->flash
->addMessage(
1509 _T("Removal has not been confirmed!")
1512 if (isset($this->session
->filter_members
)) {
1513 $filters = $this->session
->filter_members
;
1515 $filters = new MembersList();
1517 $members = new Members($filters);
1519 if (!is_array($post['id'])) {
1521 $adh = new Adherent($this->zdb
, (int)$post['id']);
1522 $ids = (array)$post['id'];
1527 $del = $members->removeMembers($ids);
1529 if ($del !== true) {
1530 if (count($ids) === 1) {
1531 $error_detected = str_replace(
1534 _T("An error occurred trying to remove member %name :/")
1537 $error_detected = _T("An error occurred trying to remove members :/");
1540 $this->flash
->addMessage(
1545 if (!is_array($post['id'])) {
1546 $success_detected = str_replace(
1549 _T("Member %name has been successfully deleted.")
1552 $success_detected = str_replace(
1555 _T("%count members have been successfully deleted.")
1559 $this->flash
->addMessage(
1571 ->withHeader('Location', $uri);
1573 return $response->withJson(
1575 'success' => $success
1580 )->setName('doRemoveMember')->add($authenticate);
1582 //advanced search page
1585 function ($request, $response) {
1586 if (isset($this->session
->filter_members
)) {
1587 $filters = $this->session
->filter_members
;
1588 if (!$filters instanceof AdvancedMembersList
) {
1589 $filters = new AdvancedMembersList($filters);
1592 $filters = new AdvancedMembersList();
1595 $groups = new Groups($this->zdb
, $this->login
);
1596 $groups_list = $groups->getList();
1598 //we want only visibles fields
1599 $fields = $this->members_fields
;
1600 $fc = $this->fields_config
;
1601 $visibles = $fc->getVisibilities();
1602 $access_level = $this->login
->getAccessLevel();
1604 //remove not searchable fields
1605 unset($fields['mdp_adh']);
1607 foreach ($fields as $k => $f) {
1608 if ($visibles[$k] == FieldsConfig
::NOBODY ||
1609 ($visibles[$k] == FieldsConfig
::ADMIN
&&
1610 $access_level < Authentication
::ACCESS_ADMIN
) ||
1611 ($visibles[$k] == FieldsConfig
::STAFF
&&
1612 $access_level < Authentication
::ACCESS_STAFF
) ||
1613 ($visibles[$k] == FieldsConfig
::MANAGER
&&
1614 $access_level < Authentication
::ACCESS_MANAGER
)
1620 //add status label search
1621 if ($pos = array_search(Status
::PK
, array_keys($fields))) {
1622 $fields = array_slice($fields, 0, $pos, true) +
1623 ['status_label' => ['label' => _T('Status label')]] +
1624 array_slice($fields, $pos, count($fields) -1, true);
1633 'children' => false,
1636 $member = new Adherent($this->zdb
, $this->login
->login
, $deps);
1637 $adh_dynamics = new DynamicFieldsHandle($this->zdb
, $this->login
, $member);
1639 $contrib = new Contribution($this->zdb
, $this->login
);
1640 $contrib_dynamics = new DynamicFieldsHandle($this->zdb
, $this->login
, $contrib);
1643 $statuts = new Status($this->zdb
);
1645 //Contributions types
1646 $ct = new Galette\Entity\
ContributionsTypes($this->zdb
);
1649 $ptypes = new PaymentTypes(
1654 $ptlist = $ptypes->getList();
1656 $filters->setViewCommonsFilters($this->preferences
, $this->view
->getSmarty());
1659 $this->view
->render(
1661 'advanced_search.tpl',
1663 'page_title' => _T("Advanced search"),
1664 'require_dialog' => true,
1665 'require_calendar' => true,
1666 'require_sorter' => true,
1667 'filter_groups_options' => $groups_list,
1668 'search_fields' => $fields,
1669 'adh_dynamics' => $adh_dynamics->getFields(),
1670 'contrib_dynamics' => $contrib_dynamics->getFields(),
1671 'statuts' => $statuts->getList(),
1672 'contributions_types' => $ct->getList(),
1673 'filters' => $filters,
1674 'payments_types' => $ptlist
1679 )->setName('advanced-search')->add($authenticate);
1681 //Batch actions on members list
1684 function ($request, $response) {
1685 $post = $request->getParsedBody();
1687 if (isset($post['member_sel'])) {
1688 if (isset($this->session
->filter_members
)) {
1689 $filters = $this->session
->filter_members
;
1691 $filters = new MembersList();
1694 $filters->selected
= $post['member_sel'];
1695 $this->session
->filter_members
= $filters;
1697 if (isset($post['cards'])) {
1700 ->withHeader('Location', $this->router
->pathFor('pdf-members-cards'));
1703 if (isset($post['labels'])) {
1706 ->withHeader('Location', $this->router
->pathFor('pdf-members-labels'));
1709 if (isset($post['mailing'])) {
1712 ->withHeader('Location', $this->router
->pathFor('mailing') . '?new=new');
1715 if (isset($post['attendance_sheet'])) {
1718 ->withHeader('Location', $this->router
->pathFor('attendance_sheet_details'));
1721 if (isset($post['csv'])) {
1724 ->withHeader('Location', $this->router
->pathFor('csv-memberslist'));
1727 if (isset($post['delete'])) {
1730 ->withHeader('Location', $this->router
->pathFor('removeMembers'));
1733 if (isset($post['masschange'])) {
1736 ->withHeader('Location', $this->router
->pathFor('masschangeMembers'));
1739 throw new \
RuntimeException('Does not know what to batch :(');
1741 $this->flash
->addMessage(
1743 _T("No member was selected, please check at least one name.")
1748 ->withHeader('Location', $this->router
->pathFor('members'));
1751 )->setName('batch-memberslist')->add($authenticate);
1755 '/members/cards[/{' . Adherent
::PK
. ':\d+}]',
1756 function ($request, $response, $args) {
1757 if ($this->session
->filter_members
) {
1758 $filters = $this->session
->filter_members
;
1760 $filters = new MembersList();
1763 if (isset($args[Adherent
::PK
])
1764 && $args[Adherent
::PK
] > 0
1766 $id_adh = $args[Adherent
::PK
];
1768 if ($this->login
->id
!= $id_adh
1769 && !$this->login
->isAdmin()
1770 && !$this->login
->isStaff()
1771 && !$this->login
->isGroupManager()
1776 if (!$this->login
->isAdmin() && !$this->login
->isStaff() && $this->login
->id
!= $id_adh) {
1777 if ($this->login
->isGroupManager()) {
1778 $adh = new Adherent($this->zdb
, $id_adh, ['dynamics' => true]);
1779 //check if current logged in user can manage loaded member
1780 $groups = $adh->groups
;
1781 $can_manage = false;
1782 foreach ($groups as $group) {
1783 if ($this->login
->isGroupManager($group->getId())) {
1788 if ($can_manage !== true) {
1790 'Logged in member ' . $this->login
->login
.
1791 ' has tried to load member #' . $adh->id
.
1792 ' but do not manage any groups he belongs to.',
1803 //requested member cannot be managed. Load logged in user
1804 $id_adh = (int)$this->login
->id
;
1807 //check if member is up to date
1808 if ($this->login
->id
== $id_adh) {
1809 $adh = new Adherent($this->zdb
, (int)$id_adh, ['dues' => true]);
1810 if (!$adh->isUp2Date()) {
1812 'Member ' . $id_adh . ' is not up to date; cannot get his PDF member card',
1817 ->withHeader('Location', $this->router
->pathFor('slash'));
1821 // If we are called from a member's card, get unique id value
1824 if (count($filters->selected
) == 0) {
1826 'No member selected to generate members cards',
1829 $this->flash
->addMessage(
1831 _T("No member was selected, please check at least one name.")
1836 ->withHeader('Location', $this->router
->pathFor('members'));
1840 // Fill array $selected with selected ids
1841 $selected = array();
1842 if (isset($unique) && $unique) {
1843 $selected[] = $unique;
1845 $selected = $filters->selected
;
1849 $members = $m->getArrayList(
1851 array('nom_adh', 'prenom_adh'),
1855 if (!is_array($members) ||
count($members) < 1) {
1857 'An error has occurred, unable to get members list.',
1861 $this->flash
->addMessage(
1863 _T("Unable to get members list.")
1868 ->withHeader('Location', $this->router
->pathFor('members'));
1871 $pdf = new PdfMembersCards($this->preferences
);
1872 $pdf->drawCards($members);
1874 $response = $this->response
->withHeader('Content-type', 'application/pdf')
1875 ->withHeader('Content-Disposition', 'attachment;filename="' . $pdf->getFileName() . '"');
1876 $response->write($pdf->download());
1879 )->setName('pdf-members-cards')->add($authenticate);
1881 //PDF members labels
1884 function ($request, $response) {
1885 $get = $request->getQueryParams();
1887 if ($this->session
->filter_reminders_labels
) {
1888 $filters = $this->session
->filter_reminders_labels
;
1889 unset($this->session
->filter_reminders_labels
);
1890 } elseif ($this->session
->filter_members
) {
1891 $filters = $this->session
->filter_members
;
1893 $filters = new MembersList();
1897 if (isset($get['from'])
1898 && $get['from'] === 'mailing'
1900 //if we're from mailing, we have to retrieve
1901 //its unreachables members for labels
1902 $mailing = $this->session
->mailing
;
1903 $members = $mailing->unreachables
;
1905 if (count($filters->selected
) == 0) {
1906 Analog
::log('No member selected to generate labels', Analog
::INFO
);
1907 $this->flash
->addMessage(
1909 _T("No member was selected, please check at least one name.")
1914 ->withHeader('Location', $this->router
->pathFor('members'));
1918 $members = $m->getArrayList(
1920 array('nom_adh', 'prenom_adh')
1924 if (!is_array($members) ||
count($members) < 1) {
1926 'An error has occurred, unable to get members list.',
1930 $this->flash
->addMessage(
1932 _T("Unable to get members list.")
1937 ->withHeader('Location', $this->router
->pathFor('members'));
1940 $pdf = new PdfMembersLabels($this->preferences
);
1941 $pdf->drawLabels($members);
1942 $response = $this->response
->withHeader('Content-type', 'application/pdf')
1943 ->withHeader('Content-Disposition', 'attachment;filename="' . $pdf->getFileName() . '"');
1944 $response->write($pdf->download());
1947 )->setName('pdf-members-labels')->add($authenticate);
1951 '/members/adhesion-form/{' . Adherent
::PK
. ':\d+}',
1952 function ($request, $response, $args) {
1953 $id_adh = (int)$args[Adherent
::PK
];
1956 if ($this->login
->id
!= $args['id']
1957 && !$this->login
->isAdmin()
1958 && !$this->login
->isStaff()
1959 && !$this->login
->isGroupManager()
1964 if (!$this->login
->isAdmin() && !$this->login
->isStaff() && $this->login
->id
!= $args['id']) {
1965 if ($this->login
->isGroupManager()) {
1966 $adh = new Adherent($this->zdb
, $id_adh, ['dynamics' => true]);
1967 //check if current logged in user can manage loaded member
1968 $groups = $adh->groups
;
1969 $can_manage = false;
1970 foreach ($groups as $group) {
1971 if ($this->login
->isGroupManager($group->getId())) {
1976 if ($can_manage !== true) {
1978 'Logged in member ' . $this->login
->login
.
1979 ' has tried to load member #' . $adh->id
.
1980 ' but do not manage any groups he belongs to.',
1991 //requested member cannot be managed. Load logged in user
1992 $id_adh = (int)$this->login
->id
;
1994 $adh = new Adherent($this->zdb
, $id_adh, ['dynamics' => true]);
1996 $form = $this->preferences
->pref_adhesion_form
;
1997 $pdf = new $form($adh, $this->zdb
, $this->preferences
);
1998 $response = $this->response
->withHeader('Content-type', 'application/pdf')
1999 ->withHeader('Content-Disposition', 'attachment; filename="' . $pdf->getFileName() . '"');
2000 $response->write($pdf->download());
2003 )->setName('adhesionForm')->add($authenticate);
2005 //Empty PDF adhesion form
2007 '/members/empty-adhesion-form',
2008 function ($request, $response) {
2009 $form = $this->preferences
->pref_adhesion_form
;
2010 $pdf = new $form(null, $this->zdb
, $this->preferences
);
2011 $response = $this->response
->withHeader('Content-type', 'application/pdf')
2012 ->withHeader('Content-Disposition', 'attachment; filename="' . $pdf->getFileName() . '"');
2013 $response->write($pdf->download());
2016 )->setName('emptyAdhesionForm');
2021 function ($request, $response) {
2022 $get = $request->getQueryParams();
2025 if (isset($get['mailing_new'])
2026 ||
isset($get['reminder'])
2028 if ($this->session
->mailing
!== null) {
2029 // check for temporary attachments to remove
2030 $m = $this->session
->mailing
;
2031 $m->removeAttachments(true);
2033 $this->session
->mailing
= null;
2038 if ($this->preferences
->pref_mail_method
== Mailing
::METHOD_DISABLED
2039 && !GALETTE_MODE
=== 'DEMO'
2041 $this->history
->add(
2042 _T("Trying to load mailing while mail is disabled in preferences.")
2044 $this->flash
->addMessage(
2046 _T("Trying to load mailing while mail is disabled in preferences.")
2050 ->withHeader('Location', $this->router
->pathFor('slash'));
2052 if (isset($this->session
->filter_mailing
)) {
2053 $filters = $this->session
->filter_mailing
;
2054 } elseif (isset($this->session
->filter_members
)) {
2055 $filters = $this->session
->filter_members
;
2057 $filters = new MembersList();
2060 if ($this->session
->mailing
!== null
2061 && !isset($get['from'])
2062 && !isset($get['reset'])
2064 $mailing = $this->session
->mailing
;
2065 } elseif (isset($get['from']) && is_numeric($get['from'])) {
2066 $mailing = new Mailing($this->preferences
, null, $get['from']);
2067 MailingHistory
::loadFrom($this->zdb
, (int)$get['from'], $mailing);
2068 } elseif (isset($get['reminder'])) {
2069 //FIXME: use a constant!
2071 $filters->membership_filter
= Members
::MEMBERSHIP_LATE
;
2072 $filters->filter_account
= Members
::ACTIVE_ACCOUNT
;
2073 $m = new Members($filters);
2074 $members = $m->getList(true);
2075 $mailing = new Mailing($this->preferences
, ($members !== false) ?
$members : null);
2077 if (count($filters->selected
) == 0
2078 && !isset($get['mailing_new'])
2079 && !isset($get['reminder'])
2082 '[Mailings] No member selected for mailing',
2086 $this->flash
->addMessage(
2088 _T('No member selected for mailing!')
2091 if (isset($profiler)) {
2095 $redirect_url = ($this->session
->redirect_mailing
!== null) ?
2096 $this->session
->redirect_mailing
:
2097 $this->router
->pathFor('members');
2101 ->withHeader('Location', $redirect_url);
2104 $members = $m->getArrayList($filters->selected
);
2105 $mailing = new Mailing($this->preferences
, ($members !== false) ?
$members : null);
2108 if (isset($get['remove_attachment'])) {
2109 $mailing->removeAttachment($get['remove_attachment']);
2112 if ($mailing->current_step
!== Mailing
::STEP_SENT
) {
2113 $this->session
->mailing
= $mailing;
2116 /** TODO: replace that... */
2117 $this->session
->labels
= $mailing->unreachables
;
2119 if (!$this->login
->isSuperAdmin()) {
2120 $member = new Adherent($this->zdb
, (int)$this->login
->id
, false);
2121 $params['sender_current'] = [
2122 'name' => $member->sname
,
2123 'email' => $member->getEmail()
2127 $params = array_merge(
2130 'mailing' => $mailing,
2131 'attachments' => $mailing->attachments
,
2132 'html_editor' => true,
2133 'html_editor_active'=> $this->preferences
->pref_editor_enabled
2139 $this->view
->render(
2141 'mailing_adherents.tpl',
2144 'page_title' => _T("Mailing"),
2145 'require_dialog' => true
2152 )->setName('mailing')->add($authenticate);
2156 function ($request, $response) {
2157 $post = $request->getParsedBody();
2158 $error_detected = [];
2159 $success_detected = [];
2161 $goto = $this->router
->pathFor('mailings');
2162 $redirect_url = ($this->session
->redirect_mailing
!== null) ?
2163 $this->session
->redirect_mailing
:
2164 $this->router
->pathFor('members');
2167 if (isset($post['mailing_done'])
2168 ||
isset($post['mailing_cancel'])
2170 if ($this->session
->mailing
!== null) {
2171 // check for temporary attachments to remove
2172 $m = $this->session
->mailing
;
2173 $m->removeAttachments(true);
2175 $this->session
->mailing
= null;
2176 if (isset($this->session
->filter_mailing
)) {
2177 $filters = $this->session
->filter_mailing
;
2178 $filters->selected
= [];
2179 $this->session
->filter_mailing
= $filters;
2184 ->withHeader('Location', $redirect_url);
2189 if ($this->preferences
->pref_mail_method
== Mailing
::METHOD_DISABLED
2190 && !GALETTE_MODE
=== 'DEMO'
2192 $this->history
->add(
2193 _T("Trying to load mailing while mail is disabled in preferences.")
2195 $error_detected[] = _T("Trying to load mailing while mail is disabled in preferences.");
2196 $goto = $this->router
->pathFor('slash');
2198 if (isset($this->session
->filter_members
)) {
2199 $filters = $this->session
->filter_members
;
2201 $filters = new MembersList();
2204 if ($this->session
->mailing
!== null
2205 && !isset($post['mailing_cancel'])
2207 $mailing = $this->session
->mailing
;
2209 if (count($filters->selected
) == 0) {
2211 '[Mailings] No member selected for mailing',
2215 $this->flash
->addMessage(
2217 _T('No member selected for mailing!')
2222 ->withHeader('Location', $redirect_url);
2225 $members = $m->getArrayList($filters->selected
);
2226 $mailing = new Mailing($this->preferences
, ($members !== false) ?
$members : null);
2229 if (isset($post['mailing_go'])
2230 ||
isset($post['mailing_reset'])
2231 ||
isset($post['mailing_confirm'])
2232 ||
isset($post['mailing_save'])
2234 if (trim($post['mailing_objet']) == '') {
2235 $error_detected[] = _T("Please type an object for the message.");
2237 $mailing->subject
= $post['mailing_objet'];
2240 if (trim($post['mailing_corps']) == '') {
2241 $error_detected[] = _T("Please enter a message.");
2243 $mailing->message
= $post['mailing_corps'];
2246 switch ($post['sender']) {
2247 case GaletteMail
::SENDER_CURRENT
:
2248 $member = new Adherent($this->zdb
, (int)$this->login
->id
, false);
2249 $mailing->setSender(
2254 case GaletteMail
::SENDER_OTHER
:
2255 $mailing->setSender(
2256 $post['sender_name'],
2257 $post['sender_address']
2260 case GaletteMail
::SENDER_PREFS
:
2262 //nothing to do; this is the default :)
2266 $mailing->html
= (isset($post['mailing_html'])) ?
true : false;
2268 //handle attachments
2269 if (isset($_FILES['files'])) {
2270 for ($i = 0; $i < count($_FILES['files']['name']); $i++
) {
2271 if ($_FILES['files']['error'][$i] === UPLOAD_ERR_OK
) {
2272 if ($_FILES['files']['tmp_name'][$i] != '') {
2273 if (is_uploaded_file($_FILES['files']['tmp_name'][$i])) {
2275 foreach (array_keys($_FILES['files']) as $key) {
2276 $da_file[$key] = $_FILES['files'][$key][$i];
2278 $res = $mailing->store($da_file);
2280 //what to do if one of attachments fail? should other be removed?
2281 $error_detected[] = $mailing->getAttachmentErrorMessage($res);
2285 } elseif ($_FILES['files']['error'][$i] !== UPLOAD_ERR_NO_FILE
) {
2287 $this->logo
->getPhpErrorMessage($_FILES['files']['error'][$i]),
2290 $error_detected[] = $this->logo
->getPhpErrorMessage(
2291 $_FILES['files']['error'][$i]
2297 if (count($error_detected) == 0
2298 && !isset($post['mailing_reset'])
2299 && !isset($post['mailing_save'])
2301 $mailing->current_step
= Mailing
::STEP_PREVIEW
;
2303 $mailing->current_step
= Mailing
::STEP_START
;
2307 if (isset($post['mailing_confirm']) && count($error_detected) == 0) {
2308 $mailing->current_step
= Mailing
::STEP_SEND
;
2309 //ok... let's go for fun
2310 $sent = $mailing->send();
2311 if ($sent == Mailing
::MAIL_ERROR
) {
2312 $mailing->current_step
= Mailing
::STEP_START
;
2314 '[Mailings] Message was not sent. Errors: ' .
2315 print_r($mailing->errors
, true),
2318 foreach ($mailing->errors
as $e) {
2319 $error_detected[] = $e;
2322 $mlh = new MailingHistory($this->zdb
, $this->login
, null, $mailing);
2323 $mlh->storeMailing(true);
2325 '[Mailings] Message has been sent.',
2328 $mailing->current_step
= Mailing
::STEP_SENT
;
2330 $filters->selected
= null;
2331 $this->session
->filter_members
= $filters;
2332 $this->session
->mailing
= null;
2333 $success_detected[] = _T("Mailing has been successfully sent!");
2334 $goto = $redirect_url;
2338 if ($mailing->current_step
!== Mailing
::STEP_SENT
) {
2339 $this->session
->mailing
= $mailing;
2342 /** TODO: replace that... */
2343 $this->session
->labels
= $mailing->unreachables
;
2345 if (!isset($post['html_editor_active'])
2346 ||
trim($post['html_editor_active']) == ''
2348 $post['html_editor_active'] = $this->preferences
->pref_editor_enabled
;
2351 if (isset($post['mailing_save'])) {
2352 //user requested to save the mailing
2353 $histo = new MailingHistory($this->zdb
, $this->login
, null, $mailing);
2354 if ($histo->storeMailing() !== false) {
2355 $success_detected[] = _T("Mailing has been successfully saved.");
2356 $this->session
->mailing
= null;
2361 //flash messages if any
2362 if (count($error_detected) > 0) {
2363 foreach ($error_detected as $error) {
2364 $this->flash
->addMessage('error_detected', $error);
2367 if (count($success_detected) > 0) {
2368 foreach ($success_detected as $success) {
2369 $this->flash
->addMessage('success_detected', $success);
2375 ->withHeader('Location', $goto);
2377 )->setName('doMailing')->add($authenticate);
2381 '/mailing/preview[/{id:\d+}]',
2382 function ($request, $response, $args) {
2383 $post = $request->getParsedBody();
2384 // check for ajax mode
2386 if ($request->isXhr()
2387 ||
isset($post['ajax'])
2388 && $post['ajax'] == 'true'
2394 if (isset($args['id'])) {
2395 $mailing = new Mailing($this->preferences
, null);
2396 MailingHistory
::loadFrom($this->zdb
, (int)$args['id'], $mailing, false);
2397 $attachments = $mailing->attachments
;
2399 $mailing = $this->session
->mailing
;
2401 switch ($post['sender']) {
2402 case GaletteMail
::SENDER_CURRENT
:
2403 $member = new Adherent($this->zdb
, (int)$this->login
->id
, false);
2404 $mailing->setSender(
2409 case GaletteMail
::SENDER_OTHER
:
2410 $mailing->setSender(
2411 $post['sender_name'],
2412 $post['sender_address']
2415 case GaletteMail
::SENDER_PREFS
:
2417 //nothing to do; this is the default :)
2421 $mailing->subject
= $post['subject'];
2422 $mailing->message
= $post['body'];
2423 $mailing->html
= ($post['html'] === 'true');
2424 $attachments = (isset($post['attachments']) ?
$post['attachments'] : []);
2428 $this->view
->render(
2430 'mailing_preview.tpl',
2432 'page_title' => _T("Mailing preview"),
2433 'mailing_id' => $args['id'],
2434 'mode' => ($ajax ?
'ajax' : ''),
2435 'mailing' => $mailing,
2436 'recipients' => $mailing->recipients
,
2437 'sender' => $mailing->getSenderName() . ' <' .
2438 $mailing->getSenderAddress() . '>',
2439 'attachments' => $attachments
2445 )->setName('mailingPreview')->add($authenticate);
2448 '/mailing/preview/{id:\d+}/attachment/{pos:\d+}',
2449 function ($request, $response, $args) {
2450 $mailing = new Mailing($this->preferences
, null);
2451 MailingHistory
::loadFrom($this->zdb
, (int)$args['id'], $mailing, false);
2452 $attachments = $mailing->attachments
;
2453 $attachment = $attachments[$args['pos']];
2454 $filepath = $attachment->getDestDir() . $attachment->getFileName();
2457 $ext = pathinfo($attachment->getFileName())['extension'];
2458 $response = $response->withHeader('Content-type', $attachment->getMimeType($filepath));
2460 $body = $response->getBody();
2461 $body->write(file_get_contents($filepath));
2464 )->setName('previewAttachment')->add($authenticate);
2467 '/ajax/mailing/set-recipients',
2468 function ($request, $response, $args) {
2469 $post = $request->getParsedBody();
2470 $mailing = $this->session
->mailing
;
2474 $members = $m->getArrayList(
2475 $post['recipients'],
2484 $mailing->setRecipients($members);
2486 $this->session
->mailing
= $mailing;
2489 $this->view
->render(
2491 'mailing_recipients.tpl',
2493 'mailing' => $mailing
2499 )->setName('mailingRecipients')->add($authenticate);
2504 function ($request, $response) {
2505 $texts = new Texts($this->texts_fields
, $this->preferences
, $this->router
);
2508 'impending' => $texts->getTexts('impendingduedate', $this->preferences
->pref_lang
),
2509 'late' => $texts->getTexts('lateduedate', $this->preferences
->pref_lang
)
2512 $members = new Members();
2513 $reminders = $members->getRemindersCount();
2516 $this->view
->render(
2520 'page_title' => _T("Reminders"),
2521 'previews' => $previews,
2522 'require_dialog' => true,
2523 'count_impending' => $reminders['impending'],
2524 'count_impending_nomail' => $reminders['nomail']['impending'],
2525 'count_late' => $reminders['late'],
2526 'count_late_nomail' => $reminders['nomail']['late']
2531 )->setName('reminders')->add($authenticate);
2535 function ($request, $response) {
2536 $error_detected = [];
2537 $warning_detected = [];
2538 $success_detected = [];
2540 $post = $request->getParsedBody();
2541 $texts = new Texts($this->texts_fields
, $this->preferences
, $this->router
);
2543 if (isset($post['reminders'])) {
2544 $selected = $post['reminders'];
2546 $reminders = new Reminders($selected);
2549 $labels_members = array();
2550 if (isset($post['reminder_wo_mail'])) {
2554 $list_reminders = $reminders->getList($this->zdb
, $labels);
2555 if (count($list_reminders) == 0) {
2556 $warning_detected[] = _T("No reminder to send for now.");
2558 foreach ($list_reminders as $reminder) {
2559 if ($labels === false) {
2560 //send reminders by mail
2561 $sent = $reminder->send($texts, $this->history
, $this->zdb
);
2563 if ($sent === true) {
2564 $success_detected[] = $reminder->getMessage();
2566 $error_detected[] = $reminder->getMessage();
2569 //generate labels for members without mail address
2570 $labels_members[] = $reminder->member_id
;
2574 if ($labels === true) {
2575 if (count($labels_members) > 0) {
2576 $labels_filters = new MembersList();
2577 $labels_filters->selected
= $labels_members;
2578 $this->session
->filters_reminders_labels
= $labels_filters;
2581 ->withHeader('Location', $this->router
->pathFor('pdf-member-labels'));
2583 $error_detected[] = _T("There are no member to proceed.");
2587 if (count($error_detected) > 0) {
2590 _T("Reminder has not been sent:")
2594 if (count($success_detected) > 0) {
2597 _T("Sent reminders:")
2602 //flash messages if any
2603 if (count($error_detected) > 0) {
2604 foreach ($error_detected as $error) {
2605 $this->flash
->addMessage('error_detected', $error);
2608 if (count($warning_detected) > 0) {
2609 foreach ($warning_detected as $warning) {
2610 $this->flash
->addMessage('warning_detected', $warning);
2613 if (count($success_detected) > 0) {
2614 foreach ($success_detected as $success) {
2615 $this->flash
->addMessage('success_detected', $success);
2621 ->withHeader('Location', $this->router
->pathFor('reminders'));
2623 )->setName('doReminders')->add($authenticate);
2626 '/members/reminder-filter/{membership:nearly|late}/{mail:withmail|withoutmail}',
2627 function ($request, $response, $args) {
2628 //always reset filters
2629 $filters = new MembersList();
2630 $filters->filter_account
= Members
::ACTIVE_ACCOUNT
;
2632 $membership = ($args['membership'] === 'nearly' ?
2633 Members
::MEMBERSHIP_NEARLY
:
2634 Members
::MEMBERSHIP_LATE
);
2635 $filters->membership_filter
= $membership;
2637 //TODO: filter on reminder may take care of parent email as well
2638 $mail = ($args['mail'] === 'withmail' ?
2639 Members
::FILTER_W_EMAIL
:
2640 Members
::FILTER_WO_EMAIL
);
2641 $filters->email_filter
= $mail;
2643 $this->session
->filter_members
= $filters;
2647 ->withHeader('Location', $this->router
->pathFor('members'));
2649 )->setName('reminders-filter')->add($authenticate);
2653 '/attendance-sheet/details',
2654 function ($request, $response) {
2655 $post = $request->getParsedBody();
2657 if ($this->session
->filter_members
!== null) {
2658 $filters = $this->session
->filter_members
;
2660 $filters = new MembersList();
2663 // check for ajax mode
2665 if ($request->isXhr()
2666 ||
isset($post['ajax'])
2667 && $post['ajax'] == 'true'
2671 //retrieve selected members
2672 $selection = (isset($post['selection']) ) ?
$post['selection'] : array();
2674 $filters->selected
= $selection;
2675 $this->session
->filter_members
= $filters;
2677 $selection = $filters->selected
;
2682 $this->view
->render(
2684 'attendance_sheet_details.tpl',
2686 'page_title' => _T("Attendance sheet configuration"),
2688 'selection' => $selection
2693 )->setName('attendance_sheet_details')->add($authenticate);
2696 '/attendance-sheet',
2697 function ($request, $response) {
2698 $post = $request->getParsedBody();
2700 if ($this->session
->filter_members
!== null) {
2701 $filters = $this->session
->filter_members
;
2703 $filters = new MembersList();
2706 //retrieve selected members
2707 $selection = (isset($post['selection']) ) ?
$post['selection'] : array();
2709 $filters->selected
= $selection;
2710 $this->session
->filter_members
= $filters;
2712 if (count($filters->selected
) == 0) {
2713 Analog
::log('No member selected to generate attendance sheet', Analog
::INFO
);
2714 $this->flash
->addMessage(
2716 _T("No member selected to generate attendance sheet")
2721 ->withHeader('Location', $this->router
->pathFor('members'));
2725 $members = $m->getArrayList(
2727 array('nom_adh', 'prenom_adh'),
2731 if (!is_array($members) ||
count($members) < 1) {
2732 Analog
::log('No member selected to generate attendance sheet', Analog
::INFO
);
2733 $this->flash
->addMessage(
2735 _T("No member selected to generate attendance sheet")
2740 ->withHeader('Location', $this->router
->pathFor('members'));
2743 $doc_title = _T("Attendance sheet");
2744 if (isset($post['sheet_type']) && trim($post['sheet_type']) != '') {
2745 $doc_title = $post['sheet_type'];
2748 $pdf = new Galette\IO\
PdfAttendanceSheet($this->preferences
);
2749 $pdf->doc_title
= $doc_title;
2750 // Set document information
2751 $pdf->SetTitle($doc_title);
2753 if (isset($post['sheet_title']) && trim($post['sheet_title']) != '') {
2754 $pdf->sheet_title
= $post['sheet_title'];
2756 if (isset($post['sheet_sub_title']) && trim($post['sheet_sub_title']) != '') {
2757 $pdf->sheet_sub_title
= $post['sheet_sub_title'];
2759 if (isset($post['sheet_date']) && trim($post['sheet_date']) != '') {
2760 $dformat = __("Y-m-d");
2761 $date = DateTime
::createFromFormat(
2765 $pdf->sheet_date
= $date;
2767 //with or without images?
2768 if (isset($post['sheet_photos']) && $post['sheet_photos'] === '1') {
2771 $pdf->drawSheet($members, $doc_title);
2772 $response = $this->response
->withHeader('Content-type', 'application/pdf');
2773 $response->write($pdf->Output(_T("attendance_sheet") . '.pdf', 'D'));
2776 )->setName('attendance_sheet')->add($authenticate);
2779 '/ajax/members[/{option:page|order}/{value:\d+}]',
2780 function ($request, $response, $args) {
2781 $post = $request->getParsedBody();
2783 if (isset($this->session
->ajax_members_filters
)) {
2784 $filters = $this->session
->ajax_members_filters
;
2786 $filters = new MembersList();
2789 if (isset($args['option']) && $args['option'] == 'page') {
2790 $filters->current_page
= (int)$args['value'];
2793 //numbers of rows to display
2794 if (isset($post['nbshow']) && is_numeric($post['nbshow'])) {
2795 $filters->show
= $post['nbshow'];
2798 $members = new Members($filters);
2799 if (!$this->login
->isAdmin() && !$this->login
->isStaff()) {
2800 if ($this->login
->isGroupManager()) {
2801 $members_list = $members->getManagedMembersList(true);
2806 [$this->login
->id
, $this->login
->login
],
2807 'Trying to list group members without access from #%id (%login)'
2811 throw new Exception('Access denied.');
2815 $members_list = $members->getMembersList(true);
2818 //assign pagination variables to the template and add pagination links
2819 $filters->setSmartyPagination($this->router
, $this->view
->getSmarty(), false);
2821 $this->session
->ajax_members_filters
= $filters;
2823 $selected_members = null;
2824 $unreachables_members = null;
2825 if (!isset($post['from'])) {
2826 $mailing = $this->session
->mailing
;
2827 if (!isset($post['members'])) {
2828 $selected_members = $mailing->recipients
;
2829 $unreachables_members = $mailing->unreachables
;
2832 $selected_members = $m->getArrayList($post['members']);
2833 if (isset($post['unreachables']) && is_array($post['unreachables'])) {
2834 $unreachables_members = $m->getArrayList($post['unreachables']);
2838 switch ($post['from']) {
2840 if (!isset($post['gid'])) {
2842 'Trying to list group members with no group id provided',
2845 throw new Exception('A group id is required.');
2848 if (!isset($post['members'])) {
2849 $group = new Group((int)$post['gid']);
2850 $selected_members = array();
2851 if (!isset($post['mode']) ||
$post['mode'] == 'members') {
2852 $selected_members = $group->getMembers();
2853 } elseif ($post['mode'] == 'managers') {
2854 $selected_members = $group->getManagers();
2857 'Trying to list group members with unknown mode',
2860 throw new Exception('Unknown mode.');
2865 $selected_members = $m->getArrayList($post['members']);
2866 if (isset($post['unreachables']) && is_array($post['unreachables'])) {
2867 $unreachables_members = $m->getArrayList($post['unreachables']);
2872 if (!isset($post['id_adh'])) {
2873 throw new \
RuntimeException(
2874 'Current selected member must be excluded while attaching!'
2883 'filters' => $filters,
2884 'members_list' => $members_list,
2885 'selected_members' => $selected_members,
2886 'unreachables_members' => $unreachables_members
2889 if (isset($post['multiple'])) {
2890 $params['multiple'] = true;
2893 if (isset($post['gid'])) {
2894 $params['the_id'] = $post['gid'];
2897 if (isset($post['id_adh'])) {
2898 $params['excluded'] = $post['id_adh'];
2902 $this->view
->render(
2909 )->setName('ajaxMembers')->add($authenticate);
2912 '/ajax/group/members',
2913 function ($request, $response) {
2914 $post = $request->getParsedBody();
2916 $ids = $post['persons'];
2917 $mode = $post['person_mode'];
2919 if (!$ids ||
!$mode) {
2921 'Missing persons and mode for ajaxGroupMembers',
2928 $persons = $m->getArrayList($ids);
2931 $this->view
->render(
2933 'group_persons.tpl',
2935 'persons' => $persons,
2936 'person_mode' => $mode
2941 )->setName('ajaxGroupMembers')->add($authenticate);
2944 '/member/{id:\d+}/file/{fid:\d+}/{pos:\d+}/{name}',
2945 function ($request, $response, $args) {
2947 $id = (int)$args['id'];
2948 if ($this->login
->id
!= $args['id']
2949 && !$this->login
->isAdmin()
2950 && !$this->login
->isStaff()
2951 && !$this->login
->isGroupManager()
2961 'children' => false,
2964 $member = new Adherent($this->zdb
, $id, $deps);
2966 if (!$denied && $this->login
->id
!= $args['id']
2967 && $this->login
->isGroupManager()
2968 && !$this->login
->isStaff()
2969 && !$this->login
->isAdmin()
2971 //check if current logged in user can manage loaded member
2972 $groups = $member->groups
;
2973 $can_manage = false;
2974 foreach ($groups as $group) {
2975 if ($this->login
->isGroupManager($group->getId())) {
2980 if ($can_manage !== true) {
2982 'Logged in member ' . $this->login
->login
.
2983 ' has tried to load member #' . $member->id
.
2984 ' but do not manage any groups he belongs to.',
2991 if ($denied === false) {
2992 $fields = $member->getDynamicFields()->getFields();
2993 if (!isset($fields[$args['fid']])) {
2994 //field does not exists or access is forbidden
2999 if ($denied === true) {
3000 $this->flash
->addMessage(
3002 _T("You do not have permission for requested URL.")
3009 $this->router
->pathFor(
3016 $filename = str_replace(
3027 'member_%mid_field_%fid_value_%pos'
3030 if (file_exists(GALETTE_FILES_PATH
. $filename)) {
3031 $type = File
::getMimeType(GALETTE_FILES_PATH
. $filename);
3032 $response = $this->response
3033 ->withHeader('Content-Type', $type)
3034 ->withHeader('Content-Disposition', 'attachment;filename="' . $args['name'] . '"')
3035 ->withHeader('Pragma', 'no-cache');
3036 $response->write(readfile(GALETTE_FILES_PATH
. $filename));
3040 'A request has been made to get an exported file named `' .
3041 $filename .'` that does not exists.',
3045 $this->flash
->addMessage(
3047 _T("The file does not exists or cannot be read :(")
3054 $this->router
->pathFor('member', ['id' => $args['id']])
3058 )->setName('getDynamicFile')->add($authenticate);
3061 '/members/mass-change',
3062 function ($request, $response) {
3063 $filters = $this->session
->filter_members
;
3066 'id' => $filters->selected
,
3067 'redirect_uri' => $this->router
->pathFor('members')
3070 $fc = $this->fields_config
;
3071 $form_elements = $fc->getMassiveFormElements($this->members_fields
, $this->login
);
3079 'children' => false,
3082 $member = new Adherent($this->zdb
, null, $deps);
3085 $statuts = new Status($this->zdb
);
3088 $this->view
->render(
3090 'mass_change_members.tpl',
3092 'mode' => $request->isXhr() ?
'ajax' : '',
3093 'page_title' => str_replace(
3096 _T('Mass change %count members')
3098 'form_url' => $this->router
->pathFor('masschangeMembersReview'),
3099 'cancel_uri' => $this->router
->pathFor('members'),
3101 'member' => $member,
3102 'fieldsets' => $form_elements['fieldsets'],
3103 'titles_list' => Titles
::getList($this->zdb
),
3104 'statuts' => $statuts->getList(),
3105 'require_mass' => true
3110 )->setName('masschangeMembers')->add($authenticate);
3113 '/members/mass-change/validate',
3114 function ($request, $response) {
3115 $post = $request->getParsedBody();
3117 if (!isset($post['confirm'])) {
3118 $this->flash
->addMessage(
3120 _T("Mass changes has not been confirmed!")
3123 //we want only visibles fields
3124 $fc = $this->fields_config
;
3125 $form_elements = $fc->getMassiveFormElements($this->members_fields
, $this->login
);
3128 foreach ($form_elements['fieldsets'] as $form_element) {
3129 foreach ($form_element->elements
as $field) {
3130 if (isset($post[$field->field_id
]) && isset($post['mass_' . $field->field_id
])) {
3131 $changes[$field->field_id
] = [
3132 'label' => $field->label
,
3133 'value' => $post[$field->field_id
]
3140 $filters = $this->session
->filter_members
;
3142 'id' => $filters->selected
,
3143 'redirect_uri' => $this->router
->pathFor('members')
3147 $statuts = new Status($this->zdb
);
3150 $this->view
->render(
3152 'mass_change_members.tpl',
3154 'mode' => $request->isXhr() ?
'ajax' : '',
3155 'page_title' => str_replace(
3158 _T('Review mass change %count members')
3160 'form_url' => $this->router
->pathFor('massstoremembers'),
3161 'cancel_uri' => $this->router
->pathFor('members'),
3163 'titles_list' => Titles
::getList($this->zdb
),
3164 'statuts' => $statuts->getList(),
3165 'changes' => $changes
3170 )->setName('masschangeMembersReview')->add($authenticate);
3173 '/members/mass-change',
3174 function ($request, $response, $args) {
3175 $post = $request->getParsedBody();
3176 $redirect_url = $post['redirect_uri'];
3177 $error_detected = [];
3180 unset($post['redirect_uri']);
3181 if (!isset($post['confirm'])) {
3182 $error_detected[] = _T("Mass changes has not been confirmed!");
3184 unset($post['confirm']);
3188 $fc = $this->fields_config
;
3189 $form_elements = $fc->getMassiveFormElements($this->members_fields
, $this->login
);
3190 $disabled = $this->members_fields
;
3191 foreach (array_keys($post) as $key) {
3193 foreach ($form_elements['fieldsets'] as $fieldset) {
3194 if (isset($fieldset->elements
[$key])) {
3201 'Permission issue mass editing field ' . $key,
3206 unset($disabled[$key]);
3210 if (!count($post)) {
3211 $error_detected[] = _T("Nothing to do!");
3213 $is_manager = !$this->login
->isAdmin() && !$this->login
->isStaff() && $this->login
->isGroupManager();
3214 foreach ($ids as $id) {
3217 'groups' => $is_manager,
3220 'children' => false,
3223 $member = new Adherent($this->zdb
, (int)$id, $deps);
3224 $member->setDependencies(
3226 $this->members_fields
,
3231 $groups = $member->groups
;
3232 $is_managed = false;
3233 foreach ($groups as $g) {
3234 if ($this->login
->isGroupManager($g->getId())) {
3241 'Trying to edit member #' . $id . ' without appropriate ACLs',
3244 $error_detected[] = _T('No permission to edit member');
3249 $valid = $member->check($post, [], $disabled);
3250 if ($valid === true) {
3251 $done = $member->store();
3253 $error_detected[] = _T("An error occurred while storing the member.");
3258 $error_detected = array_merge($error_detected, $valid);
3264 if ($mass == 0 && !count($error_detected)) {
3265 $error_detected[] = _T('Something went wront during mass edition!');
3267 $this->flash
->addMessage(
3272 _T('%count members has been changed successfully!')
3277 if (count($error_detected) > 0) {
3278 foreach ($error_detected as $error) {
3279 $this->flash
->addMessage(
3286 if (!$request->isXhr()) {
3289 ->withHeader('Location', $redirect_url);
3291 return $response->withJson(
3293 'success' => count($error_detected) === 0
3298 )->setName('massstoremembers')->add($authenticate);
3302 '/members/duplicate/{' . Adherent
::PK
. ':\d+}',
3303 function ($request, $response, $args) {
3304 $id_adh = (int)$args[Adherent
::PK
];
3305 $adh = new Adherent($this->zdb
, $id_adh, ['dynamics' => true]);
3306 $adh->setDuplicate();
3308 //store entity in session
3309 $this->session
->member
= $adh;
3313 ->withHeader('Location', $this->router
->pathFor('editmember', ['action' => 'add']));
3315 )->setName('duplicateMember')->add($authenticate);
3321 function ($request, $response) {
3322 if ($request->isPost()) {
3323 $post = $request->getParsedBody();
3325 $post = $request->getQueryParams();
3329 if (isset($post['search_title'])) {
3330 $name = $post['search_title'];
3331 unset($post['search_title']);
3334 //when using advanced search, no parameters are sent
3335 if (isset($post['advanced_search'])) {
3337 $filters = $this->session
->filter_members
;
3338 foreach ($filters->search_fields
as $field) {
3339 $post[$field] = $filters->$field;
3343 //reformat, add required infos
3345 'parameters' => $post,
3346 'form' => 'Adherent',
3350 $sco = new Galette\Entity\
SavedSearch($this->zdb
, $this->login
);
3351 if ($check = $sco->check($post)) {
3352 if (!$res = $sco->store()) {
3353 if ($res === false) {
3354 $this->flash
->addMessage(
3356 _T("An SQL error has occurred while storing search.")
3359 $this->flash
->addMessage(
3361 _T("This search is already saved.")
3365 $this->flash
->addMessage(
3367 _T("Search has been saved.")
3372 foreach ($sco->getErrors() as $error) {
3373 $this->flash
->addMessage(
3380 if ($request->isGet()) {
3383 ->withHeader('Location', $this->router
->pathFor('members'));
3386 )->setName('saveSearch');
3389 '/saved-searches[/{option:page|order}/{value:\d+}]',
3390 function ($request, $response, $args = []) {
3392 if (isset($args['option'])) {
3393 $option = $args['option'];
3396 if (isset($args['value'])) {
3397 $value = $args['value'];
3400 if (isset($this->session
->filter_savedsearch
)) {
3401 $filters = $this->session
->filter_savedsearch
;
3403 $filters = new SavedSearchesList();
3406 if ($option !== null) {
3409 $filters->current_page
= (int)$value;
3412 $filters->orderby
= $value;
3417 $searches = new SavedSearches($this->zdb
, $this->login
, $filters);
3418 $list = $searches->getList(true);
3420 //assign pagination variables to the template and add pagination links
3421 $filters->setSmartyPagination($this->router
, $this->view
->getSmarty(), false);
3423 $this->session
->filter_savedsearch
= $filters;
3426 $this->view
->render(
3428 'saved_searches.tpl',
3430 'page_title' => _T("Saved searches"),
3431 'require_dialog' => true,
3432 'searches' => $list,
3433 'nb' => $searches->getCount(),
3434 'filters' => $filters
3439 )->setName('searches')->add($authenticate);
3442 '/search/remove/{id:\d+}',
3443 function ($request, $response, $args) {
3445 'id' => $args['id'],
3446 'redirect_uri' => $this->router
->pathFor('searches')
3450 $this->view
->render(
3452 'confirm_removal.tpl',
3454 'type' => _T("Saved search"),
3455 'mode' => $request->isXhr() ?
'ajax' : '',
3456 'page_title' => _T('Remove saved search'),
3457 'form_url' => $this->router
->pathFor('doRemoveSearch', ['id' => $args['id']]),
3458 'cancel_uri' => $this->router
->pathFor('searches'),
3464 )->setName('removeSearch')->add($authenticate);
3468 function ($request, $response) {
3469 $filters = $this->session
->filter_savedsearch
;
3472 'id' => $filters->selected
,
3473 'redirect_uri' => $this->router
->pathFor('searches')
3477 $this->view
->render(
3479 'confirm_removal.tpl',
3481 'type' => _T("Saved search"),
3482 'mode' => $request->isXhr() ?
'ajax' : '',
3483 'page_title' => _T('Remove saved searches'),
3484 'message' => str_replace(
3487 _T('You are about to remove %count searches.')
3489 'form_url' => $this->router
->pathFor('doRemoveSearch'),
3490 'cancel_uri' => $this->router
->pathFor('searches'),
3496 )->setName('removeSearches')->add($authenticate);
3499 '/search/remove' . '[/{id:\d+}]',
3500 function ($request, $response) {
3501 $post = $request->getParsedBody();
3502 $ajax = isset($post['ajax']) && $post['ajax'] === 'true';
3505 $uri = isset($post['redirect_uri']) ?
3506 $post['redirect_uri'] :
3507 $this->router
->pathFor('slash');
3509 if (!isset($post['confirm'])) {
3510 $this->flash
->addMessage(
3512 _T("Removal has not been confirmed!")
3515 if (isset($this->session
->filter_savedsearch
)) {
3516 $filters = $this->session
->filter_savedsearch
;
3518 $filters = new SavedSearchesList();
3520 $searches = new SavedSearches($this->zdb
, $this->login
, $filters);
3522 if (!is_array($post['id'])) {
3523 $ids = (array)$post['id'];
3528 $del = $searches->remove($ids, $this->history
);
3530 if ($del !== true) {
3531 $error_detected = _T("An error occurred trying to remove searches :/");
3533 $this->flash
->addMessage(
3538 $success_detected = str_replace(
3541 _T("%count searches have been successfully deleted.")
3544 $this->flash
->addMessage(
3556 ->withHeader('Location', $uri);
3558 return $response->withJson(
3560 'success' => $success
3565 )->setName('doRemoveSearch')->add($authenticate);
3568 '/save-search/{id}',
3569 function ($request, $response, $args) {
3571 $sco = new Galette\Entity\
SavedSearch($this->zdb
, $this->login
, (int)$args['id']);
3572 $this->flash
->addMessage(
3574 _T("Saved search loaded")
3576 } catch (\Exception
$e) {
3577 $this->flash
->addMessage(
3579 _T("An SQL error has occurred while storing search.")
3582 $parameters = (array)$sco->parameters
;
3585 if (isset($parameters['free_search'])) {
3586 $filters = new AdvancedMembersList();
3588 $filters = new MembersList();
3591 foreach ($parameters as $key => $value) {
3592 $filters->$key = $value;
3594 $this->session
->filter_members
= $filters;
3598 ->withHeader('Location', $this->router
->pathFor('members'));
3600 )->setName('loadSearch');