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 'require_calendar' => true,
149 'autocomplete' => true,
152 'titles_list' => Titles
::getList($this->zdb
),
154 'spam_pass' => $spam_pass,
155 'spam_img' => $spam_img,
156 'fieldsets' => $form_elements['fieldsets'],
157 'hidden_elements' => $form_elements['hiddens']
162 )->setName('subscribe');
164 //members list CSV export
166 '/members/export/csv',
167 function ($request, $response) {
170 if (isset($this->session
->filter_members
)) {
171 //CAUTION: this one may be simple or advanced, display must change
172 $filters = $this->session
->filter_members
;
174 $filters = new MembersList();
177 $export_fields = null;
178 if (file_exists(GALETTE_CONFIG_PATH
. 'local_export_fields.inc.php')) {
179 include_once GALETTE_CONFIG_PATH
. 'local_export_fields.inc.php';
180 $export_fields = $fields;
184 $fc = $this->fields_config
;
185 $visibles = $fc->getVisibilities();
186 //hack for id_adh and parent_id
187 $hacks = ['id_adh', 'parent_id'];
188 foreach ($hacks as $hack) {
189 if ($visibles[$hack] == FieldsConfig
::NOBODY
) {
190 $visibles[$hack] = FieldsConfig
::MANAGER
;
193 $access_level = $this->login
->getAccessLevel();
196 foreach ($this->members_fields
as $k => $f) {
197 // skip fields blacklisted for export
198 if ($k === 'mdp_adh' ||
199 ($export_fields !== null &&
200 (is_array($export_fields) && !in_array($k, $export_fields)))
205 // skip fields according to access control
206 if ($visibles[$k] == FieldsConfig
::NOBODY ||
207 ($visibles[$k] == FieldsConfig
::ADMIN
&&
208 $access_level < Authentication
::ACCESS_ADMIN
) ||
209 ($visibles[$k] == FieldsConfig
::STAFF
&&
210 $access_level < Authentication
::ACCESS_STAFF
) ||
211 ($visibles[$k] == FieldsConfig
::MANAGER
&&
212 $access_level < Authentication
::ACCESS_MANAGER
)
218 $labels[] = $f['label'];
221 $members = new Members($filters);
222 $members_list = $members->getArrayList(
231 $s = new Status($this->zdb
);
232 $statuses = $s->getList();
235 $titles = $t->getList($this->zdb
);
237 foreach ($members_list as &$member) {
238 if (isset($member->id_statut
)) {
240 $member->id_statut
= $statuses[$member->id_statut
];
243 if (isset($member->titre_adh
)) {
245 $member->titre_adh
= $titles[$member->titre_adh
]->short
;
249 if (isset($member->date_crea_adh
)) {
250 if ($member->date_crea_adh
!= ''
251 && $member->date_crea_adh
!= '1901-01-01'
253 $dcrea = new DateTime($member->date_crea_adh
);
254 $member->date_crea_adh
= $dcrea->format(__("Y-m-d"));
256 $member->date_crea_adh
= '';
260 if (isset($member->date_modif_adh
)) {
261 if ($member->date_modif_adh
!= ''
262 && $member->date_modif_adh
!= '1901-01-01'
264 $dmodif = new DateTime($member->date_modif_adh
);
265 $member->date_modif_adh
= $dmodif->format(__("Y-m-d"));
267 $member->date_modif_adh
= '';
271 if (isset($member->date_echeance
)) {
272 if ($member->date_echeance
!= ''
273 && $member->date_echeance
!= '1901-01-01'
275 $dech = new DateTime($member->date_echeance
);
276 $member->date_echeance
= $dech->format(__("Y-m-d"));
278 $member->date_echeance
= '';
282 if (isset($member->ddn_adh
)) {
283 if ($member->ddn_adh
!= ''
284 && $member->ddn_adh
!= '1901-01-01'
286 $ddn = new DateTime($member->ddn_adh
);
287 $member->ddn_adh
= $ddn->format(__("Y-m-d"));
289 $member->ddn_adh
= '';
293 if (isset($member->sexe_adh
)) {
295 switch ($member->sexe_adh
) {
297 $member->sexe_adh
= _T("Man");
299 case Adherent
::WOMAN
:
300 $member->sexe_adh
= _T("Woman");
303 $member->sexe_adh
= _T("Unspecified");
309 if (isset($member->activite_adh
)) {
310 $member->activite_adh
311 = ($member->activite_adh
) ?
_T("Yes") : _T("No");
313 if (isset($member->bool_admin_adh
)) {
314 $member->bool_admin_adh
315 = ($member->bool_admin_adh
) ?
_T("Yes") : _T("No");
317 if (isset($member->bool_exempt_adh
)) {
318 $member->bool_exempt_adh
319 = ($member->bool_exempt_adh
) ?
_T("Yes") : _T("No");
321 if (isset($member->bool_display_info
)) {
322 $member->bool_display_info
323 = ($member->bool_display_info
) ?
_T("Yes") : _T("No");
326 $filename = 'filtered_memberslist.csv';
327 $filepath = CsvOut
::DEFAULT_DIRECTORY
. $filename;
328 $fp = fopen($filepath, 'w');
332 Csv
::DEFAULT_SEPARATOR
,
344 $filepath = CsvOut
::DEFAULT_DIRECTORY
. $filename;
345 if (file_exists($filepath)) {
346 $response = $this->response
->withHeader('Content-Description', 'File Transfer')
347 ->withHeader('Content-Type', 'text/csv')
348 ->withHeader('Content-Disposition', 'attachment;filename="' . $filename . '"')
349 ->withHeader('Pragma', 'no-cache')
350 ->withHeader('Content-Transfer-Encoding', 'binary')
351 ->withHeader('Expires', '0')
352 ->withHeader('Cache-Control', 'must-revalidate')
353 ->withHeader('Pragma', 'public');
355 $stream = fopen('php://memory', 'r+');
356 fwrite($stream, file_get_contents($filepath));
359 return $response->withBody(new \Slim\Http\
Stream($stream));
362 'A request has been made to get an exported file named `' .
363 $filename .'` that does not exists.',
366 $notFound = $this->notFoundHandler
;
367 return $notFound($request, $response);
371 )->setName('csv-memberslist')->add($authenticate);
375 '/members[/{option:page|order}/{value:\d+}]',
376 function ($request, $response, $args = []) {
378 if (isset($args['option'])) {
379 $option = $args['option'];
382 if (isset($args['value'])) {
383 $value = $args['value'];
386 if (isset($this->session
->filter_members
)) {
387 $filters = $this->session
->filter_members
;
389 $filters = new MembersList();
392 if ($option !== null) {
395 $filters->current_page
= (int)$value;
398 $filters->orderby
= $value;
403 $members = new Members($filters);
405 $members_list = array();
406 if ($this->login
->isAdmin() ||
$this->login
->isStaff()) {
407 $members_list = $members->getMembersList(true);
409 $members_list = $members->getManagedMembersList(true);
412 $groups = new Groups($this->zdb
, $this->login
);
413 $groups_list = $groups->getList();
415 //assign pagination variables to the template and add pagination links
416 $filters->setSmartyPagination($this->router
, $this->view
->getSmarty(), false);
417 $filters->setViewCommonsFilters($this->preferences
, $this->view
->getSmarty());
419 $this->session
->filter_members
= $filters;
424 'gestion_adherents.tpl',
426 'page_title' => _T("Members management"),
427 'require_dialog' => true,
428 'require_calendar' => true,
429 'require_mass' => true,
430 'members' => $members_list,
431 'filter_groups_options' => $groups_list,
432 'nb_members' => $members->getCount(),
433 'filters' => $filters,
434 'adv_filters' => $filters instanceof AdvancedMembersList
441 )->add($authenticate);
443 //members list filtering
446 function ($request, $response) {
447 $post = $request->getParsedBody();
448 if (isset($this->session
->filter_members
)) {
449 //CAUTION: this one may be simple or advanced, display must change
450 $filters = $this->session
->filter_members
;
452 $filters = new MembersList();
455 //reintialize filters
456 if (isset($post['clear_filter'])) {
457 $filters = new MembersList();
458 } elseif (isset($post['clear_adv_filter'])) {
459 $this->session
->filter_members
= null;
460 unset($this->session
->filter_members
);
464 ->withHeader('Location', $this->router
->pathFor('advanced-search'));
465 } elseif (isset($post['adv_criteria'])) {
468 ->withHeader('Location', $this->router
->pathFor('advanced-search'));
471 if (isset($post['filter_str'])) { //filter search string
472 $filters->filter_str
= stripslashes(
473 htmlspecialchars($post['filter_str'], ENT_QUOTES
)
477 if (isset($post['field_filter'])) {
478 if (is_numeric($post['field_filter'])) {
479 $filters->field_filter
= $post['field_filter'];
482 //membership to filter
483 if (isset($post['membership_filter'])) {
484 if (is_numeric($post['membership_filter'])) {
485 $filters->membership_filter
486 = $post['membership_filter'];
489 //account status to filter
490 if (isset($post['filter_account'])) {
491 if (is_numeric($post['filter_account'])) {
492 $filters->filter_account
= $post['filter_account'];
496 if (isset($post['email_filter'])) {
497 $filters->email_filter
= (int)$post['email_filter'];
500 if (isset($post['group_filter'])
501 && $post['group_filter'] > 0
503 $filters->group_filter
= (int)$post['group_filter'];
505 //number of rows to show
506 if (isset($post['nbshow'])) {
507 $filters->show
= $post['nbshow'];
510 if (isset($post['advanced_filtering'])) {
511 if (!$filters instanceof AdvancedMembersList
) {
512 $filters = new AdvancedMembersList($filters);
516 unset($post['advanced_filtering']);
518 foreach ($post as $k => $v) {
519 if (strpos($k, 'free_', 0) === 0) {
522 foreach ($post['free_field'] as $f) {
524 && trim($post['free_text'][$i]) !== ''
526 $fs_search = $post['free_text'][$i];
528 = (int)$post['free_logical_operator'][$i];
530 = (int)$post['free_query_operator'][$i];
531 $type = (int)$post['free_type'][$i];
536 'search' => $fs_search,
540 $filters->free_search
= $fs;
548 case 'contrib_min_amount':
549 case 'contrib_max_amount':
550 if (trim($v) !== '') {
563 if (isset($post['savesearch'])) {
568 $this->router
->pathFor(
575 $this->session
->filter_members
= $filters;
579 ->withHeader('Location', $this->router
->pathFor('members'));
581 )->setName('filter-memberslist')->add($authenticate);
586 function ($request, $response) {
587 if ($this->login
->isSuperAdmin()) {
590 ->withHeader('Location', $this->router
->pathFor('slash'));
601 $member = new Adherent($this->zdb
, $this->login
->login
, $deps);
604 $fc = $this->fields_config
;
605 $display_elements = $fc->getDisplayElements($this->login
);
612 'page_title' => _T("Member Profile"),
613 'require_dialog' => true,
615 'pref_lang' => $this->i18n
->getNameFromId($member->language
),
616 'pref_card_self' => $this->preferences
->pref_card_self
,
617 'groups' => Groups
::getSimpleList(),
619 'display_elements' => $display_elements
623 )->setName('me')->add($authenticate);
628 function ($request, $response, $args) {
639 $member = new Adherent($this->zdb
, (int)$id, $deps);
641 if ($this->login
->id
!= $id && !$this->login
->isAdmin() && !$this->login
->isStaff()) {
642 //check if requested member is part of managed groups
643 $groups = $member->groups
;
645 foreach ($groups as $g) {
646 if ($this->login
->isGroupManager($g->getId())) {
651 if ($is_managed !== true) {
652 //requested member is not part of managed groups,
653 //fall back to logged in member
655 'Trying to display member #' . $id . ' without appropriate ACLs',
663 $this->router
->pathFor(
665 ['id' => $this->login
->id
]
671 if ($member->id
== null) {
672 //member does not exists!
673 $this->flash
->addMessage(
675 str_replace('%id', $args['id'], _T("No member #%id."))
682 $this->router
->pathFor('slash')
686 // flagging fields visibility
687 $fc = $this->fields_config
;
688 $display_elements = $fc->getDisplayElements($this->login
);
695 'page_title' => _T("Member Profile"),
696 'require_dialog' => true,
698 'pref_lang' => $this->i18n
->getNameFromId($member->language
),
699 'pref_card_self' => $this->preferences
->pref_card_self
,
700 'groups' => Groups
::getSimpleList(),
702 'display_elements' => $display_elements
707 )->setName('member')->add($authenticate)->add($navMiddleware);
710 '/member/{action:edit|add}[/{id:\d+}]',
711 function ($request, $response, $args) {
712 $action = $args['action'];
714 if (isset($args['id'])) {
718 if ($action === 'edit' && $id === null) {
719 throw new \
RuntimeException(
720 _T("Member ID cannot ben null calling edit route!")
722 } elseif ($action === 'add' && $id !== null) {
725 ->withHeader('Location', $this->router
->pathFor('editmember', ['action' => 'add']));
737 if ($this->session
->member
!== null) {
738 $member = $this->session
->member
;
739 $this->session
->member
= null;
741 $member = new Adherent($this->zdb
, null, $deps);
744 if ($this->login
->isAdmin() ||
$this->login
->isStaff() ||
$this->login
->isGroupManager()) {
746 if ($member->id
!= $id) {
749 if (!$this->login
->isAdmin() && !$this->login
->isStaff() && $this->login
->isGroupManager()) {
750 //check if current logged in user can manage loaded member
751 $groups = $member->groups
;
753 foreach ($groups as $group) {
754 if ($this->login
->isGroupManager($group->getId())) {
759 if ($can_manage !== true) {
761 'Logged in member ' . $this->login
->login
.
762 ' has tried to load member #' . $member->id
.
763 ' but do not manage any groups he belongs to.',
766 $member->load($this->login
->id
);
771 if ($member->id
!= $id) {
772 $member->load($this->login
->id
);
776 // flagging required fields
777 $fc = $this->fields_config
;
779 // password required if we create a new member
780 if ($member->id
!= '') {
781 $fc->setNotRequired('mdp_adh');
784 //handle requirements for parent fields
785 $parent_fields = $member->getParentFields();
786 foreach ($parent_fields as $key => $field) {
787 if ($fc->isRequired($field) && $member->hasParent()) {
788 $fc->setNotRequired($field);
789 } elseif (!$fc->isRequired($field)) {
790 unset($parent_fields[$key]);
793 $route_params['parent_fields'] = $parent_fields;
795 // flagging required fields invisible to members
796 if ($this->login
->isAdmin() ||
$this->login
->isStaff()) {
797 $fc->setNotRequired('activite_adh');
798 $fc->setNotRequired('id_statut');
801 // template variable declaration
802 $title = _T("Member Profile");
803 if ($member->id
!= '') {
804 $title .= ' (' . _T("modification") . ')';
806 $title .= ' (' . _T("creation") . ')';
810 $statuts = new Status($this->zdb
);
813 $groups = new Groups($this->zdb
, $this->login
);
814 $groups_list = $groups->getSimpleList(true);
816 $form_elements = $fc->getFormElements(
824 $required_fields = array(
829 $list_members = $m->getList(false, $required_fields, true);
831 if (count($list_members) > 0) {
832 foreach ($list_members as $lmember) {
834 $sname = mb_strtoupper($lmember->nom_adh
, 'UTF-8') .
835 ' ' . ucwords(mb_strtolower($lmember->prenom_adh
, 'UTF-8')) .
836 ' (' . $lmember->id_adh
. ')';
837 $members[$lmember->$pk] = $sname;
841 $route_params['members'] = [
842 'filters' => $m->getFilters(),
843 'count' => $m->getCount()
846 //check if current attached member is part of the list
847 if ($member->hasParent()) {
848 if (!isset($members[$member->parent
->id
])) {
850 [$member->parent
->id
=> $member->parent
->getSName()] +
856 if (count($members)) {
857 $route_params['members']['list'] = $members;
867 'parent_tpl' => 'page.tpl',
868 'require_dialog' => true,
869 'autocomplete' => true,
870 'page_title' => $title,
873 'require_calendar' => true,
876 'titles_list' => Titles
::getList($this->zdb
),
877 'statuts' => $statuts->getList(),
878 'groups' => $groups_list,
879 'fieldsets' => $form_elements['fieldsets'],
880 'hidden_elements' => $form_elements['hiddens']
888 )->add($authenticate)->add($navMiddleware);
891 '/member/store[/{self:subscribe}]',
892 function ($request, $response, $args) {
893 if (!$this->preferences
->pref_bool_selfsubscribe
&& !$this->login
->isLogged()) {
896 ->withHeader('Location', $this->router
->pathFor('slash'));
899 $post = $request->getParsedBody();
908 $member = new Adherent($this->zdb
, null, $deps);
909 $member->setDependencies(
911 $this->members_fields
,
914 if (isset($args['self'])) {
915 //mark as self membership
916 $member->setSelfMembership();
919 $success_detected = [];
920 $warning_detected = [];
921 $error_detected = [];
924 $adherent['id_adh'] = get_numeric_form_value('id_adh', '');
926 if ($this->login
->isAdmin() ||
$this->login
->isStaff() ||
$this->login
->isGroupManager()) {
927 if ($adherent['id_adh']) {
928 $member->load($adherent['id_adh']);
929 if (!$this->login
->isAdmin() && !$this->login
->isStaff() && $this->login
->isGroupManager()) {
930 //check if current logged in user can manage loaded member
931 $groups = $member->groups
;
933 foreach ($groups as $group) {
934 if ($this->login
->isGroupManager($group->getId())) {
939 if ($can_manage !== true) {
941 'Logged in member ' . $this->login
->login
.
942 ' has tried to load member #' . $member->id
.
943 ' but do not manage any groups he belongs to.',
946 $member->load($this->login
->id
);
951 $member->load($this->login
->id
);
952 $adherent['id_adh'] = $this->login
->id
;
955 // flagging required fields
956 $fc = $this->fields_config
;
958 // password required if we create a new member
959 if ($member->id
!= '') {
960 $fc->setNotRequired('mdp_adh');
963 if ($member->hasParent() && !isset($post['detach_parent'])
964 ||
isset($post['parent_id']) && !empty($post['parent_id'])
966 $parent_fields = $member->getParentFields();
967 foreach ($parent_fields as $field) {
968 if ($fc->isRequired($field)) {
969 $fc->setNotRequired($field);
974 // flagging required fields invisible to members
975 if ($this->login
->isAdmin() ||
$this->login
->isStaff()) {
976 $fc->setNotRequired('activite_adh');
977 $fc->setNotRequired('id_statut');
980 $form_elements = $fc->getFormElements(
985 $fieldsets = $form_elements['fieldsets'];
989 foreach ($fieldsets as $category) {
990 foreach ($category->elements
as $field) {
991 if ($field->required
== true) {
992 $required[$field->field_id
] = true;
994 if ($field->disabled
== true) {
995 $disabled[$field->field_id
] = true;
996 } elseif (!isset($post[$field->field_id
])) {
997 switch ($field->field_id
) {
998 //unchecked booleans are not sent from form
999 case 'bool_admin_adh':
1000 case 'bool_exempt_adh':
1001 case 'bool_display_info':
1002 $post[$field->field_id
] = 0;
1009 $real_requireds = array_diff(array_keys($required), array_keys($disabled));
1012 if (isset($post[array_shift($real_requireds)])) {
1014 $valid = $member->check($post, $required, $disabled);
1015 if ($valid !== true) {
1016 $error_detected = array_merge($error_detected, $valid);
1019 if (count($error_detected) == 0) {
1020 //all goes well, we can proceed
1023 if ($member->id
== '') {
1026 $store = $member->store();
1027 if ($store === true) {
1028 //member has been stored :)
1030 if (isset($args['self'])) {
1031 $success_detected[] = _T("Your account has been created!");
1032 if ($this->preferences
->pref_mail_method
> GaletteMail
::METHOD_DISABLED
1033 && $member->getEmail() != ''
1035 $success_detected[] = _T("An email has been sent to you, check your inbox.");
1038 $success_detected[] = _T("New member has been successfully added.");
1040 //Send email to admin if preference checked
1041 if ($this->preferences
->pref_mail_method
> GaletteMail
::METHOD_DISABLED
1042 && $this->preferences
->pref_bool_mailadh
1045 $this->texts_fields
,
1049 'name_adh' => custom_html_entity_decode(
1052 'firstname_adh' => custom_html_entity_decode(
1055 'lastname_adh' => custom_html_entity_decode(
1058 'mail_adh' => custom_html_entity_decode(
1061 'login_adh' => custom_html_entity_decode(
1066 $mtxt = $texts->getTexts(
1067 (isset($args['self']) ?
'newselfadh' : 'newadh'),
1068 $this->preferences
->pref_lang
1071 $mail = new GaletteMail($this->preferences
);
1072 $mail->setSubject($texts->getSubject());
1074 foreach ($this->preferences
->vpref_email_newadh
as $pref_email) {
1075 $recipients[$pref_email] = $pref_email;
1077 $mail->setRecipients($recipients);
1078 $mail->setMessage($texts->getBody());
1079 $sent = $mail->send();
1081 if ($sent == GaletteMail
::MAIL_SENT
) {
1082 $this->history
->add(
1085 $member->sname
. ' (' . $member->email
. ')',
1086 _T("New account mail sent to admin for '%s'.")
1092 $member->sname
. ' (' . $member->email
. ')',
1093 _T("A problem happened while sending email to admin for account '%s'.")
1095 $this->history
->add($str);
1096 $warning_detected[] = $str;
1101 $success_detected[] = _T("Member account has been modified.");
1104 // send mail to member
1105 if (isset($args['self']) ||
isset($post['mail_confirm']) && $post['mail_confirm'] == '1') {
1106 if ($this->preferences
->pref_mail_method
> GaletteMail
::METHOD_DISABLED
) {
1107 if ($member->getEmail() == '' && !isset($args['self'])) {
1108 $error_detected[] = _T("- You can't send a confirmation by email if the member hasn't got an address!");
1111 'name_adh' => custom_html_entity_decode(
1114 'firstname_adh' => custom_html_entity_decode(
1117 'lastname_adh' => custom_html_entity_decode(
1120 'mail_adh' => custom_html_entity_decode(
1123 'login_adh' => custom_html_entity_decode(
1128 $password = new Password($this->zdb
);
1129 $res = $password->generateNewPassword($member->id
);
1131 $link_validity = new DateTime();
1132 $link_validity->add(new DateInterval('PT24H'));
1133 $mreplaces['change_pass_uri'] = $this->preferences
->getURL() .
1134 $this->router
->pathFor(
1135 'password-recovery',
1136 ['hash' => base64_encode($password->getHash())]
1138 $mreplaces['link_validity'] = $link_validity->format(_T("Y-m-d H:i:s"));
1143 _T("An error occurred storing temporary password for %s. Please inform an admin.")
1145 $this->history
->add($str);
1146 $this->flash
->addMessage(
1153 //send mail to member
1154 // Get email text in database
1156 $this->texts_fields
,
1161 $mlang = $this->preferences
->pref_lang
;
1162 if (isset($post['pref_lang'])) {
1163 $mlang = $post['pref_lang'];
1165 $mtxt = $texts->getTexts(
1166 (($new) ?
'sub' : 'accountedited'),
1170 $mail = new GaletteMail($this->preferences
);
1171 $mail->setSubject($texts->getSubject());
1172 $mail->setRecipients(
1174 $member->getEmail() => $member->sname
1177 $mail->setMessage($texts->getBody());
1178 $sent = $mail->send();
1180 if ($sent == GaletteMail
::MAIL_SENT
) {
1183 $member->sname
. ' (' . $member->getEmail() . ')',
1185 _T("New account mail sent to '%s'.") :
1186 _T("Account modification mail sent to '%s'.")
1188 $this->history
->add($msg);
1189 $success_detected[] = $msg;
1193 $member->sname
. ' (' . $member->getEmail() . ')',
1194 _T("A problem happened while sending account mail to '%s'")
1196 $this->history
->add($str);
1197 $error_detected[] = $str;
1200 } elseif ($this->preferences
->pref_mail_method
== GaletteMail
::METHOD_DISABLED
) {
1201 //if mail has been disabled in the preferences, we should not be here ;
1202 //we do not throw an error, just a simple warning that will be show later
1203 $msg = _T("You asked Galette to send a confirmation mail to the member, but mail has been disabled in the preferences.");
1204 $warning_detected[] = $msg;
1208 // send mail to admin
1209 if ($this->preferences
->pref_mail_method
> GaletteMail
::METHOD_DISABLED
1210 && $this->preferences
->pref_bool_mailadh
1212 && $member->id
== $this->login
->id
1215 'name_adh' => custom_html_entity_decode(
1218 'firstname_adh' => custom_html_entity_decode(
1221 'lastname_adh' => custom_html_entity_decode(
1224 'mail_adh' => custom_html_entity_decode(
1227 'login_adh' => custom_html_entity_decode(
1232 //send mail to member
1233 // Get email text in database
1235 $this->texts_fields
,
1240 $mlang = $this->preferences
->pref_lang
;
1242 $mtxt = $texts->getTexts(
1247 $mail = new GaletteMail($this->preferences
);
1248 $mail->setSubject($texts->getSubject());
1250 foreach ($this->preferences
->vpref_email_newadh
as $pref_email) {
1251 $recipients[$pref_email] = $pref_email;
1253 $mail->setRecipients($recipients);
1255 $mail->setMessage($texts->getBody());
1256 $sent = $mail->send();
1258 if ($sent == GaletteMail
::MAIL_SENT
) {
1259 $msg = _T("Account modification mail sent to admin.");
1260 $this->history
->add($msg);
1261 $success_detected[] = $msg;
1263 $str = _T("A problem happened while sending account mail to admin");
1264 $this->history
->add($str);
1265 $error_detected[] = $str;
1269 //store requested groups
1272 $managed_groups_adh = null;
1274 //add/remove user from groups
1275 if (isset($post['groups_adh'])) {
1276 $groups_adh = $post['groups_adh'];
1278 $add_groups = Groups
::addMemberToGroups(
1283 if ($add_groups === false) {
1284 $error_detected[] = _T("An error occurred adding member to its groups.");
1287 //add/remove manager from groups
1288 if (isset($post['groups_managed_adh'])) {
1289 $managed_groups_adh = $post['groups_managed_adh'];
1291 $add_groups = Groups
::addMemberToGroups(
1293 $managed_groups_adh,
1296 $member->loadGroups();
1298 if ($add_groups === false) {
1299 $error_detected[] = _T("An error occurred adding member to its groups as manager.");
1302 //something went wrong :'(
1303 $error_detected[] = _T("An error occurred while storing the member.");
1307 if (count($error_detected) == 0) {
1308 $files_res = $member->handleFiles($_FILES);
1309 if (is_array($files_res)) {
1310 $error_detected = array_merge($error_detected, $files_res);
1313 if (isset($post['del_photo'])) {
1314 if (!$member->picture
->delete($member->id
)) {
1315 $error_detected[] = _T("Delete failed");
1316 $str_adh = $member->id
. ' (' . $member->sname
. ' ' . ')';
1318 'Unable to delete picture for member ' . $str_adh,
1325 if (count($error_detected) > 0) {
1326 foreach ($error_detected as $error) {
1327 if (strpos($error, '%member_url_') !== false) {
1328 preg_match('/%member_url_(\d+)/', $error, $matches);
1329 $url = $this->router
->pathFor('member', ['id' => $matches[1]]);
1330 $error = str_replace(
1331 '%member_url_' . $matches[1],
1336 $this->flash
->addMessage(
1343 if (count($warning_detected) > 0) {
1344 foreach ($warning_detected as $warning) {
1345 $this->flash
->addMessage(
1351 if (count($success_detected) > 0) {
1352 foreach ($success_detected as $success) {
1353 $this->flash
->addMessage(
1360 if (count($error_detected) == 0) {
1361 $redirect_url = null;
1362 if (isset($args['self'])) {
1363 $redirect_url = $this->router
->pathFor('login');
1364 } elseif (isset($post['redirect_on_create'])
1365 && $post['redirect_on_create'] > Adherent
::AFTER_ADD_DEFAULT
1367 switch ($post['redirect_on_create']) {
1368 case Adherent
::AFTER_ADD_TRANS
:
1369 $redirect_url = $this->router
->pathFor('transaction', ['action' => 'add']);
1371 case Adherent
::AFTER_ADD_NEW
:
1372 $redirect_url = $this->router
->pathFor('editmember', ['action' => 'add']);
1374 case Adherent
::AFTER_ADD_SHOW
:
1375 $redirect_url = $this->router
->pathFor('member', ['id' => $member->id
]);
1377 case Adherent
::AFTER_ADD_LIST
:
1378 $redirect_url = $this->router
->pathFor('members');
1380 case Adherent
::AFTER_ADD_HOME
:
1381 $redirect_url = $this->router
->pathFor('slash');
1384 } elseif (!isset($post['id_adh']) && !$member->isDueFree()) {
1385 $redirect_url = $this->router
->pathFor(
1391 ) . '?id_adh=' . $member->id
;
1393 $redirect_url = $this->router
->pathFor('member', ['id' => $member->id
]);
1398 ->withHeader('Location', $redirect_url);
1400 //store entity in session
1401 $this->session
->member
= $member;
1403 if (isset($args['self'])) {
1404 $redirect_url = $this->router
->pathFor('subscribe');
1408 'id' => $member->id
,
1412 $rparams = ['action' => 'add'];
1414 $redirect_url = $this->router
->pathFor(
1422 ->withHeader('Location', $redirect_url);
1426 )->setName('storemembers');
1429 '/member/remove/{id:\d+}',
1430 function ($request, $response, $args) {
1431 $adh = new Adherent($this->zdb
, (int)$args['id']);
1434 'id' => $args['id'],
1435 'redirect_uri' => $this->router
->pathFor('members')
1439 $this->view
->render(
1441 'confirm_removal.tpl',
1443 'type' => _T("Member"),
1444 'mode' => $request->isXhr() ?
'ajax' : '',
1445 'page_title' => sprintf(
1446 _T('Remove member %1$s'),
1449 'form_url' => $this->router
->pathFor('doRemoveMember', ['id' => $adh->id
]),
1450 'cancel_uri' => $this->router
->pathFor('members'),
1456 )->setName('removeMember')->add($authenticate);
1460 function ($request, $response) {
1461 $filters = $this->session
->filter_members
;
1464 'id' => $filters->selected
,
1465 'redirect_uri' => $this->router
->pathFor('members')
1469 $this->view
->render(
1471 'confirm_removal.tpl',
1473 'type' => _T("Member"),
1474 'mode' => $request->isXhr() ?
'ajax' : '',
1475 'page_title' => _T('Remove members'),
1476 'message' => str_replace(
1479 _T('You are about to remove %count members.')
1481 'form_url' => $this->router
->pathFor('doRemoveMember'),
1482 'cancel_uri' => $this->router
->pathFor('members'),
1488 )->setName('removeMembers')->add($authenticate);
1491 '/member/remove' . '[/{id:\d+}]',
1492 function ($request, $response) {
1493 $post = $request->getParsedBody();
1494 $ajax = isset($post['ajax']) && $post['ajax'] === 'true';
1497 $uri = isset($post['redirect_uri']) ?
1498 $post['redirect_uri'] :
1499 $this->router
->pathFor('slash');
1501 if (!isset($post['confirm'])) {
1502 $this->flash
->addMessage(
1504 _T("Removal has not been confirmed!")
1507 if (isset($this->session
->filter_members
)) {
1508 $filters = $this->session
->filter_members
;
1510 $filters = new MembersList();
1512 $members = new Members($filters);
1514 if (!is_array($post['id'])) {
1516 $adh = new Adherent($this->zdb
, (int)$post['id']);
1517 $ids = (array)$post['id'];
1522 $del = $members->removeMembers($ids);
1524 if ($del !== true) {
1525 if (count($ids) === 1) {
1526 $error_detected = str_replace(
1529 _T("An error occurred trying to remove member %name :/")
1532 $error_detected = _T("An error occurred trying to remove members :/");
1535 $this->flash
->addMessage(
1540 if (!is_array($post['id'])) {
1541 $success_detected = str_replace(
1544 _T("Member %name has been successfully deleted.")
1547 $success_detected = str_replace(
1550 _T("%count members have been successfully deleted.")
1554 $this->flash
->addMessage(
1566 ->withHeader('Location', $uri);
1568 return $response->withJson(
1570 'success' => $success
1575 )->setName('doRemoveMember')->add($authenticate);
1577 //advanced search page
1580 function ($request, $response) {
1581 if (isset($this->session
->filter_members
)) {
1582 $filters = $this->session
->filter_members
;
1583 if (!$filters instanceof AdvancedMembersList
) {
1584 $filters = new AdvancedMembersList($filters);
1587 $filters = new AdvancedMembersList();
1590 $groups = new Groups($this->zdb
, $this->login
);
1591 $groups_list = $groups->getList();
1593 //we want only visibles fields
1594 $fields = $this->members_fields
;
1595 $fc = $this->fields_config
;
1596 $visibles = $fc->getVisibilities();
1597 $access_level = $this->login
->getAccessLevel();
1599 //remove not searchable fields
1600 unset($fields['mdp_adh']);
1602 foreach ($fields as $k => $f) {
1603 if ($visibles[$k] == FieldsConfig
::NOBODY ||
1604 ($visibles[$k] == FieldsConfig
::ADMIN
&&
1605 $access_level < Authentication
::ACCESS_ADMIN
) ||
1606 ($visibles[$k] == FieldsConfig
::STAFF
&&
1607 $access_level < Authentication
::ACCESS_STAFF
) ||
1608 ($visibles[$k] == FieldsConfig
::MANAGER
&&
1609 $access_level < Authentication
::ACCESS_MANAGER
)
1615 //add status label search
1616 if ($pos = array_search(Status
::PK
, array_keys($fields))) {
1617 $fields = array_slice($fields, 0, $pos, true) +
1618 ['status_label' => ['label' => _T('Status label')]] +
1619 array_slice($fields, $pos, count($fields) -1, true);
1628 'children' => false,
1631 $member = new Adherent($this->zdb
, $this->login
->login
, $deps);
1632 $adh_dynamics = new DynamicFieldsHandle($this->zdb
, $this->login
, $member);
1634 $contrib = new Contribution($this->zdb
, $this->login
);
1635 $contrib_dynamics = new DynamicFieldsHandle($this->zdb
, $this->login
, $contrib);
1638 $statuts = new Status($this->zdb
);
1640 //Contributions types
1641 $ct = new Galette\Entity\
ContributionsTypes($this->zdb
);
1644 $ptypes = new PaymentTypes(
1649 $ptlist = $ptypes->getList();
1651 $filters->setViewCommonsFilters($this->preferences
, $this->view
->getSmarty());
1654 $this->view
->render(
1656 'advanced_search.tpl',
1658 'page_title' => _T("Advanced search"),
1659 'require_dialog' => true,
1660 'require_calendar' => true,
1661 'require_sorter' => true,
1662 'filter_groups_options' => $groups_list,
1663 'search_fields' => $fields,
1664 'adh_dynamics' => $adh_dynamics->getFields(),
1665 'contrib_dynamics' => $contrib_dynamics->getFields(),
1666 'statuts' => $statuts->getList(),
1667 'contributions_types' => $ct->getList(),
1668 'filters' => $filters,
1669 'payments_types' => $ptlist
1674 )->setName('advanced-search')->add($authenticate);
1676 //Batch actions on members list
1679 function ($request, $response) {
1680 $post = $request->getParsedBody();
1682 if (isset($post['member_sel'])) {
1683 if (isset($this->session
->filter_members
)) {
1684 $filters = $this->session
->filter_members
;
1686 $filters = new MembersList();
1689 $filters->selected
= $post['member_sel'];
1690 $this->session
->filter_members
= $filters;
1692 if (isset($post['cards'])) {
1695 ->withHeader('Location', $this->router
->pathFor('pdf-members-cards'));
1698 if (isset($post['labels'])) {
1701 ->withHeader('Location', $this->router
->pathFor('pdf-members-labels'));
1704 if (isset($post['mailing'])) {
1707 ->withHeader('Location', $this->router
->pathFor('mailing') . '?new=new');
1710 if (isset($post['attendance_sheet'])) {
1713 ->withHeader('Location', $this->router
->pathFor('attendance_sheet_details'));
1716 if (isset($post['csv'])) {
1719 ->withHeader('Location', $this->router
->pathFor('csv-memberslist'));
1722 if (isset($post['delete'])) {
1725 ->withHeader('Location', $this->router
->pathFor('removeMembers'));
1728 if (isset($post['masschange'])) {
1731 ->withHeader('Location', $this->router
->pathFor('masschangeMembers'));
1734 throw new \
RuntimeException('Does not know what to batch :(');
1736 $this->flash
->addMessage(
1738 _T("No member was selected, please check at least one name.")
1743 ->withHeader('Location', $this->router
->pathFor('members'));
1746 )->setName('batch-memberslist')->add($authenticate);
1750 '/members/cards[/{' . Adherent
::PK
. ':\d+}]',
1751 function ($request, $response, $args) {
1752 if ($this->session
->filter_members
) {
1753 $filters = $this->session
->filter_members
;
1755 $filters = new MembersList();
1758 if (isset($args[Adherent
::PK
])
1759 && $args[Adherent
::PK
] > 0
1761 $id_adh = $args[Adherent
::PK
];
1763 if ($this->login
->id
!= $id_adh
1764 && !$this->login
->isAdmin()
1765 && !$this->login
->isStaff()
1766 && !$this->login
->isGroupManager()
1771 if (!$this->login
->isAdmin() && !$this->login
->isStaff() && $this->login
->id
!= $id_adh) {
1772 if ($this->login
->isGroupManager()) {
1773 $adh = new Adherent($this->zdb
, $id_adh, ['dynamics' => true]);
1774 //check if current logged in user can manage loaded member
1775 $groups = $adh->groups
;
1776 $can_manage = false;
1777 foreach ($groups as $group) {
1778 if ($this->login
->isGroupManager($group->getId())) {
1783 if ($can_manage !== true) {
1785 'Logged in member ' . $this->login
->login
.
1786 ' has tried to load member #' . $adh->id
.
1787 ' but do not manage any groups he belongs to.',
1798 //requested member cannot be managed. Load logged in user
1799 $id_adh = (int)$this->login
->id
;
1802 //check if member is up to date
1803 if ($this->login
->id
== $id_adh) {
1804 $adh = new Adherent($this->zdb
, (int)$id_adh, ['dues' => true]);
1805 if (!$adh->isUp2Date()) {
1807 'Member ' . $id_adh . ' is not up to date; cannot get his PDF member card',
1812 ->withHeader('Location', $this->router
->pathFor('slash'));
1816 // If we are called from a member's card, get unique id value
1819 if (count($filters->selected
) == 0) {
1821 'No member selected to generate members cards',
1824 $this->flash
->addMessage(
1826 _T("No member was selected, please check at least one name.")
1831 ->withHeader('Location', $this->router
->pathFor('members'));
1835 // Fill array $selected with selected ids
1836 $selected = array();
1837 if (isset($unique) && $unique) {
1838 $selected[] = $unique;
1840 $selected = $filters->selected
;
1844 $members = $m->getArrayList(
1846 array('nom_adh', 'prenom_adh'),
1850 if (!is_array($members) ||
count($members) < 1) {
1852 'An error has occurred, unable to get members list.',
1856 $this->flash
->addMessage(
1858 _T("Unable to get members list.")
1863 ->withHeader('Location', $this->router
->pathFor('members'));
1866 $pdf = new PdfMembersCards($this->preferences
);
1867 $pdf->drawCards($members);
1869 $response = $this->response
->withHeader('Content-type', 'application/pdf')
1870 ->withHeader('Content-Disposition', 'attachment;filename="' . $pdf->getFileName() . '"');
1871 $response->write($pdf->download());
1874 )->setName('pdf-members-cards')->add($authenticate);
1876 //PDF members labels
1879 function ($request, $response) {
1880 $get = $request->getQueryParams();
1882 if ($this->session
->filter_reminders_labels
) {
1883 $filters = $this->session
->filter_reminders_labels
;
1884 unset($this->session
->filter_reminders_labels
);
1885 } elseif ($this->session
->filter_members
) {
1886 $filters = $this->session
->filter_members
;
1888 $filters = new MembersList();
1892 if (isset($get['from'])
1893 && $get['from'] === 'mailing'
1895 //if we're from mailing, we have to retrieve
1896 //its unreachables members for labels
1897 $mailing = $this->session
->mailing
;
1898 $members = $mailing->unreachables
;
1900 if (count($filters->selected
) == 0) {
1901 Analog
::log('No member selected to generate labels', Analog
::INFO
);
1902 $this->flash
->addMessage(
1904 _T("No member was selected, please check at least one name.")
1909 ->withHeader('Location', $this->router
->pathFor('members'));
1913 $members = $m->getArrayList(
1915 array('nom_adh', 'prenom_adh')
1919 if (!is_array($members) ||
count($members) < 1) {
1921 'An error has occurred, unable to get members list.',
1925 $this->flash
->addMessage(
1927 _T("Unable to get members list.")
1932 ->withHeader('Location', $this->router
->pathFor('members'));
1935 $pdf = new PdfMembersLabels($this->preferences
);
1936 $pdf->drawLabels($members);
1937 $response = $this->response
->withHeader('Content-type', 'application/pdf')
1938 ->withHeader('Content-Disposition', 'attachment;filename="' . $pdf->getFileName() . '"');
1939 $response->write($pdf->download());
1942 )->setName('pdf-members-labels')->add($authenticate);
1946 '/members/adhesion-form/{' . Adherent
::PK
. ':\d+}',
1947 function ($request, $response, $args) {
1948 $id_adh = (int)$args[Adherent
::PK
];
1951 if ($this->login
->id
!= $args['id']
1952 && !$this->login
->isAdmin()
1953 && !$this->login
->isStaff()
1954 && !$this->login
->isGroupManager()
1959 if (!$this->login
->isAdmin() && !$this->login
->isStaff() && $this->login
->id
!= $args['id']) {
1960 if ($this->login
->isGroupManager()) {
1961 $adh = new Adherent($this->zdb
, $id_adh, ['dynamics' => true]);
1962 //check if current logged in user can manage loaded member
1963 $groups = $adh->groups
;
1964 $can_manage = false;
1965 foreach ($groups as $group) {
1966 if ($this->login
->isGroupManager($group->getId())) {
1971 if ($can_manage !== true) {
1973 'Logged in member ' . $this->login
->login
.
1974 ' has tried to load member #' . $adh->id
.
1975 ' but do not manage any groups he belongs to.',
1986 //requested member cannot be managed. Load logged in user
1987 $id_adh = (int)$this->login
->id
;
1989 $adh = new Adherent($this->zdb
, $id_adh, ['dynamics' => true]);
1991 $form = $this->preferences
->pref_adhesion_form
;
1992 $pdf = new $form($adh, $this->zdb
, $this->preferences
);
1993 $response = $this->response
->withHeader('Content-type', 'application/pdf')
1994 ->withHeader('Content-Disposition', 'attachment; filename="' . $pdf->getFileName() . '"');
1995 $response->write($pdf->download());
1998 )->setName('adhesionForm')->add($authenticate);
2000 //Empty PDF adhesion form
2002 '/members/empty-adhesion-form',
2003 function ($request, $response) {
2004 $form = $this->preferences
->pref_adhesion_form
;
2005 $pdf = new $form(null, $this->zdb
, $this->preferences
);
2006 $response = $this->response
->withHeader('Content-type', 'application/pdf')
2007 ->withHeader('Content-Disposition', 'attachment; filename="' . $pdf->getFileName() . '"');
2008 $response->write($pdf->download());
2011 )->setName('emptyAdhesionForm');
2016 function ($request, $response) {
2017 $get = $request->getQueryParams();
2020 if (isset($get['mailing_new'])
2021 ||
isset($get['reminder'])
2023 if ($this->session
->mailing
!== null) {
2024 // check for temporary attachments to remove
2025 $m = $this->session
->mailing
;
2026 $m->removeAttachments(true);
2028 $this->session
->mailing
= null;
2033 if ($this->preferences
->pref_mail_method
== Mailing
::METHOD_DISABLED
2034 && !GALETTE_MODE
=== 'DEMO'
2036 $this->history
->add(
2037 _T("Trying to load mailing while mail is disabled in preferences.")
2039 $this->flash
->addMessage(
2041 _T("Trying to load mailing while mail is disabled in preferences.")
2045 ->withHeader('Location', $this->router
->pathFor('slash'));
2047 if (isset($this->session
->filter_mailing
)) {
2048 $filters = $this->session
->filter_mailing
;
2049 } elseif (isset($this->session
->filter_members
)) {
2050 $filters = $this->session
->filter_members
;
2052 $filters = new MembersList();
2055 if ($this->session
->mailing
!== null
2056 && !isset($get['from'])
2057 && !isset($get['reset'])
2059 $mailing = $this->session
->mailing
;
2060 } elseif (isset($get['from']) && is_numeric($get['from'])) {
2061 $mailing = new Mailing($this->preferences
, null, $get['from']);
2062 MailingHistory
::loadFrom($this->zdb
, (int)$get['from'], $mailing);
2063 } elseif (isset($get['reminder'])) {
2064 //FIXME: use a constant!
2066 $filters->membership_filter
= Members
::MEMBERSHIP_LATE
;
2067 $filters->filter_account
= Members
::ACTIVE_ACCOUNT
;
2068 $m = new Members($filters);
2069 $members = $m->getList(true);
2070 $mailing = new Mailing($this->preferences
, ($members !== false) ?
$members : null);
2072 if (count($filters->selected
) == 0
2073 && !isset($get['mailing_new'])
2074 && !isset($get['reminder'])
2077 '[Mailings] No member selected for mailing',
2081 $this->flash
->addMessage(
2083 _T('No member selected for mailing!')
2086 if (isset($profiler)) {
2090 $redirect_url = ($this->session
->redirect_mailing
!== null) ?
2091 $this->session
->redirect_mailing
:
2092 $this->router
->pathFor('members');
2096 ->withHeader('Location', $redirect_url);
2099 $members = $m->getArrayList($filters->selected
);
2100 $mailing = new Mailing($this->preferences
, ($members !== false) ?
$members : null);
2103 if (isset($get['remove_attachment'])) {
2104 $mailing->removeAttachment($get['remove_attachment']);
2107 if ($mailing->current_step
!== Mailing
::STEP_SENT
) {
2108 $this->session
->mailing
= $mailing;
2111 /** TODO: replace that... */
2112 $this->session
->labels
= $mailing->unreachables
;
2114 if (!$this->login
->isSuperAdmin()) {
2115 $member = new Adherent($this->zdb
, (int)$this->login
->id
, false);
2116 $params['sender_current'] = [
2117 'name' => $member->sname
,
2118 'email' => $member->getEmail()
2122 $params = array_merge(
2125 'mailing' => $mailing,
2126 'attachments' => $mailing->attachments
,
2127 'html_editor' => true,
2128 'html_editor_active'=> $this->preferences
->pref_editor_enabled
2134 $this->view
->render(
2136 'mailing_adherents.tpl',
2139 'page_title' => _T("Mailing"),
2140 'require_dialog' => true
2147 )->setName('mailing')->add($authenticate);
2151 function ($request, $response) {
2152 $post = $request->getParsedBody();
2153 $error_detected = [];
2154 $success_detected = [];
2156 $goto = $this->router
->pathFor('mailings');
2157 $redirect_url = ($this->session
->redirect_mailing
!== null) ?
2158 $this->session
->redirect_mailing
:
2159 $this->router
->pathFor('members');
2162 if (isset($post['mailing_done'])
2163 ||
isset($post['mailing_cancel'])
2165 if ($this->session
->mailing
!== null) {
2166 // check for temporary attachments to remove
2167 $m = $this->session
->mailing
;
2168 $m->removeAttachments(true);
2170 $this->session
->mailing
= null;
2171 if (isset($this->session
->filter_mailing
)) {
2172 $filters = $this->session
->filter_mailing
;
2173 $filters->selected
= [];
2174 $this->session
->filter_mailing
= $filters;
2179 ->withHeader('Location', $redirect_url);
2184 if ($this->preferences
->pref_mail_method
== Mailing
::METHOD_DISABLED
2185 && !GALETTE_MODE
=== 'DEMO'
2187 $this->history
->add(
2188 _T("Trying to load mailing while mail is disabled in preferences.")
2190 $error_detected[] = _T("Trying to load mailing while mail is disabled in preferences.");
2191 $goto = $this->router
->pathFor('slash');
2193 if (isset($this->session
->filter_members
)) {
2194 $filters = $this->session
->filter_members
;
2196 $filters = new MembersList();
2199 if ($this->session
->mailing
!== null
2200 && !isset($post['mailing_cancel'])
2202 $mailing = $this->session
->mailing
;
2204 if (count($filters->selected
) == 0) {
2206 '[Mailings] No member selected for mailing',
2210 $this->flash
->addMessage(
2212 _T('No member selected for mailing!')
2217 ->withHeader('Location', $redirect_url);
2220 $members = $m->getArrayList($filters->selected
);
2221 $mailing = new Mailing($this->preferences
, ($members !== false) ?
$members : null);
2224 if (isset($post['mailing_go'])
2225 ||
isset($post['mailing_reset'])
2226 ||
isset($post['mailing_confirm'])
2227 ||
isset($post['mailing_save'])
2229 if (trim($post['mailing_objet']) == '') {
2230 $error_detected[] = _T("Please type an object for the message.");
2232 $mailing->subject
= $post['mailing_objet'];
2235 if (trim($post['mailing_corps']) == '') {
2236 $error_detected[] = _T("Please enter a message.");
2238 $mailing->message
= $post['mailing_corps'];
2241 switch ($post['sender']) {
2242 case GaletteMail
::SENDER_CURRENT
:
2243 $member = new Adherent($this->zdb
, (int)$this->login
->id
, false);
2244 $mailing->setSender(
2249 case GaletteMail
::SENDER_OTHER
:
2250 $mailing->setSender(
2251 $post['sender_name'],
2252 $post['sender_address']
2255 case GaletteMail
::SENDER_PREFS
:
2257 //nothing to do; this is the default :)
2261 $mailing->html
= (isset($post['mailing_html'])) ?
true : false;
2263 //handle attachments
2264 if (isset($_FILES['files'])) {
2265 for ($i = 0; $i < count($_FILES['files']['name']); $i++
) {
2266 if ($_FILES['files']['error'][$i] === UPLOAD_ERR_OK
) {
2267 if ($_FILES['files']['tmp_name'][$i] != '') {
2268 if (is_uploaded_file($_FILES['files']['tmp_name'][$i])) {
2270 foreach (array_keys($_FILES['files']) as $key) {
2271 $da_file[$key] = $_FILES['files'][$key][$i];
2273 $res = $mailing->store($da_file);
2275 //what to do if one of attachments fail? should other be removed?
2276 $error_detected[] = $mailing->getAttachmentErrorMessage($res);
2280 } elseif ($_FILES['files']['error'][$i] !== UPLOAD_ERR_NO_FILE
) {
2282 $this->logo
->getPhpErrorMessage($_FILES['files']['error'][$i]),
2285 $error_detected[] = $this->logo
->getPhpErrorMessage(
2286 $_FILES['files']['error'][$i]
2292 if (count($error_detected) == 0
2293 && !isset($post['mailing_reset'])
2294 && !isset($post['mailing_save'])
2296 $mailing->current_step
= Mailing
::STEP_PREVIEW
;
2298 $mailing->current_step
= Mailing
::STEP_START
;
2302 if (isset($post['mailing_confirm']) && count($error_detected) == 0) {
2303 $mailing->current_step
= Mailing
::STEP_SEND
;
2304 //ok... let's go for fun
2305 $sent = $mailing->send();
2306 if ($sent == Mailing
::MAIL_ERROR
) {
2307 $mailing->current_step
= Mailing
::STEP_START
;
2309 '[Mailings] Message was not sent. Errors: ' .
2310 print_r($mailing->errors
, true),
2313 foreach ($mailing->errors
as $e) {
2314 $error_detected[] = $e;
2317 $mlh = new MailingHistory($this->zdb
, $this->login
, null, $mailing);
2318 $mlh->storeMailing(true);
2320 '[Mailings] Message has been sent.',
2323 $mailing->current_step
= Mailing
::STEP_SENT
;
2325 $filters->selected
= null;
2326 $this->session
->filter_members
= $filters;
2327 $this->session
->mailing
= null;
2328 $success_detected[] = _T("Mailing has been successfully sent!");
2329 $goto = $redirect_url;
2333 if ($mailing->current_step
!== Mailing
::STEP_SENT
) {
2334 $this->session
->mailing
= $mailing;
2337 /** TODO: replace that... */
2338 $this->session
->labels
= $mailing->unreachables
;
2340 if (!isset($post['html_editor_active'])
2341 ||
trim($post['html_editor_active']) == ''
2343 $post['html_editor_active'] = $this->preferences
->pref_editor_enabled
;
2346 if (isset($post['mailing_save'])) {
2347 //user requested to save the mailing
2348 $histo = new MailingHistory($this->zdb
, $this->login
, null, $mailing);
2349 if ($histo->storeMailing() !== false) {
2350 $success_detected[] = _T("Mailing has been successfully saved.");
2351 $this->session
->mailing
= null;
2356 //flash messages if any
2357 if (count($error_detected) > 0) {
2358 foreach ($error_detected as $error) {
2359 $this->flash
->addMessage('error_detected', $error);
2362 if (count($success_detected) > 0) {
2363 foreach ($success_detected as $success) {
2364 $this->flash
->addMessage('success_detected', $success);
2370 ->withHeader('Location', $goto);
2372 )->setName('doMailing')->add($authenticate);
2376 '/mailing/preview[/{id:\d+}]',
2377 function ($request, $response, $args) {
2378 $post = $request->getParsedBody();
2379 // check for ajax mode
2381 if ($request->isXhr()
2382 ||
isset($post['ajax'])
2383 && $post['ajax'] == 'true'
2389 if (isset($args['id'])) {
2390 $mailing = new Mailing($this->preferences
, null);
2391 MailingHistory
::loadFrom($this->zdb
, (int)$args['id'], $mailing, false);
2392 $attachments = $mailing->attachments
;
2394 $mailing = $this->session
->mailing
;
2396 switch ($post['sender']) {
2397 case GaletteMail
::SENDER_CURRENT
:
2398 $member = new Adherent($this->zdb
, (int)$this->login
->id
, false);
2399 $mailing->setSender(
2404 case GaletteMail
::SENDER_OTHER
:
2405 $mailing->setSender(
2406 $post['sender_name'],
2407 $post['sender_address']
2410 case GaletteMail
::SENDER_PREFS
:
2412 //nothing to do; this is the default :)
2416 $mailing->subject
= $post['subject'];
2417 $mailing->message
= $post['body'];
2418 $mailing->html
= ($post['html'] === 'true');
2419 $attachments = (isset($post['attachments']) ?
$post['attachments'] : []);
2423 $this->view
->render(
2425 'mailing_preview.tpl',
2427 'page_title' => _T("Mailing preview"),
2428 'mailing_id' => $args['id'],
2429 'mode' => ($ajax ?
'ajax' : ''),
2430 'mailing' => $mailing,
2431 'recipients' => $mailing->recipients
,
2432 'sender' => $mailing->getSenderName() . ' <' .
2433 $mailing->getSenderAddress() . '>',
2434 'attachments' => $attachments
2440 )->setName('mailingPreview')->add($authenticate);
2443 '/mailing/preview/{id:\d+}/attachment/{pos:\d+}',
2444 function ($request, $response, $args) {
2445 $mailing = new Mailing($this->preferences
, null);
2446 MailingHistory
::loadFrom($this->zdb
, (int)$args['id'], $mailing, false);
2447 $attachments = $mailing->attachments
;
2448 $attachment = $attachments[$args['pos']];
2449 $filepath = $attachment->getDestDir() . $attachment->getFileName();
2452 $ext = pathinfo($attachment->getFileName())['extension'];
2453 $response = $response->withHeader('Content-type', $attachment->getMimeType($filepath));
2455 $body = $response->getBody();
2456 $body->write(file_get_contents($filepath));
2459 )->setName('previewAttachment')->add($authenticate);
2462 '/ajax/mailing/set-recipients',
2463 function ($request, $response, $args) {
2464 $post = $request->getParsedBody();
2465 $mailing = $this->session
->mailing
;
2469 $members = $m->getArrayList(
2470 $post['recipients'],
2479 $mailing->setRecipients($members);
2481 $this->session
->mailing
= $mailing;
2484 $this->view
->render(
2486 'mailing_recipients.tpl',
2488 'mailing' => $mailing
2494 )->setName('mailingRecipients')->add($authenticate);
2499 function ($request, $response) {
2500 $texts = new Texts($this->texts_fields
, $this->preferences
, $this->router
);
2503 'impending' => $texts->getTexts('impendingduedate', $this->preferences
->pref_lang
),
2504 'late' => $texts->getTexts('lateduedate', $this->preferences
->pref_lang
)
2507 $members = new Members();
2508 $reminders = $members->getRemindersCount();
2511 $this->view
->render(
2515 'page_title' => _T("Reminders"),
2516 'previews' => $previews,
2517 'require_dialog' => true,
2518 'count_impending' => $reminders['impending'],
2519 'count_impending_nomail' => $reminders['nomail']['impending'],
2520 'count_late' => $reminders['late'],
2521 'count_late_nomail' => $reminders['nomail']['late']
2526 )->setName('reminders')->add($authenticate);
2530 function ($request, $response) {
2531 $error_detected = [];
2532 $warning_detected = [];
2533 $success_detected = [];
2535 $post = $request->getParsedBody();
2536 $texts = new Texts($this->texts_fields
, $this->preferences
, $this->router
);
2538 if (isset($post['reminders'])) {
2539 $selected = $post['reminders'];
2541 $reminders = new Reminders($selected);
2544 $labels_members = array();
2545 if (isset($post['reminder_wo_mail'])) {
2549 $list_reminders = $reminders->getList($this->zdb
, $labels);
2550 if (count($list_reminders) == 0) {
2551 $warning_detected[] = _T("No reminder to send for now.");
2553 foreach ($list_reminders as $reminder) {
2554 if ($labels === false) {
2555 //send reminders by mail
2556 $sent = $reminder->send($texts, $this->history
, $this->zdb
);
2558 if ($sent === true) {
2559 $success_detected[] = $reminder->getMessage();
2561 $error_detected[] = $reminder->getMessage();
2564 //generate labels for members without mail address
2565 $labels_members[] = $reminder->member_id
;
2569 if ($labels === true) {
2570 if (count($labels_members) > 0) {
2571 $labels_filters = new MembersList();
2572 $labels_filters->selected
= $labels_members;
2573 $this->session
->filters_reminders_labels
= $labels_filters;
2576 ->withHeader('Location', $this->router
->pathFor('pdf-member-labels'));
2578 $error_detected[] = _T("There are no member to proceed.");
2582 if (count($error_detected) > 0) {
2585 _T("Reminder has not been sent:")
2589 if (count($success_detected) > 0) {
2592 _T("Sent reminders:")
2597 //flash messages if any
2598 if (count($error_detected) > 0) {
2599 foreach ($error_detected as $error) {
2600 $this->flash
->addMessage('error_detected', $error);
2603 if (count($warning_detected) > 0) {
2604 foreach ($warning_detected as $warning) {
2605 $this->flash
->addMessage('warning_detected', $warning);
2608 if (count($success_detected) > 0) {
2609 foreach ($success_detected as $success) {
2610 $this->flash
->addMessage('success_detected', $success);
2616 ->withHeader('Location', $this->router
->pathFor('reminders'));
2618 )->setName('doReminders')->add($authenticate);
2621 '/members/reminder-filter/{membership:nearly|late}/{mail:withmail|withoutmail}',
2622 function ($request, $response, $args) {
2623 //always reset filters
2624 $filters = new MembersList();
2625 $filters->filter_account
= Members
::ACTIVE_ACCOUNT
;
2627 $membership = ($args['membership'] === 'nearly' ?
2628 Members
::MEMBERSHIP_NEARLY
:
2629 Members
::MEMBERSHIP_LATE
);
2630 $filters->membership_filter
= $membership;
2632 //TODO: filter on reminder may take care of parent email as well
2633 $mail = ($args['mail'] === 'withmail' ?
2634 Members
::FILTER_W_EMAIL
:
2635 Members
::FILTER_WO_EMAIL
);
2636 $filters->email_filter
= $mail;
2638 $this->session
->filter_members
= $filters;
2642 ->withHeader('Location', $this->router
->pathFor('members'));
2644 )->setName('reminders-filter')->add($authenticate);
2648 '/attendance-sheet/details',
2649 function ($request, $response) {
2650 $post = $request->getParsedBody();
2652 if ($this->session
->filter_members
!== null) {
2653 $filters = $this->session
->filter_members
;
2655 $filters = new MembersList();
2658 // check for ajax mode
2660 if ($request->isXhr()
2661 ||
isset($post['ajax'])
2662 && $post['ajax'] == 'true'
2666 //retrieve selected members
2667 $selection = (isset($post['selection']) ) ?
$post['selection'] : array();
2669 $filters->selected
= $selection;
2670 $this->session
->filter_members
= $filters;
2672 $selection = $filters->selected
;
2677 $this->view
->render(
2679 'attendance_sheet_details.tpl',
2681 'page_title' => _T("Attendance sheet configuration"),
2683 'selection' => $selection
2688 )->setName('attendance_sheet_details')->add($authenticate);
2691 '/attendance-sheet',
2692 function ($request, $response) {
2693 $post = $request->getParsedBody();
2695 if ($this->session
->filter_members
!== null) {
2696 $filters = $this->session
->filter_members
;
2698 $filters = new MembersList();
2701 //retrieve selected members
2702 $selection = (isset($post['selection']) ) ?
$post['selection'] : array();
2704 $filters->selected
= $selection;
2705 $this->session
->filter_members
= $filters;
2707 if (count($filters->selected
) == 0) {
2708 Analog
::log('No member selected to generate attendance sheet', Analog
::INFO
);
2709 $this->flash
->addMessage(
2711 _T("No member selected to generate attendance sheet")
2716 ->withHeader('Location', $this->router
->pathFor('members'));
2720 $members = $m->getArrayList(
2722 array('nom_adh', 'prenom_adh'),
2726 if (!is_array($members) ||
count($members) < 1) {
2727 Analog
::log('No member selected to generate attendance sheet', Analog
::INFO
);
2728 $this->flash
->addMessage(
2730 _T("No member selected to generate attendance sheet")
2735 ->withHeader('Location', $this->router
->pathFor('members'));
2738 $doc_title = _T("Attendance sheet");
2739 if (isset($post['sheet_type']) && trim($post['sheet_type']) != '') {
2740 $doc_title = $post['sheet_type'];
2744 'doc_title' => $doc_title,
2745 'title' => $post['sheet_title'] ??
null,
2746 'subtitle' => $post['sheet_sub_title'] ??
null,
2747 'sheet_date'=> $post['sheet_date'] ??
null
2749 $pdf = new Galette\IO\
PdfAttendanceSheet($this->zdb
, $this->preferences
, $data);
2750 //with or without images?
2751 if (isset($post['sheet_photos']) && $post['sheet_photos'] === '1') {
2754 $pdf->drawSheet($members);
2755 $response = $this->response
->withHeader('Content-type', 'application/pdf');
2756 $response->write($pdf->Output(_T("attendance_sheet") . '.pdf', 'D'));
2759 )->setName('attendance_sheet')->add($authenticate);
2762 '/ajax/members[/{option:page|order}/{value:\d+}]',
2763 function ($request, $response, $args) {
2764 $post = $request->getParsedBody();
2766 if (isset($this->session
->ajax_members_filters
)) {
2767 $filters = $this->session
->ajax_members_filters
;
2769 $filters = new MembersList();
2772 if (isset($args['option']) && $args['option'] == 'page') {
2773 $filters->current_page
= (int)$args['value'];
2776 //numbers of rows to display
2777 if (isset($post['nbshow']) && is_numeric($post['nbshow'])) {
2778 $filters->show
= $post['nbshow'];
2781 $members = new Members($filters);
2782 if (!$this->login
->isAdmin() && !$this->login
->isStaff()) {
2783 if ($this->login
->isGroupManager()) {
2784 $members_list = $members->getManagedMembersList(true);
2789 [$this->login
->id
, $this->login
->login
],
2790 'Trying to list group members without access from #%id (%login)'
2794 throw new Exception('Access denied.');
2798 $members_list = $members->getMembersList(true);
2801 //assign pagination variables to the template and add pagination links
2802 $filters->setSmartyPagination($this->router
, $this->view
->getSmarty(), false);
2804 $this->session
->ajax_members_filters
= $filters;
2806 $selected_members = null;
2807 $unreachables_members = null;
2808 if (!isset($post['from'])) {
2809 $mailing = $this->session
->mailing
;
2810 if (!isset($post['members'])) {
2811 $selected_members = $mailing->recipients
;
2812 $unreachables_members = $mailing->unreachables
;
2815 $selected_members = $m->getArrayList($post['members']);
2816 if (isset($post['unreachables']) && is_array($post['unreachables'])) {
2817 $unreachables_members = $m->getArrayList($post['unreachables']);
2821 switch ($post['from']) {
2823 if (!isset($post['gid'])) {
2825 'Trying to list group members with no group id provided',
2828 throw new Exception('A group id is required.');
2831 if (!isset($post['members'])) {
2832 $group = new Group((int)$post['gid']);
2833 $selected_members = array();
2834 if (!isset($post['mode']) ||
$post['mode'] == 'members') {
2835 $selected_members = $group->getMembers();
2836 } elseif ($post['mode'] == 'managers') {
2837 $selected_members = $group->getManagers();
2840 'Trying to list group members with unknown mode',
2843 throw new Exception('Unknown mode.');
2848 $selected_members = $m->getArrayList($post['members']);
2849 if (isset($post['unreachables']) && is_array($post['unreachables'])) {
2850 $unreachables_members = $m->getArrayList($post['unreachables']);
2855 if (!isset($post['id_adh'])) {
2856 throw new \
RuntimeException(
2857 'Current selected member must be excluded while attaching!'
2866 'filters' => $filters,
2867 'members_list' => $members_list,
2868 'selected_members' => $selected_members,
2869 'unreachables_members' => $unreachables_members
2872 if (isset($post['multiple'])) {
2873 $params['multiple'] = true;
2876 if (isset($post['gid'])) {
2877 $params['the_id'] = $post['gid'];
2880 if (isset($post['id_adh'])) {
2881 $params['excluded'] = $post['id_adh'];
2885 $this->view
->render(
2892 )->setName('ajaxMembers')->add($authenticate);
2895 '/ajax/group/members',
2896 function ($request, $response) {
2897 $post = $request->getParsedBody();
2899 $ids = $post['persons'];
2900 $mode = $post['person_mode'];
2902 if (!$ids ||
!$mode) {
2904 'Missing persons and mode for ajaxGroupMembers',
2911 $persons = $m->getArrayList($ids);
2914 $this->view
->render(
2916 'group_persons.tpl',
2918 'persons' => $persons,
2919 'person_mode' => $mode
2924 )->setName('ajaxGroupMembers')->add($authenticate);
2927 '/member/{id:\d+}/file/{fid:\d+}/{pos:\d+}/{name}',
2928 function ($request, $response, $args) {
2930 $id = (int)$args['id'];
2931 if ($this->login
->id
!= $args['id']
2932 && !$this->login
->isAdmin()
2933 && !$this->login
->isStaff()
2934 && !$this->login
->isGroupManager()
2944 'children' => false,
2947 $member = new Adherent($this->zdb
, $id, $deps);
2949 if (!$denied && $this->login
->id
!= $args['id']
2950 && $this->login
->isGroupManager()
2951 && !$this->login
->isStaff()
2952 && !$this->login
->isAdmin()
2954 //check if current logged in user can manage loaded member
2955 $groups = $member->groups
;
2956 $can_manage = false;
2957 foreach ($groups as $group) {
2958 if ($this->login
->isGroupManager($group->getId())) {
2963 if ($can_manage !== true) {
2965 'Logged in member ' . $this->login
->login
.
2966 ' has tried to load member #' . $member->id
.
2967 ' but do not manage any groups he belongs to.',
2974 if ($denied === false) {
2975 $fields = $member->getDynamicFields()->getFields();
2976 if (!isset($fields[$args['fid']])) {
2977 //field does not exists or access is forbidden
2982 if ($denied === true) {
2983 $this->flash
->addMessage(
2985 _T("You do not have permission for requested URL.")
2992 $this->router
->pathFor(
2999 $filename = str_replace(
3010 'member_%mid_field_%fid_value_%pos'
3013 if (file_exists(GALETTE_FILES_PATH
. $filename)) {
3014 $type = File
::getMimeType(GALETTE_FILES_PATH
. $filename);
3015 $response = $this->response
3016 ->withHeader('Content-Type', $type)
3017 ->withHeader('Content-Disposition', 'attachment;filename="' . $args['name'] . '"')
3018 ->withHeader('Pragma', 'no-cache');
3019 $response->write(readfile(GALETTE_FILES_PATH
. $filename));
3023 'A request has been made to get an exported file named `' .
3024 $filename .'` that does not exists.',
3028 $this->flash
->addMessage(
3030 _T("The file does not exists or cannot be read :(")
3037 $this->router
->pathFor('member', ['id' => $args['id']])
3041 )->setName('getDynamicFile')->add($authenticate);
3044 '/members/mass-change',
3045 function ($request, $response) {
3046 $filters = $this->session
->filter_members
;
3049 'id' => $filters->selected
,
3050 'redirect_uri' => $this->router
->pathFor('members')
3053 $fc = $this->fields_config
;
3054 $form_elements = $fc->getMassiveFormElements($this->members_fields
, $this->login
);
3062 'children' => false,
3065 $member = new Adherent($this->zdb
, null, $deps);
3068 $statuts = new Status($this->zdb
);
3071 $this->view
->render(
3073 'mass_change_members.tpl',
3075 'mode' => $request->isXhr() ?
'ajax' : '',
3076 'page_title' => str_replace(
3079 _T('Mass change %count members')
3081 'form_url' => $this->router
->pathFor('masschangeMembersReview'),
3082 'cancel_uri' => $this->router
->pathFor('members'),
3084 'member' => $member,
3085 'fieldsets' => $form_elements['fieldsets'],
3086 'titles_list' => Titles
::getList($this->zdb
),
3087 'statuts' => $statuts->getList(),
3088 'require_mass' => true
3093 )->setName('masschangeMembers')->add($authenticate);
3096 '/members/mass-change/validate',
3097 function ($request, $response) {
3098 $post = $request->getParsedBody();
3100 if (!isset($post['confirm'])) {
3101 $this->flash
->addMessage(
3103 _T("Mass changes has not been confirmed!")
3106 //we want only visibles fields
3107 $fc = $this->fields_config
;
3108 $form_elements = $fc->getMassiveFormElements($this->members_fields
, $this->login
);
3111 foreach ($form_elements['fieldsets'] as $form_element) {
3112 foreach ($form_element->elements
as $field) {
3113 if (isset($post[$field->field_id
]) && isset($post['mass_' . $field->field_id
])) {
3114 $changes[$field->field_id
] = [
3115 'label' => $field->label
,
3116 'value' => $post[$field->field_id
]
3123 $filters = $this->session
->filter_members
;
3125 'id' => $filters->selected
,
3126 'redirect_uri' => $this->router
->pathFor('members')
3130 $statuts = new Status($this->zdb
);
3133 $this->view
->render(
3135 'mass_change_members.tpl',
3137 'mode' => $request->isXhr() ?
'ajax' : '',
3138 'page_title' => str_replace(
3141 _T('Review mass change %count members')
3143 'form_url' => $this->router
->pathFor('massstoremembers'),
3144 'cancel_uri' => $this->router
->pathFor('members'),
3146 'titles_list' => Titles
::getList($this->zdb
),
3147 'statuts' => $statuts->getList(),
3148 'changes' => $changes
3153 )->setName('masschangeMembersReview')->add($authenticate);
3156 '/members/mass-change',
3157 function ($request, $response, $args) {
3158 $post = $request->getParsedBody();
3159 $redirect_url = $post['redirect_uri'];
3160 $error_detected = [];
3163 unset($post['redirect_uri']);
3164 if (!isset($post['confirm'])) {
3165 $error_detected[] = _T("Mass changes has not been confirmed!");
3167 unset($post['confirm']);
3171 $fc = $this->fields_config
;
3172 $form_elements = $fc->getMassiveFormElements($this->members_fields
, $this->login
);
3173 $disabled = $this->members_fields
;
3174 foreach (array_keys($post) as $key) {
3176 foreach ($form_elements['fieldsets'] as $fieldset) {
3177 if (isset($fieldset->elements
[$key])) {
3184 'Permission issue mass editing field ' . $key,
3189 unset($disabled[$key]);
3193 if (!count($post)) {
3194 $error_detected[] = _T("Nothing to do!");
3196 $is_manager = !$this->login
->isAdmin() && !$this->login
->isStaff() && $this->login
->isGroupManager();
3197 foreach ($ids as $id) {
3200 'groups' => $is_manager,
3203 'children' => false,
3206 $member = new Adherent($this->zdb
, (int)$id, $deps);
3207 $member->setDependencies(
3209 $this->members_fields
,
3214 $groups = $member->groups
;
3215 $is_managed = false;
3216 foreach ($groups as $g) {
3217 if ($this->login
->isGroupManager($g->getId())) {
3224 'Trying to edit member #' . $id . ' without appropriate ACLs',
3227 $error_detected[] = _T('No permission to edit member');
3232 $valid = $member->check($post, [], $disabled);
3233 if ($valid === true) {
3234 $done = $member->store();
3236 $error_detected[] = _T("An error occurred while storing the member.");
3241 $error_detected = array_merge($error_detected, $valid);
3247 if ($mass == 0 && !count($error_detected)) {
3248 $error_detected[] = _T('Something went wront during mass edition!');
3250 $this->flash
->addMessage(
3255 _T('%count members has been changed successfully!')
3260 if (count($error_detected) > 0) {
3261 foreach ($error_detected as $error) {
3262 $this->flash
->addMessage(
3269 if (!$request->isXhr()) {
3272 ->withHeader('Location', $redirect_url);
3274 return $response->withJson(
3276 'success' => count($error_detected) === 0
3281 )->setName('massstoremembers')->add($authenticate);
3285 '/members/duplicate/{' . Adherent
::PK
. ':\d+}',
3286 function ($request, $response, $args) {
3287 $id_adh = (int)$args[Adherent
::PK
];
3288 $adh = new Adherent($this->zdb
, $id_adh, ['dynamics' => true]);
3289 $adh->setDuplicate();
3291 //store entity in session
3292 $this->session
->member
= $adh;
3296 ->withHeader('Location', $this->router
->pathFor('editmember', ['action' => 'add']));
3298 )->setName('duplicateMember')->add($authenticate);
3304 function ($request, $response) {
3305 if ($request->isPost()) {
3306 $post = $request->getParsedBody();
3308 $post = $request->getQueryParams();
3312 if (isset($post['search_title'])) {
3313 $name = $post['search_title'];
3314 unset($post['search_title']);
3317 //when using advanced search, no parameters are sent
3318 if (isset($post['advanced_search'])) {
3320 $filters = $this->session
->filter_members
;
3321 foreach ($filters->search_fields
as $field) {
3322 $post[$field] = $filters->$field;
3326 //reformat, add required infos
3328 'parameters' => $post,
3329 'form' => 'Adherent',
3333 $sco = new Galette\Entity\
SavedSearch($this->zdb
, $this->login
);
3334 if ($check = $sco->check($post)) {
3335 if (!$res = $sco->store()) {
3336 if ($res === false) {
3337 $this->flash
->addMessage(
3339 _T("An SQL error has occurred while storing search.")
3342 $this->flash
->addMessage(
3344 _T("This search is already saved.")
3348 $this->flash
->addMessage(
3350 _T("Search has been saved.")
3355 foreach ($sco->getErrors() as $error) {
3356 $this->flash
->addMessage(
3363 if ($request->isGet()) {
3366 ->withHeader('Location', $this->router
->pathFor('members'));
3369 )->setName('saveSearch');
3372 '/saved-searches[/{option:page|order}/{value:\d+}]',
3373 function ($request, $response, $args = []) {
3375 if (isset($args['option'])) {
3376 $option = $args['option'];
3379 if (isset($args['value'])) {
3380 $value = $args['value'];
3383 if (isset($this->session
->filter_savedsearch
)) {
3384 $filters = $this->session
->filter_savedsearch
;
3386 $filters = new SavedSearchesList();
3389 if ($option !== null) {
3392 $filters->current_page
= (int)$value;
3395 $filters->orderby
= $value;
3400 $searches = new SavedSearches($this->zdb
, $this->login
, $filters);
3401 $list = $searches->getList(true);
3403 //assign pagination variables to the template and add pagination links
3404 $filters->setSmartyPagination($this->router
, $this->view
->getSmarty(), false);
3406 $this->session
->filter_savedsearch
= $filters;
3409 $this->view
->render(
3411 'saved_searches.tpl',
3413 'page_title' => _T("Saved searches"),
3414 'require_dialog' => true,
3415 'searches' => $list,
3416 'nb' => $searches->getCount(),
3417 'filters' => $filters
3422 )->setName('searches')->add($authenticate);
3425 '/search/remove/{id:\d+}',
3426 function ($request, $response, $args) {
3428 'id' => $args['id'],
3429 'redirect_uri' => $this->router
->pathFor('searches')
3433 $this->view
->render(
3435 'confirm_removal.tpl',
3437 'type' => _T("Saved search"),
3438 'mode' => $request->isXhr() ?
'ajax' : '',
3439 'page_title' => _T('Remove saved search'),
3440 'form_url' => $this->router
->pathFor('doRemoveSearch', ['id' => $args['id']]),
3441 'cancel_uri' => $this->router
->pathFor('searches'),
3447 )->setName('removeSearch')->add($authenticate);
3451 function ($request, $response) {
3452 $filters = $this->session
->filter_savedsearch
;
3455 'id' => $filters->selected
,
3456 'redirect_uri' => $this->router
->pathFor('searches')
3460 $this->view
->render(
3462 'confirm_removal.tpl',
3464 'type' => _T("Saved search"),
3465 'mode' => $request->isXhr() ?
'ajax' : '',
3466 'page_title' => _T('Remove saved searches'),
3467 'message' => str_replace(
3470 _T('You are about to remove %count searches.')
3472 'form_url' => $this->router
->pathFor('doRemoveSearch'),
3473 'cancel_uri' => $this->router
->pathFor('searches'),
3479 )->setName('removeSearches')->add($authenticate);
3482 '/search/remove' . '[/{id:\d+}]',
3483 function ($request, $response) {
3484 $post = $request->getParsedBody();
3485 $ajax = isset($post['ajax']) && $post['ajax'] === 'true';
3488 $uri = isset($post['redirect_uri']) ?
3489 $post['redirect_uri'] :
3490 $this->router
->pathFor('slash');
3492 if (!isset($post['confirm'])) {
3493 $this->flash
->addMessage(
3495 _T("Removal has not been confirmed!")
3498 if (isset($this->session
->filter_savedsearch
)) {
3499 $filters = $this->session
->filter_savedsearch
;
3501 $filters = new SavedSearchesList();
3503 $searches = new SavedSearches($this->zdb
, $this->login
, $filters);
3505 if (!is_array($post['id'])) {
3506 $ids = (array)$post['id'];
3511 $del = $searches->remove($ids, $this->history
);
3513 if ($del !== true) {
3514 $error_detected = _T("An error occurred trying to remove searches :/");
3516 $this->flash
->addMessage(
3521 $success_detected = str_replace(
3524 _T("%count searches have been successfully deleted.")
3527 $this->flash
->addMessage(
3539 ->withHeader('Location', $uri);
3541 return $response->withJson(
3543 'success' => $success
3548 )->setName('doRemoveSearch')->add($authenticate);
3551 '/save-search/{id}',
3552 function ($request, $response, $args) {
3554 $sco = new Galette\Entity\
SavedSearch($this->zdb
, $this->login
, (int)$args['id']);
3555 $this->flash
->addMessage(
3557 _T("Saved search loaded")
3559 } catch (\Exception
$e) {
3560 $this->flash
->addMessage(
3562 _T("An SQL error has occurred while storing search.")
3565 $parameters = (array)$sco->parameters
;
3568 if (isset($parameters['free_search'])) {
3569 $filters = new AdvancedMembersList();
3571 $filters = new MembersList();
3574 foreach ($parameters as $key => $value) {
3575 $filters->$key = $value;
3577 $this->session
->filter_members
= $filters;
3581 ->withHeader('Location', $this->router
->pathFor('members'));
3583 )->setName('loadSearch');