mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-10-31 09:18:24 +00:00 
			
		
		
		
	Admin CRUD for user groups
This commit is contained in:
		| @@ -0,0 +1,28 @@ | ||||
| <?php | ||||
|  | ||||
| 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\MainBundle\Controller; | ||||
|  | ||||
| use Chill\MainBundle\CRUD\Controller\CRUDController; | ||||
| use Chill\MainBundle\Pagination\PaginatorInterface; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
|  | ||||
| class UserGroupAdminController extends CRUDController | ||||
| { | ||||
|     protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator) | ||||
|     { | ||||
|         $query->addSelect('JSON_EXTRACT(e.label, :lang) AS HIDDEN labeli18n') | ||||
|             ->setParameter('lang', $request->getLocale()); | ||||
|         $query->addOrderBy('labeli18n', 'ASC'); | ||||
|  | ||||
|         return $query; | ||||
|     } | ||||
| } | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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<int, \Chill\MainBundle\Entity\User> | ||||
|      * @var Collection<int, User>&Selectable<int, User> | ||||
|      */ | ||||
|     #[ORM\ManyToMany(targetEntity: User::class)] | ||||
|     #[ORM\JoinTable(name: 'chill_main_user_group_user')] | ||||
|     private Collection $users; | ||||
|     private Collection&Selectable $users; | ||||
|  | ||||
|     /** | ||||
|      * @var Collection<int, User>&Selectable<int, User> | ||||
| @@ -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<int, User>&Collection<int, User> | ||||
|      */ | ||||
|     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); | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										58
									
								
								src/Bundle/ChillMainBundle/Form/UserGroupType.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/Bundle/ChillMainBundle/Form/UserGroupType.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| <?php | ||||
|  | ||||
| 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\MainBundle\Form; | ||||
|  | ||||
| use Chill\MainBundle\Form\Type\PickUserDynamicType; | ||||
| use Chill\MainBundle\Form\Type\TranslatableStringFormType; | ||||
| use Symfony\Component\Form\AbstractType; | ||||
| use Symfony\Component\Form\Extension\Core\Type\ColorType; | ||||
| use Symfony\Component\Form\Extension\Core\Type\TextType; | ||||
| use Symfony\Component\Form\FormBuilderInterface; | ||||
|  | ||||
| class UserGroupType extends AbstractType | ||||
| { | ||||
|     public function buildForm(FormBuilderInterface $builder, array $options) | ||||
|     { | ||||
|         $builder | ||||
|             ->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', | ||||
|             ]) | ||||
|         ; | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|             } | ||||
|   | ||||
| @@ -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 %} | ||||
| @@ -0,0 +1,86 @@ | ||||
| {% extends '@ChillMain/CRUD/Admin/index.html.twig' %} | ||||
|  | ||||
| {% block admin_content %} | ||||
|     {% embed '@ChillMain/CRUD/_index.html.twig' %} | ||||
|  | ||||
|         {% block table_entities %} | ||||
|             <div class="flex-table"> | ||||
|                 {% for entity in entities %} | ||||
|                     <div class="item-bloc"> | ||||
|                         <div class="item-row"> | ||||
|                             <div class="wrap-header"> | ||||
|                                 <div class="wh-row"> | ||||
|                                     <div class="wh-col"> | ||||
|                                         {{ entity|chill_entity_render_box }} | ||||
|                                     </div> | ||||
|                                     <div class="wh-col"> | ||||
|                                         {%- if not entity.active -%} | ||||
|                                             <div> | ||||
|                                                 <span class="badge bg-danger">{{ 'user_group.inactive'|trans }}</span> | ||||
|                                             </div>  | ||||
|                                         {%- endif -%} | ||||
|                                         <div>{{ 'user_group.with_count_users'|trans({'count': entity.users|length}) }}</div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="item-row separator"> | ||||
|                             <div class="wrap-list"> | ||||
|                                 <div class="wl-row"> | ||||
|                                     <div class="wl-col title"> | ||||
|                                         <strong>{{ 'user_group.with_users'|trans }}</strong> | ||||
|                                     </div> | ||||
|                                     <div class="wl-col list"> | ||||
|                                         {% for user in entity.userListByLabelAscending %} | ||||
|                                             <p class="wl-item"> | ||||
|                                             <span class="badge-user"> | ||||
|                                                 {{ user|chill_entity_render_box }} | ||||
|                                             </span> | ||||
|                                             </p> | ||||
|                                         {% else %} | ||||
|                                             <p class="wl-item chill-no-data-statement">{{ 'user_group.no_users'|trans }}</p> | ||||
|                                         {% endfor %} | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="item-row separator"> | ||||
|                             <div class="wrap-list"> | ||||
|                                 <div class="wl-row"> | ||||
|                                     <div class="wl-col title"> | ||||
|                                         <strong>{{ 'user_group.adminUsers'|trans }}</strong> | ||||
|                                     </div> | ||||
|                                     <div class="wl-col list"> | ||||
|                                         {% for user in entity.adminUserListByLabelAscending %} | ||||
|                                             <p class="wl-item"> | ||||
|                                             <span class="badge-user"> | ||||
|                                                 {{ user|chill_entity_render_box }} | ||||
|                                             </span> | ||||
|                                             </p> | ||||
|                                         {% else %} | ||||
|                                             <p class="wl-item chill-no-data-statement">{{ 'user_group.no_admin_users'|trans }}</p> | ||||
|                                         {% endfor %} | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="item-row separator"> | ||||
|                             <ul class="record_actions slim"> | ||||
|                                 <li> | ||||
|                                     <a href="{{ chill_path_add_return_path('chill_crud_admin_user_group_edit', {'id': entity.id}) }}" class="btn btn-edit"></a> | ||||
|                                 </li> | ||||
|                             </ul> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 {% endfor %} | ||||
|             </div> | ||||
|         {% endblock %} | ||||
|  | ||||
|         {% block actions_before %} | ||||
|             <li class='cancel'> | ||||
|                 <a href="{{ path('chill_main_admin_central') }}" class="btn btn-cancel">{{'Back to the admin'|trans }}</a> | ||||
|             </li> | ||||
|         {% endblock %} | ||||
|  | ||||
|     {% endembed %} | ||||
| {% endblock %} | ||||
| @@ -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 %} | ||||
| @@ -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]); | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user