diff --git a/app/routes.php b/app/routes.php index 3ea341d93df594f6c5782bd809855abc9fb47e39..088c939b137e48f4d309e8378d85d27adfe6fc08 100644 --- a/app/routes.php +++ b/app/routes.php @@ -17,8 +17,10 @@ use App\Application\Actions\Group\ViewModifyGroupForm; use App\Application\Actions\Group\ModifyGroupAction; use App\Application\Actions\Group\DeleteGroupAction; use App\Application\Actions\Group\AddUserGroupAction; +use App\Application\Actions\Group\AddUsersGroupAction; use App\Application\Actions\Search\SearchAction; +use App\Application\Actions\Search\ListUsersJson; use App\Application\Actions\Message\CreateMessageAction; use App\Application\Actions\Message\ListMessagesAction; @@ -28,6 +30,7 @@ use App\Application\Actions\Localisation\CreateLocalisationAction; use App\Application\Actions\Localisation\ListLocalisationsAction; use App\Application\Actions\Localisation\ViewLocalisationAction; + use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Slim\App; @@ -130,6 +133,7 @@ return function (App $app) { $group->get('/{id}/modify', ViewModifyGroupForm::class); $group->post('/{id}/modify', ModifyGroupAction::class); $group->post('/{id}/add', AddUserGroupAction::class); + $group->post('/{id}/add_multiple', AddUsersGroupAction::class); $group->get('/{id}', ViewGroupAction::class); } @@ -142,4 +146,10 @@ return function (App $app) { $group->post('', CreateLocalisationAction::class); } ); + + $app->group( + '/api', function (Group $group) { + $group->get('/users', ListUsersJson::class); + } + ); }; diff --git a/public/assets/js/users-search.js b/public/assets/js/users-search.js new file mode 100644 index 0000000000000000000000000000000000000000..82c59de72cae9bdaa34171f60615f9be9e4cd06c --- /dev/null +++ b/public/assets/js/users-search.js @@ -0,0 +1,55 @@ +window.onload = function () { + let usersToAdd = []; + + function removeUser(id) { + usersToAdd = usersToAdd.filter(user => user.id !== id); + refreshUsersToAdd(); + } + + function refreshUsersToAdd() { + const userLabels = usersToAdd.map(user => { + const deleteIcon = $('<i class="delete icon"/>'); + + deleteIcon.on('click', () => removeUser(user.id)); + + return $('<div class="ui image label" />') + .append($('<img>')) + .append($('<span>').text(user.username)) + .append(deleteIcon); + }); + + const userInputs = usersToAdd.map(user => + $('<input type="hidden" name="ids[]" />').prop('value', user.id) + ); + + $('#users-add-form').empty().append(userLabels).append(userInputs); + } + + function resetUsersToAdd() { + usersToAdd = []; + $('#users-add-form').empty(); + } + + $('#add-user-button').on('click', () => { + $('#modal_add_user').modal('show'); + resetUsersToAdd(); + }); + + $('.ui.search') + .search({ + apiSettings: { + url: '/api/users?q={query}' + }, + fields: { + results: 'data', + title: 'username' + }, + onSelect(result) { + if (!usersToAdd.find(user => user.id === result.id)) { + usersToAdd.push(result); + refreshUsersToAdd(); + } + } + }) + ; +} \ No newline at end of file diff --git a/src/Application/Actions/Group/AddUsersGroupAction.php b/src/Application/Actions/Group/AddUsersGroupAction.php new file mode 100755 index 0000000000000000000000000000000000000000..e970da821bb79de2602b92dc23bd5807d177ab36 --- /dev/null +++ b/src/Application/Actions/Group/AddUsersGroupAction.php @@ -0,0 +1,51 @@ +<?php +declare(strict_types=1); + +namespace App\Application\Actions\Group; +use App\Domain\Group\GroupNotFoundException; +use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface as Request; +use App\Domain\Group\Group ; + +class AddUsersGroupAction extends GroupAction +{ + /** + * {@inheritdoc} + */ + protected function action(): Response + { + $groupId = (int) $this->resolveArg('id'); + $group = $this->groupRepository->find($groupId); + + $parsedRequestBody = (array)$this->request->getParsedBody(); + $user_ids = $parsedRequestBody['ids']; + + if (!isset($group)) { + throw new GroupNotFoundException(); + } + + $users_query = $this->userRepository->createQueryBuilder('u'); + $users_list = $users_query + ->where('u.id IN (:user_ids)') + ->setParameter('user_ids', $user_ids) + ->getQuery() + ->getResult(); + + foreach ($users_list as $user) { + if (!$group->hasUser($user->getId())) { + $user->addGroup($group); + } + } + + $this->em->persist($group); + $this->em->flush(); + + $this->logger->info("User has been added in group."); + $this->flash->addMessage('add_user', 'Users have been added in group.'); + + return $this->response + ->withHeader('Location', '/groups/' . $groupId) + ->withStatus(302); + } + +} diff --git a/src/Application/Actions/Search/ListUsersJson.php b/src/Application/Actions/Search/ListUsersJson.php new file mode 100644 index 0000000000000000000000000000000000000000..019f1cdf86b8a00bed2c709804265c7b8f92f026 --- /dev/null +++ b/src/Application/Actions/Search/ListUsersJson.php @@ -0,0 +1,58 @@ +<?php +declare(strict_types=1); + +namespace App\Application\Actions\Search; + +use App\Application\Actions\Action; +use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface as Request; +use Doctrine\ORM\EntityManager; +use Psr\Log\LoggerInterface; +use Slim\Views\Twig; +use Slim\Flash\Messages; + +class ListUsersJson extends Action +{ + public function __construct(LoggerInterface $logger, EntityManager $em, Twig $twig, Messages $flash) + { + parent::__construct($logger); + $this->em = $em; + $this->userRepository = $em->getRepository('App\Domain\User\User'); + $this->flash = $flash; + $this->twig = $twig; + + } + /** + * {@inheritdoc} + */ + protected function action(): Response + { + + $parsedRequestBody = (array)$this->request->getParsedBody(); + + $search = $this->request->getQueryParams()['q']; + + $users_query = $this->userRepository->createQueryBuilder('u'); + $users_list = $users_query + ->where('u.username LIKE :search') + ->orWhere('u.firstName LIKE :search') + ->orWhere('u.lastName LIKE :search') + ->setParameter('search', '%' . $search . '%') + ->getQuery() + ->getResult(); + + return $this->respondWithData($users_list); + } + + /** + * Remove html chars + * @return string + */ + protected function checkValue($value): string + { + $value = strip_tags($value); + $value = htmlspecialchars_decode($value); + return $value; + } + +} diff --git a/src/Domain/User/User.php b/src/Domain/User/User.php index d3271e2a84fb4a01486a8c583368c8c098bf555f..c3a1dc7dabad64c0a2690247d5b061abaec6536f 100755 --- a/src/Domain/User/User.php +++ b/src/Domain/User/User.php @@ -174,7 +174,6 @@ class User implements JsonSerializable return $this->admins; } - /** * Set property */ diff --git a/templates/group/group_view.twig b/templates/group/group_view.twig index 02e08767f001e51b169347f08a06ac4013311577..00d29be4e52f7a1f905a32c29327a19c527a928c 100644 --- a/templates/group/group_view.twig +++ b/templates/group/group_view.twig @@ -21,6 +21,7 @@ <form action="/groups/{{group.getId}}/delete" method="post"> <button type="submit" class="ui button"><i class="trash icon"></i></button> </form> + <button class="ui button" id="add-user-button"><i class="user plus icon"></i> Add a member </button> {% endif %} {% if group.hasUser(session.userId) == false %} <form action="/groups/{{group.getId}}/add" method="post"> @@ -41,5 +42,36 @@ </div> </div> {% endfor %} + + {% if group.checkAdmin(session.userId) %} + <div class="ui modal" id="modal_add_user"> + <div class="header"> + Add a member + </div> + <div class="content"> + <div class="description"> + <div class="ui search"> + <div class="ui icon input"> + <input class="prompt" type="text" placeholder="Search users"> + <i class="search icon"></i> + </div> + <div class="results"></div> + </div> + + <form method="post" action="/groups/{{group.id}}/add_multiple" id="users-add-form"></form> + </div> + </div> + <div class="actions"> + <div class="ui black deny button">Cancel</div> + <button type="submit" form="users-add-form" class="ui positive right labeled icon button"> + Add <i class="checkmark icon"></i> + </button> + </div> + </div> + + <script type="text/javascript" src="/assets/js/users-search.js"></script> + {% endif %} + </div> -{% endblock %} \ No newline at end of file +{% endblock %} +