]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Controllers/Crud/GroupsController.php
Initialize group parent search dropdown with HTML
[galette.git] / galette / lib / Galette / Controllers / Crud / GroupsController.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Galette groups controller
7 *
8 * PHP version 5
9 *
10 * Copyright © 2020-2023 The Galette Team
11 *
12 * This file is part of Galette (http://galette.tuxfamily.org).
13 *
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * @category Controllers
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2020-2023 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
33 * @link http://galette.tuxfamily.org
34 * @since Available since 0.9.4dev - 2020-05-06
35 */
36
37 namespace Galette\Controllers\Crud;
38
39 use Throwable;
40 use Galette\Controllers\CrudController;
41 use Slim\Psr7\Request;
42 use Slim\Psr7\Response;
43 use Galette\Entity\Adherent;
44 use Galette\Entity\Group;
45 use Galette\Repository\Groups;
46 use Galette\Repository\Members;
47 use Analog\Analog;
48
49 /**
50 * Galette groups controller
51 *
52 * @category Controllers
53 * @name GroupsController
54 * @package Galette
55 * @author Johan Cwiklinski <johan@x-tnd.be>
56 * @copyright 2020-2023 The Galette Team
57 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
58 * @link http://galette.tuxfamily.org
59 * @since Available since 0.9.4dev - 2020-05-06
60 */
61
62 class GroupsController extends CrudController
63 {
64 // CRUD - Create
65
66 /**
67 * Add page
68 *
69 * @param Request $request PSR Request
70 * @param Response $response PSR Response
71 *
72 * @return Response
73 */
74 public function add(Request $request, Response $response): Response
75 {
76 //no new page (included on list), just to satisfy inheritance
77 return $response;
78 }
79
80 /**
81 * Add action
82 *
83 * @param Request $request PSR Request
84 * @param Response $response PSR Response
85 * @param string $name Group name
86 *
87 * @return Response
88 */
89 public function doAdd(Request $request, Response $response, string $name = null): Response
90 {
91 $group = new Group();
92 $group->setLogin($this->login);
93 $group->setName($name);
94 $group->store();
95 if (!$this->login->isSuperAdmin()) {
96 $group->setManagers(new Adherent($this->zdb, $this->login->id));
97 }
98 $id = $group->getId();
99
100 return $response
101 ->withStatus(301)
102 ->withHeader('Location', $this->routeparser->urlFor('groups', ['id' => $id]));
103 }
104
105
106 /**
107 * Check uniqueness
108 *
109 * @param Request $request PSR Request
110 * @param Response $response PSR Response
111 *
112 * @return Response
113 */
114 public function checkUniqueness(Request $request, Response $response): Response
115 {
116 $post = $request->getParsedBody();
117 if (!isset($post['gname']) || $post['gname'] == '') {
118 Analog::log(
119 'Trying to check if group name is unique without name specified',
120 Analog::INFO
121 );
122 return $this->withJson(
123 $response,
124 [
125 'success' => false,
126 'message' => htmlentities(_T("Group name is missing!"))
127 ]
128 );
129 } else {
130 return $this->withJson(
131 $response,
132 [
133 'success' => Groups::isUnique($this->zdb, $post['gname'])
134 ]
135 );
136 }
137 }
138
139 // /CRUD - Create
140 // CRUD - Read
141
142 /**
143 * List page
144 *
145 * @param Request $request PSR Request
146 * @param Response $response PSR Response
147 * @param string $option One of 'page' or 'order'
148 * @param string|integer $value Value of the option
149 * @param integer $id Member id to check rights
150 *
151 * @return Response
152 */
153 public function list(Request $request, Response $response, $option = null, $value = null, $id = null): Response
154 {
155 $groups = new Groups($this->zdb, $this->login);
156 $group = new Group();
157 $group->setLogin($this->login);
158
159 $groups_root = $groups->getList(false);
160 $groups_list = $groups->getList();
161
162 if ($id !== null) {
163 if ($this->login->isGroupManager($id)) {
164 $group->load($id);
165 } else {
166 Analog::log(
167 'Trying to display group ' . $id . ' without appropriate permissions',
168 Analog::INFO
169 );
170 return $response->withStatus(403);
171 }
172 }
173
174 if ($id === null && count($groups_list) > 0) {
175 $group = current($groups_list);
176 if (!$this->login->isGroupManager($id)) {
177 foreach ($groups_list as $g) {
178 if ($this->login->isGroupManager($g->getId())) {
179 $group = $g;
180 break;
181 }
182 }
183 }
184 }
185
186 $parent_groups = [];
187 foreach ($groups_list as $parent_group) {
188 if ($group->canSetParentGroup($parent_group)) {
189 $parent_groups[] = $parent_group;
190 }
191 }
192
193 //Active tab on page
194 $tab = $request->getQueryParams['tab'] ?? 'group_information';
195
196 // display page
197 $this->view->render(
198 $response,
199 'pages/groups_list.html.twig',
200 array(
201 'page_title' => _T("Groups"),
202 'groups_root' => $groups_root,
203 'parent_groups' => $parent_groups,
204 'group' => $group,
205 'tab' => $tab
206 )
207 );
208 return $response;
209 }
210
211 /**
212 * Group page
213 *
214 * @param Request $request PSR Request
215 * @param Response $response PSR Response
216 *
217 * @return Response
218 */
219 public function getGroup(Request $request, Response $response): Response
220 {
221 $post = $request->getParsedBody();
222 $id = $post['id_group'];
223 $group = new Group((int)$id);
224 if (!$group->canEdit($this->login)) {
225 throw new \RuntimeException('Trying to edit group without appropriate permissions');
226 }
227
228 $groups = new Groups($this->zdb, $this->login);
229
230 // display page
231 $this->view->render(
232 $response,
233 'elements/group.html.twig',
234 array(
235 'mode' => 'ajax',
236 'groups' => $groups->getList(),
237 'group' => $group
238 )
239 );
240 return $response;
241 }
242
243 /**
244 * Groups list page for ajax calls
245 *
246 * @param Request $request PSR Request
247 * @param Response $response PSR Response
248 *
249 * @return Response
250 */
251 public function simpleList(Request $request, Response $response): Response
252 {
253 $post = $request->getParsedBody();
254
255 $groups = new Groups($this->zdb, $this->login);
256
257 // display page
258 $this->view->render(
259 $response,
260 'elements/ajax_groups.html.twig',
261 array(
262 'mode' => 'ajax',
263 'groups_list' => $groups->getList(),
264 'selected_groups' => (isset($post['groups']) ? $post['groups'] : [])
265 )
266 );
267 return $response;
268 }
269
270 /**
271 * Groups list page for ajax calls
272 *
273 * @param Request $request PSR Request
274 * @param Response $response PSR Response
275 *
276 * @return Response
277 */
278 public function ajaxMembers(Request $request, Response $response): Response
279 {
280 $post = $request->getParsedBody();
281
282 $ids = $post['persons'];
283 $mode = $post['person_mode'];
284
285 if (!$ids || !$mode) {
286 Analog::log(
287 'Missing persons and mode for ajaxGroupMembers',
288 Analog::INFO
289 );
290 die();
291 }
292
293 $m = new Members();
294 $persons = $m->getArrayList($ids);
295
296 // display page
297 $this->view->render(
298 $response,
299 'elements/group_persons.html.twig',
300 [
301 'persons' => $persons,
302 'person_mode' => $mode
303 ]
304 );
305 return $response;
306 }
307
308 /**
309 * Filtering
310 *
311 * @param Request $request PSR Request
312 * @param Response $response PSR Response
313 *
314 * @return Response
315 */
316 public function filter(Request $request, Response $response): Response
317 {
318 //no filters
319 return $response;
320 }
321
322 // /CRUD - Read
323 // CRUD - Update
324
325 /**
326 * Edit page
327 *
328 * @param Request $request PSR Request
329 * @param Response $response PSR Response
330 * @param integer $id Record id
331 *
332 * @return Response
333 */
334 public function edit(Request $request, Response $response, int $id): Response
335 {
336 //no edit page (included on list), just to satisfy inheritance
337 return $response;
338 }
339
340 /**
341 * Edit action
342 *
343 * @param Request $request PSR Request
344 * @param Response $response PSR Response
345 * @param integer $id Group id
346 *
347 * @return Response
348 */
349 public function doEdit(Request $request, Response $response, int $id): Response
350 {
351 $post = $request->getParsedBody();
352 $group = new Group($id);
353 if (!$group->canEdit($this->login)) {
354 throw new \RuntimeException('Trying to edit group without appropriate permissions');
355 }
356
357 $group->setName($post['group_name']);
358 try {
359 if ($post['parent_group'] !== '') {
360 $group->setParentGroup((int)$post['parent_group']);
361 } else {
362 $group->detach();
363 }
364
365 $m = new Members();
366
367 //handle group managers
368 if (isset($post['managers'])) {
369 $managers_id = $post['managers'];
370 $managers = $m->getArrayList($managers_id);
371 $group->setManagers($managers);
372 }
373
374 //handle group members
375 if (isset($post['members'])) {
376 $members_id = $post['members'];
377 $members = $m->getArrayList($members_id);
378 $group->setMembers($members);
379 }
380
381 $store = $group->store();
382 if ($store === true) {
383 $this->flash->addMessage(
384 'success_detected',
385 str_replace(
386 '%groupname',
387 $group->getName(),
388 _T("Group `%groupname` has been successfully saved.")
389 )
390 );
391 } else {
392 //something went wrong :'(
393 $this->flash->addMessage(
394 'error_detected',
395 _T("An error occurred while storing the group.")
396 );
397 }
398 } catch (Throwable $e) {
399 $this->flash->addMessage(
400 'error_detected',
401 $e->getMessage()
402 );
403 }
404
405 if (isset($post['tab']) && $post['tab'] != 'general') {
406 $tab = '?tab=' . $post['tab'];
407 } else {
408 $tab = '';
409 }
410 return $response
411 ->withStatus(301)
412 ->withHeader('Location', $this->routeparser->urlFor('groups', ['id' => $group->getId()]) . $tab);
413 }
414
415 /**
416 * Reoder action
417 *
418 * @param Request $request PSR Request
419 * @param Response $response PSR Response
420 *
421 * @return Response
422 */
423 public function reorder(Request $request, Response $response): Response
424 {
425 if (
426 !$this->login->isAdmin()
427 && !$this->login->isStaff()
428 && !($this->login->isGroupManager() && $this->preferences->pref_bool_groupsmanagers_edit_groups)
429 ) {
430 throw new \RuntimeException('Trying to reorder groups without appropriate permissions');
431 }
432
433 $post = $request->getParsedBody();
434 if (!isset($post['to']) || !isset($post['id_group']) || $post['id_group'] == '') {
435 Analog::log(
436 'Trying to reorder without required parameters!',
437 Analog::INFO
438 );
439 $result = false;
440 } else {
441 $id = $post['id_group'];
442 $group = new Group((int)$id);
443 if (!empty($post['to'])) {
444 $group->setParentGroup((int)$post['to']);
445 } else {
446 $group->detach();
447 }
448 $result = $group->store();
449 }
450
451 return $this->withJson(
452 $response,
453 [
454 'success' => $result
455 ]
456 );
457 }
458
459 // /CRUD - Update
460 // CRUD - Delete
461
462 /**
463 * Get redirection URI
464 *
465 * @param array $args Route arguments
466 *
467 * @return string
468 */
469 public function redirectUri(array $args)
470 {
471 return $this->routeparser->urlFor('groups');
472 }
473
474 /**
475 * Get form URI
476 *
477 * @param array $args Route arguments
478 *
479 * @return string
480 */
481 public function formUri(array $args)
482 {
483 return $this->routeparser->urlFor(
484 'doRemoveGroup',
485 ['id' => (int)$args['id']]
486 );
487 }
488
489 /**
490 * Get confirmation removal page title
491 *
492 * @param array $args Route arguments
493 *
494 * @return string
495 */
496 public function confirmRemoveTitle(array $args)
497 {
498 $group = new Group((int)$args['id']);
499 return sprintf(
500 _T('Remove group %1$s'),
501 $group->getFullName()
502 );
503 }
504
505 /**
506 * Remove object
507 *
508 * @param array $args Route arguments
509 * @param array $post POST values
510 *
511 * @return boolean
512 */
513 protected function doDelete(array $args, array $post)
514 {
515 $group = new Group((int)$post['id']);
516 $group->setLogin($this->login);
517 $cascade = isset($post['cascade']);
518 $is_deleted = $group->remove($cascade);
519
520 if ($is_deleted !== true && $group->isEmpty() === false) {
521 $this->flash->addMessage(
522 'error_detected',
523 _T("Group is not empty, it cannot be deleted. Use cascade delete instead.")
524 );
525 }
526
527 return $is_deleted;
528 }
529
530 /**
531 * Removal confirmation parameters, can be overriden
532 *
533 * @param Request $request PSR Request
534 *
535 * @return array
536 */
537 protected function getconfirmDeleteParams(Request $request): array
538 {
539 return parent::getconfirmDeleteParams($request) + ['with_cascade' => true];
540 }
541
542 // CRUD - Delete
543 }