diff --git a/src/Bundle/ChillMainBundle/Controller/UserGroupAdminController.php b/src/Bundle/ChillMainBundle/Controller/UserGroupAdminController.php new file mode 100644 index 000000000..04a9a9910 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Controller/UserGroupAdminController.php @@ -0,0 +1,28 @@ +addSelect('JSON_EXTRACT(e.label, :lang) AS HIDDEN labeli18n') + ->setParameter('lang', $request->getLocale()); + $query->addOrderBy('labeli18n', 'ASC'); + + return $query; + } +} diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 97df404af..999277ed1 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -24,6 +24,7 @@ use Chill\MainBundle\Controller\LocationTypeController; use Chill\MainBundle\Controller\NewsItemController; use Chill\MainBundle\Controller\RegroupmentController; use Chill\MainBundle\Controller\UserController; +use Chill\MainBundle\Controller\UserGroupAdminController; use Chill\MainBundle\Controller\UserGroupApiController; use Chill\MainBundle\Controller\UserJobApiController; use Chill\MainBundle\Controller\UserJobController; @@ -70,6 +71,7 @@ use Chill\MainBundle\Form\LocationFormType; use Chill\MainBundle\Form\LocationTypeType; use Chill\MainBundle\Form\NewsItemType; use Chill\MainBundle\Form\RegroupmentType; +use Chill\MainBundle\Form\UserGroupType; use Chill\MainBundle\Form\UserJobType; use Chill\MainBundle\Form\UserType; use Misd\PhoneNumberBundle\Doctrine\DBAL\Types\PhoneNumberType; @@ -355,6 +357,28 @@ class ChillMainExtension extends Extension implements { $container->prependExtensionConfig('chill_main', [ 'cruds' => [ + [ + 'class' => UserGroup::class, + 'controller' => UserGroupAdminController::class, + 'name' => 'admin_user_group', + 'base_path' => '/admin/main/user-group', + 'base_role' => 'ROLE_ADMIN', + 'form_class' => UserGroupType::class, + 'actions' => [ + 'index' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillMain/UserGroup/index.html.twig', + ], + 'new' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillMain/UserGroup/new.html.twig', + ], + 'edit' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillMain/UserGroup/edit.html.twig', + ], + ], + ], [ 'class' => UserJob::class, 'controller' => UserJobController::class, diff --git a/src/Bundle/ChillMainBundle/Entity/UserGroup.php b/src/Bundle/ChillMainBundle/Entity/UserGroup.php index 35e967e5f..b42609693 100644 --- a/src/Bundle/ChillMainBundle/Entity/UserGroup.php +++ b/src/Bundle/ChillMainBundle/Entity/UserGroup.php @@ -13,6 +13,10 @@ namespace Chill\MainBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; +use Doctrine\Common\Collections\Criteria; +use Doctrine\Common\Collections\Order; +use Doctrine\Common\Collections\ReadableCollection; +use Doctrine\Common\Collections\Selectable; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] @@ -31,11 +35,11 @@ class UserGroup private array $label = []; /** - * @var \Doctrine\Common\Collections\Collection + * @var Collection&Selectable */ #[ORM\ManyToMany(targetEntity: User::class)] #[ORM\JoinTable(name: 'chill_main_user_group_user')] - private Collection $users; + private Collection&Selectable $users; /** * @var Collection&Selectable @@ -61,6 +65,7 @@ class UserGroup public function __construct() { + $this->adminUsers = new \Doctrine\Common\Collections\ArrayCollection(); $this->users = new ArrayCollection(); } @@ -72,6 +77,7 @@ class UserGroup public function setActive(bool $active): self { $this->active = $active; + return $this; } @@ -119,7 +125,10 @@ class UserGroup return $this->label; } - public function getUsers(): Collection + /** + * @return Selectable&Collection + */ + public function getUsers(): Collection&Selectable { return $this->users; } @@ -191,4 +200,20 @@ class UserGroup { return $this->users->contains($user); } + + public function getUserListByLabelAscending(): ReadableCollection + { + $criteria = Criteria::create(); + $criteria->orderBy(['label' => Order::Ascending]); + + return $this->getUsers()->matching($criteria); + } + + public function getAdminUserListByLabelAscending(): ReadableCollection + { + $criteria = Criteria::create(); + $criteria->orderBy(['label' => Order::Ascending]); + + return $this->getAdminUsers()->matching($criteria); + } } diff --git a/src/Bundle/ChillMainBundle/Form/UserGroupType.php b/src/Bundle/ChillMainBundle/Form/UserGroupType.php new file mode 100644 index 000000000..8a4685c7c --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/UserGroupType.php @@ -0,0 +1,58 @@ +add('label', TranslatableStringFormType::class, [ + 'label' => 'user_group.Label', + 'required' => true, + ]) + ->add('active') + ->add('backgroundColor', ColorType::class, [ + 'label' => 'user_group.BackgroundColor', + ]) + ->add('foregroundColor', ColorType::class, [ + 'label' => 'user_group.ForegroundColor', + ]) + ->add('excludeKey', TextType::class, [ + 'label' => 'user_group.ExcludeKey', + 'help' => 'user_group.ExcludeKeyHelp', + 'required' => false, + 'empty_data' => '', + ]) + ->add('users', PickUserDynamicType::class, [ + 'label' => 'user_group.Users', + 'multiple' => true, + 'required' => false, + 'empty_data' => [], + ]) + ->add('adminUsers', PickUserDynamicType::class, [ + 'label' => 'user_group.adminUsers', + 'multiple' => true, + 'required' => false, + 'empty_data' => [], + 'help' => 'user_group.adminUsersHelp', + ]) + ; + } +} diff --git a/src/Bundle/ChillMainBundle/Repository/UserGroupRepository.php b/src/Bundle/ChillMainBundle/Repository/UserGroupRepository.php index aa2d6f5f5..637846526 100644 --- a/src/Bundle/ChillMainBundle/Repository/UserGroupRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/UserGroupRepository.php @@ -59,8 +59,9 @@ final readonly class UserGroupRepository implements UserGroupRepositoryInterface ->setSelectPertinence('3 + SIMILARITY(LOWER(UNACCENT(?)), ug.label->>?) + CASE WHEN (EXISTS(SELECT 1 FROM unnest(string_to_array(label->>?, \' \')) AS t WHERE LOWER(t) LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\')) THEN 100 ELSE 0 END', [$pattern, $lang, $lang, $pattern]) ->setFromClause('chill_main_user_group AS ug') ->setWhereClauses(' + ug.active AND ( SIMILARITY(LOWER(UNACCENT(?)), ug.label->>?) > 0.15 - OR ug.label->>? LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\' + OR ug.label->>? LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\') ', [$pattern, $lang, $pattern, $lang]); return $query; diff --git a/src/Bundle/ChillMainBundle/Resources/public/chill/scss/flex_table.scss b/src/Bundle/ChillMainBundle/Resources/public/chill/scss/flex_table.scss index 673d5129a..0adf2b628 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/chill/scss/flex_table.scss +++ b/src/Bundle/ChillMainBundle/Resources/public/chill/scss/flex_table.scss @@ -233,7 +233,7 @@ div.wrap-header { } &:last-child {} - div.wh-col { + & > div.wh-col { &:first-child { flex-grow: 0; flex-shrink: 1; flex-basis: auto; } diff --git a/src/Bundle/ChillMainBundle/Resources/views/UserGroup/edit.html.twig b/src/Bundle/ChillMainBundle/Resources/views/UserGroup/edit.html.twig new file mode 100644 index 000000000..3090cb87c --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/UserGroup/edit.html.twig @@ -0,0 +1,21 @@ +{% extends '@ChillMain/CRUD/Admin/index.html.twig' %} + +{% block css %} + {{ parent() }} + {{ encore_entry_link_tags('mod_pickentity_type') }} +{% endblock %} + +{% block js %} + {{ parent() }} + {{ encore_entry_script_tags('mod_pickentity_type') }} +{% endblock %} + +{% block title %} + {% include('@ChillMain/CRUD/_edit_title.html.twig') %} +{% endblock %} + +{% block admin_content %} + {% embed '@ChillMain/CRUD/_edit_content.html.twig' %} + {% block content_form_actions_save_and_show %}{% endblock %} + {% endembed %} +{% endblock admin_content %} diff --git a/src/Bundle/ChillMainBundle/Resources/views/UserGroup/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/UserGroup/index.html.twig new file mode 100644 index 000000000..c9d666f76 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/UserGroup/index.html.twig @@ -0,0 +1,86 @@ +{% extends '@ChillMain/CRUD/Admin/index.html.twig' %} + +{% block admin_content %} + {% embed '@ChillMain/CRUD/_index.html.twig' %} + + {% block table_entities %} +
+ {% for entity in entities %} +
+
+
+
+
+ {{ entity|chill_entity_render_box }} +
+
+ {%- if not entity.active -%} +
+ {{ 'user_group.inactive'|trans }} +
  + {%- endif -%} +
{{ 'user_group.with_count_users'|trans({'count': entity.users|length}) }}
+
+
+
+
+
+
+
+
+ {{ 'user_group.with_users'|trans }} +
+
+ {% for user in entity.userListByLabelAscending %} +

+ + {{ user|chill_entity_render_box }} + +

+ {% else %} +

{{ 'user_group.no_users'|trans }}

+ {% endfor %} +
+
+
+
+
+
+
+
+ {{ 'user_group.adminUsers'|trans }} +
+
+ {% for user in entity.adminUserListByLabelAscending %} +

+ + {{ user|chill_entity_render_box }} + +

+ {% else %} +

{{ 'user_group.no_admin_users'|trans }}

+ {% endfor %} +
+
+
+
+
+
    +
  • + +
  • +
+
+
+ {% endfor %} +
+ {% endblock %} + + {% block actions_before %} +
  • + {{'Back to the admin'|trans }} +
  • + {% endblock %} + + {% endembed %} +{% endblock %} diff --git a/src/Bundle/ChillMainBundle/Resources/views/UserGroup/new.html.twig b/src/Bundle/ChillMainBundle/Resources/views/UserGroup/new.html.twig new file mode 100644 index 000000000..2bb0c3d1f --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/UserGroup/new.html.twig @@ -0,0 +1,21 @@ +{% extends '@ChillMain/CRUD/Admin/index.html.twig' %} + +{% block css %} + {{ parent() }} + {{ encore_entry_link_tags('mod_pickentity_type') }} +{% endblock %} + +{% block js %} + {{ parent() }} + {{ encore_entry_script_tags('mod_pickentity_type') }} +{% endblock %} + +{% block title %} + {% include('@ChillMain/CRUD/_new_title.html.twig') %} +{% endblock %} + +{% block admin_content %} + {% embed '@ChillMain/CRUD/_new_content.html.twig' %} + {% block content_form_actions_save_and_show %}{% endblock %} + {% endembed %} +{% endblock admin_content %} diff --git a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminUserMenuBuilder.php b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminUserMenuBuilder.php index 22bdfbeb8..6c2baf0fd 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminUserMenuBuilder.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminUserMenuBuilder.php @@ -67,6 +67,10 @@ class AdminUserMenuBuilder implements LocalMenuBuilderInterface 'route' => 'chill_crud_admin_user_index', ])->setExtras(['order' => 1040]); + $menu->addChild('crud.admin_user_group.index.title', [ + 'route' => 'chill_crud_admin_user_group_index', + ])->setExtras(['order' => 1042]); + $menu->addChild('User jobs', [ 'route' => 'chill_crud_admin_user_job_index', ])->setExtras(['order' => 1050]); diff --git a/src/Bundle/ChillMainBundle/migrations/Version20240927095751.php b/src/Bundle/ChillMainBundle/migrations/Version20240927095751.php index ce34eb5c2..788efb1e8 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20240927095751.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20240927095751.php @@ -2,6 +2,13 @@ declare(strict_types=1); +/* + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + namespace Chill\Migrations\Main; use Doctrine\DBAL\Schema\Schema; diff --git a/src/Bundle/ChillMainBundle/translations/messages+intl-icu.fr.yaml b/src/Bundle/ChillMainBundle/translations/messages+intl-icu.fr.yaml index 7f941b13a..ecfd0f5c8 100644 --- a/src/Bundle/ChillMainBundle/translations/messages+intl-icu.fr.yaml +++ b/src/Bundle/ChillMainBundle/translations/messages+intl-icu.fr.yaml @@ -5,6 +5,15 @@ years_old: >- other {# ans} } +user_group: + with_count_users: >- + {count, plural, + =0 {Aucun membre} + one {1 utilisateur} + many {# utilisateurs} + other {# utilisateurs} + } + notification: My notifications with counter: >- {nb, plural, diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index 8bade3ce6..484e72a41 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -51,6 +51,20 @@ user: no job: Pas de métier assigné no scope: Pas de cercle assigné +user_group: + inactive: Inactif + with_users: Associé aux utilisateurs + no_users: Aucun utilisateur associé + no_admin_users: Aucun administrateur + Label: Nom du groupe + BackgroundColor: Couleur de fond du badge + ForegroundColor: Couleur de la police du badge + ExcludeKey: Clé d'exclusion + ExcludeKeyHelp: Lorsque cela est pertinent, les groupes comportant la même clé d'exclusion s'excluent mutuellement. + Users: Membres du groupe + adminUsers: Administrateurs du groupe + adminUsersHelp: Les administrateurs du groupe peuvent ajouter ou retirer des membres dans le groupe. + inactive: inactif Edit: Modifier @@ -395,6 +409,12 @@ crud: add_new: Créer title_new: Nouveau métier title_edit: Modifier un métier + admin_user_group: + index: + title: Groupes d'utilisateurs + add_new: Créer + title_edit: Modifier un groupe d'utilisateur + title_new: Nouveau groupe utilisateur main_location_type: index: title: Liste des types de localisations