edit user roles and app per organization
This commit is contained in:
parent
1d2debf364
commit
cfe89f58db
|
|
@ -10,7 +10,7 @@
|
||||||
- Les icones sont gérées via symfony UX (https://ux.symfony.com/icons)
|
- Les icones sont gérées via symfony UX (https://ux.symfony.com/icons)
|
||||||
- Les icones sont prises en prioritées dans la bibliothèque bootstrap
|
- Les icones sont prises en prioritées dans la bibliothèque bootstrap
|
||||||
- Les icones n'éxistants pas dans cette bibliothèques seront prises en priorité dans fontawesome regular (pour une cohérence visuelle)
|
- Les icones n'éxistants pas dans cette bibliothèques seront prises en priorité dans fontawesome regular (pour une cohérence visuelle)
|
||||||
- Sinon privilégier la bibliothèque ayant le visuel le plus proche
|
- Sinon privilégier la bibliothèque ayant le visuel le plus proche
|
||||||
|
|
||||||
### Version 0.1 : (17/03/2025)
|
### Version 0.1 : (17/03/2025)
|
||||||
- Contient la logique de login mot de passe avec une entité user (email et password seuelement)
|
- Contient la logique de login mot de passe avec une entité user (email et password seuelement)
|
||||||
|
|
@ -19,5 +19,12 @@
|
||||||
- Une base de template est gérée pour toutes les pages de l'application aya,t besoin de l'entête et du menu général
|
- Une base de template est gérée pour toutes les pages de l'application aya,t besoin de l'entête et du menu général
|
||||||
- Une ébauche de page d'accueil est en cours
|
- Une ébauche de page d'accueil est en cours
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
#### Choices.js
|
||||||
|
```bash
|
||||||
|
php bin/console importmap:require choices.js
|
||||||
|
php bin/console importmap:require choices.js/public/assets/styles/choices.min.css
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,5 @@ import './js/template.js';
|
||||||
import './js/off_canvas.js';
|
import './js/off_canvas.js';
|
||||||
import './js/hoverable-collapse.js';
|
import './js/hoverable-collapse.js';
|
||||||
import './js/cookies.js';
|
import './js/cookies.js';
|
||||||
|
import 'choices.js';
|
||||||
|
import 'choices.js/public/assets/styles/choices.min.css';
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
},
|
},
|
||||||
"@symfony/ux-turbo": {
|
"@symfony/ux-turbo": {
|
||||||
"turbo-core": {
|
"turbo-core": {
|
||||||
"enabled": false,
|
"enabled": true,
|
||||||
"fetch": "eager"
|
"fetch": "eager"
|
||||||
},
|
},
|
||||||
"mercure-turbo-stream": {
|
"mercure-turbo-stream": {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
import {Controller} from '@hotwired/stimulus';
|
||||||
|
import Choices from 'choices.js';
|
||||||
|
/*
|
||||||
|
* The following line makes this controller "lazy": it won't be downloaded until needed
|
||||||
|
* See https://symfony.com/bundles/StimulusBundle/current/index.html#lazy-stimulus-controllers
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* stimulusFetch: 'lazy' */
|
||||||
|
export default class extends Controller {
|
||||||
|
static values = {
|
||||||
|
rolesArray: Array,
|
||||||
|
selectedRoleIds: Array,
|
||||||
|
applicationsArray: Array,
|
||||||
|
selectedApplicationIds: Array
|
||||||
|
}
|
||||||
|
// {value: 'choice1', label: 'Choice 1'},
|
||||||
|
// {value: 'choice2', label: 'Choice 2'},
|
||||||
|
// {value: 'choice3', label: 'Choice 3'},
|
||||||
|
|
||||||
|
roleSelect() {
|
||||||
|
const element = document.getElementById('roles');
|
||||||
|
if (element) {
|
||||||
|
const choicesData = this.rolesArrayValue.map(role => ({
|
||||||
|
value: role.id,
|
||||||
|
label: role.name,
|
||||||
|
selected: this.selectedRoleIdsValue.includes(role.id)
|
||||||
|
}));
|
||||||
|
|
||||||
|
const choices = new Choices(element, {
|
||||||
|
choices: choicesData,
|
||||||
|
removeItemButton: true,
|
||||||
|
placeholder: true,
|
||||||
|
placeholderValue: 'Ajouter un ou plusieurs rôles'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appSelect() {
|
||||||
|
const element = document.getElementById('applications');
|
||||||
|
if (element) {
|
||||||
|
|
||||||
|
const choicesData = this.applicationsArrayValue.map(app => ({
|
||||||
|
value: app.id,
|
||||||
|
label: app.name,
|
||||||
|
customProperties: { icon: app.icon },
|
||||||
|
selected: this.selectedApplicationIdsValue.includes(app.id)
|
||||||
|
}));
|
||||||
|
|
||||||
|
const choices = new Choices(element, {
|
||||||
|
choices: choicesData,
|
||||||
|
removeItemButton: true,
|
||||||
|
placeholder: true,
|
||||||
|
placeholderValue: 'Ajouter une ou plusieurs applications',
|
||||||
|
// callbackOnCreateTemplates: function(template) {
|
||||||
|
// return {
|
||||||
|
// // Custom rendering for dropdown choices
|
||||||
|
// choice: (classNames, data) => {
|
||||||
|
// return template(`
|
||||||
|
// <div class="${classNames.item} ${classNames.itemChoice}" data-select-text="${this.config.itemSelectText}" data-choice data-id="${data.id}" data-value="${data.value}" ${data.groupId > 0 ? 'role="treeitem"' : 'role="option"'} >
|
||||||
|
// ${data.customProperties && data.customProperties.icon ? `<img src="${data.customProperties.icon}" alt="" style="width:20px;height:20px;vertical-align:middle;margin-right:8px;">` : ''}
|
||||||
|
// ${data.label}
|
||||||
|
// </div>
|
||||||
|
// `);
|
||||||
|
// },
|
||||||
|
// // Custom rendering for selected items
|
||||||
|
// item: (classNames, data) => {
|
||||||
|
// return template(`
|
||||||
|
// <div class="${classNames.item} ${classNames.itemSelectable}" data-item data-id="${data.id}" data-value="${data.value}" ${data.active ? 'aria-selected="true"' : ''} ${data.disabled ? 'aria-disabled="true"' : ''}>
|
||||||
|
// ${data.customProperties && data.customProperties.icon ? `<img src="${data.customProperties.icon}" alt="" style="width:20px;height:20px;vertical-align:middle;margin-right:8px;">` : ''}
|
||||||
|
// ${data.label}
|
||||||
|
// </div>
|
||||||
|
// `);
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
this.roleSelect();
|
||||||
|
this.appSelect();
|
||||||
|
|
||||||
|
// Set choices after initialization
|
||||||
|
// choices.setValue(choicesData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Add custom controller actions here
|
||||||
|
// fooBar() { this.fooTarget.classList.toggle(this.bazClass) }
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
// Called anytime its element is disconnected from the DOM
|
||||||
|
// (on page change, when it's removed from or moved in the DOM, etc.)
|
||||||
|
|
||||||
|
// Here you should remove all event listeners added in "connect()"
|
||||||
|
// this.fooTarget.removeEventListener('click', this._fooBar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2423,16 +2423,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpdoc-parser",
|
"name": "phpstan/phpdoc-parser",
|
||||||
"version": "2.1.0",
|
"version": "2.2.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||||
"reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68"
|
"reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9b30d6fd026b2c132b3985ce6b23bec09ab3aa68",
|
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8",
|
||||||
"reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68",
|
"reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -2464,9 +2464,9 @@
|
||||||
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
||||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/2.1.0"
|
"source": "https://github.com/phpstan/phpdoc-parser/tree/2.2.0"
|
||||||
},
|
},
|
||||||
"time": "2025-02-19T13:28:12+00:00"
|
"time": "2025-07-13T07:04:09+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/cache",
|
"name": "psr/cache",
|
||||||
|
|
|
||||||
|
|
@ -35,4 +35,11 @@ return [
|
||||||
'version' => '5.3.5',
|
'version' => '5.3.5',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
],
|
],
|
||||||
|
'choices.js' => [
|
||||||
|
'version' => '11.1.0',
|
||||||
|
],
|
||||||
|
'choices.js/public/assets/styles/choices.min.css' => [
|
||||||
|
'version' => '11.1.0',
|
||||||
|
'type' => 'css',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20250724133531 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE TABLE user_organization_app (id SERIAL NOT NULL, applications_id INT DEFAULT NULL, organization_id INT DEFAULT NULL, users_id INT DEFAULT NULL, PRIMARY KEY(id))');
|
||||||
|
$this->addSql('CREATE INDEX IDX_BEF66DF129A0022 ON user_organization_app (applications_id)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_BEF66DF132C8A3DE ON user_organization_app (organization_id)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_BEF66DF167B3B43D ON user_organization_app (users_id)');
|
||||||
|
$this->addSql('CREATE TABLE user_organization_roles (id SERIAL NOT NULL, role_id INT DEFAULT NULL, users_id INT DEFAULT NULL, organization_id INT DEFAULT NULL, PRIMARY KEY(id))');
|
||||||
|
$this->addSql('CREATE INDEX IDX_94FD2EFBD60322AC ON user_organization_roles (role_id)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_94FD2EFB67B3B43D ON user_organization_roles (users_id)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_94FD2EFB32C8A3DE ON user_organization_roles (organization_id)');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_app ADD CONSTRAINT FK_BEF66DF129A0022 FOREIGN KEY (applications_id) REFERENCES apps (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_app ADD CONSTRAINT FK_BEF66DF132C8A3DE FOREIGN KEY (organization_id) REFERENCES organizations (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_app ADD CONSTRAINT FK_BEF66DF167B3B43D FOREIGN KEY (users_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_roles ADD CONSTRAINT FK_94FD2EFBD60322AC FOREIGN KEY (role_id) REFERENCES roles (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_roles ADD CONSTRAINT FK_94FD2EFB67B3B43D FOREIGN KEY (users_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_roles ADD CONSTRAINT FK_94FD2EFB32C8A3DE FOREIGN KEY (organization_id) REFERENCES organizations (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SCHEMA public');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_app DROP CONSTRAINT FK_BEF66DF129A0022');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_app DROP CONSTRAINT FK_BEF66DF132C8A3DE');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_app DROP CONSTRAINT FK_BEF66DF167B3B43D');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_roles DROP CONSTRAINT FK_94FD2EFBD60322AC');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_roles DROP CONSTRAINT FK_94FD2EFB67B3B43D');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_roles DROP CONSTRAINT FK_94FD2EFB32C8A3DE');
|
||||||
|
$this->addSql('DROP TABLE user_organization_app');
|
||||||
|
$this->addSql('DROP TABLE user_organization_roles');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20250725065027 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('DROP SEQUENCE user_organization_roles_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP SEQUENCE user_organization_app_id_seq CASCADE');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_app DROP CONSTRAINT fk_bef66df129a0022');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_app DROP CONSTRAINT fk_bef66df132c8a3de');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_app DROP CONSTRAINT fk_bef66df167b3b43d');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_roles DROP CONSTRAINT fk_94fd2efb32c8a3de');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_roles DROP CONSTRAINT fk_94fd2efb67b3b43d');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_roles DROP CONSTRAINT fk_94fd2efbd60322ac');
|
||||||
|
$this->addSql('DROP TABLE user_organization_app');
|
||||||
|
$this->addSql('DROP TABLE user_organization_roles');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SCHEMA public');
|
||||||
|
$this->addSql('CREATE SEQUENCE user_organization_roles_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE SEQUENCE user_organization_app_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE TABLE user_organization_app (id SERIAL NOT NULL, applications_id INT DEFAULT NULL, organization_id INT DEFAULT NULL, users_id INT DEFAULT NULL, PRIMARY KEY(id))');
|
||||||
|
$this->addSql('CREATE INDEX idx_bef66df129a0022 ON user_organization_app (applications_id)');
|
||||||
|
$this->addSql('CREATE INDEX idx_bef66df132c8a3de ON user_organization_app (organization_id)');
|
||||||
|
$this->addSql('CREATE INDEX idx_bef66df167b3b43d ON user_organization_app (users_id)');
|
||||||
|
$this->addSql('CREATE TABLE user_organization_roles (id SERIAL NOT NULL, role_id INT DEFAULT NULL, users_id INT DEFAULT NULL, organization_id INT DEFAULT NULL, PRIMARY KEY(id))');
|
||||||
|
$this->addSql('CREATE INDEX idx_94fd2efb32c8a3de ON user_organization_roles (organization_id)');
|
||||||
|
$this->addSql('CREATE INDEX idx_94fd2efb67b3b43d ON user_organization_roles (users_id)');
|
||||||
|
$this->addSql('CREATE INDEX idx_94fd2efbd60322ac ON user_organization_roles (role_id)');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_app ADD CONSTRAINT fk_bef66df129a0022 FOREIGN KEY (applications_id) REFERENCES apps (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_app ADD CONSTRAINT fk_bef66df132c8a3de FOREIGN KEY (organization_id) REFERENCES organizations (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_app ADD CONSTRAINT fk_bef66df167b3b43d FOREIGN KEY (users_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_roles ADD CONSTRAINT fk_94fd2efb32c8a3de FOREIGN KEY (organization_id) REFERENCES organizations (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_roles ADD CONSTRAINT fk_94fd2efb67b3b43d FOREIGN KEY (users_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE user_organization_roles ADD CONSTRAINT fk_94fd2efbd60322ac FOREIGN KEY (role_id) REFERENCES roles (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,12 +2,16 @@
|
||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Entity\Apps;
|
||||||
|
use App\Entity\Roles;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Form\UserForm;
|
use App\Form\UserForm;
|
||||||
|
use App\Entity\UsersOrganizations;
|
||||||
use App\Service\UserOrganizationService;
|
use App\Service\UserOrganizationService;
|
||||||
use App\Service\UserService;
|
use App\Service\UserService;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\Asset\Packages;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
@ -15,11 +19,12 @@ use Symfony\Component\Routing\Attribute\Route;
|
||||||
#[Route(path: '/user', name: 'user_')]
|
#[Route(path: '/user', name: 'user_')]
|
||||||
class UserController extends AbstractController
|
class UserController extends AbstractController
|
||||||
{
|
{
|
||||||
private const NOT_FOUND = 'User not found';
|
private const NOT_FOUND = 'Entity not found';
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly UserOrganizationService $userOrganizationService,
|
private readonly UserOrganizationService $userOrganizationService,
|
||||||
private readonly EntityManagerInterface $entityManager,
|
private readonly EntityManagerInterface $entityManager,
|
||||||
private readonly UserService $userService)
|
private readonly UserService $userService)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,23 +204,84 @@ class UserController extends AbstractController
|
||||||
return new Response('Unauthorized', Response::HTTP_UNAUTHORIZED);
|
return new Response('Unauthorized', Response::HTTP_UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
#Route('/organizationsUserEdit/{id}', name: 'organization_user_edit', requirements: ['id' => '\d+'], methods: ['POST'])]
|
/**
|
||||||
public function organizationUserEdit(int $id, Request $request, EntityManagerInterface $entityManager): Response
|
* Update organization user /userOrganizationEdit/{id} - Update organization user
|
||||||
|
* The id parameter is the ID of the UsersOrganizations entity.
|
||||||
|
*/
|
||||||
|
#[Route('/userOrganizationEdit/{id}', name: 'organization_edit', requirements: ['id' => '\d+'], methods: ['GET', 'POST'])]
|
||||||
|
public function userOrganizationEdit(int $id, Request $request, EntityManagerInterface $entityManager, Packages $packages): Response
|
||||||
{
|
{
|
||||||
if (!$this->isGranted('ROLE_SUPER_ADMIN')) {
|
$this->denyAccessUnlessGranted('ROLE_SUPER_ADMIN');
|
||||||
throw $this->createAccessDeniedException('Access denied');
|
|
||||||
|
// get the UsersOrganizations entity by ID and handle not found case same for user
|
||||||
|
$userOrganization = $entityManager->getRepository(UsersOrganizations::class)->find($id);
|
||||||
|
if (!$userOrganization) {
|
||||||
|
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||||
|
}
|
||||||
|
$user = $userOrganization->getUsers() ?? throw $this->createNotFoundException(self::NOT_FOUND);
|
||||||
|
$organization = $userOrganization->getOrganization() ?? throw $this->createNotFoundException(self::NOT_FOUND);
|
||||||
|
|
||||||
|
//Handle the POST
|
||||||
|
if ($request->isMethod('POST')) {
|
||||||
|
// Get the selected roles and apps from the request
|
||||||
|
$selectedRoles = $request->request->all('roles');
|
||||||
|
$selectedApps = $request->request->all('applications');
|
||||||
|
|
||||||
|
// order in important here. apps MUST be before roles
|
||||||
|
$this->userOrganizationService->setUserOrganizationsApps($user, $organization,$selectedApps);
|
||||||
|
$this->userOrganizationService->setUserOrganizations($user, $organization, $selectedRoles);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Redirect to the user profile after successful update
|
||||||
|
return $this->redirectToRoute('user_show', ['id' => $user->getId()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = $entityManager->getRepository(User::class)->find($id);
|
//Overwrite the userOrganization with the userOrganizationsService for data consistency
|
||||||
if (!$user) {
|
// NULL pointer won't occur here because a valid UsersOrganizations entity was fetched above
|
||||||
|
$userOrganization = $this->userOrganizationService->getUserOrganizations($userOrganization->getUsers(), $userOrganization->getOrganization()->getId());
|
||||||
|
|
||||||
|
// Fetch all roles and apps
|
||||||
|
$roles = $entityManager->getRepository(Roles::class)->findAll();
|
||||||
|
$apps = $entityManager->getRepository(Apps::class)->findAll();
|
||||||
|
if (!$roles) {
|
||||||
|
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (!$apps) {
|
||||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle organization user edit logic here
|
// Map roles and apps to arrays for rendering
|
||||||
|
$rolesArray = array_map(static function ($role) {
|
||||||
|
return [
|
||||||
|
'id' => $role->getId(),
|
||||||
|
'name' => $role->getName()
|
||||||
|
];
|
||||||
|
}, $roles);
|
||||||
|
$appsArray = [];
|
||||||
|
foreach ($apps as $app) {
|
||||||
|
$appsArray[] = [
|
||||||
|
'id' => $app->getId(),
|
||||||
|
'name' => $app->getName(),
|
||||||
|
'icon' => $packages->getUrl($app->getLogoUrl()),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return $this->redirectToRoute('user_show', ['id' => $user->getId()]);
|
// Map selected roles and apps to their IDs for the form
|
||||||
|
$selectedRoles = array_map(static function ($role) {
|
||||||
|
return $role->getId();
|
||||||
|
}, $userOrganization[0]["roles"]);
|
||||||
|
$selectedApps = array_map(static function ($app) {
|
||||||
|
return $app->getId();
|
||||||
|
}, $userOrganization[0]["apps"]);
|
||||||
|
|
||||||
|
return $this->render('user/organization/edit.html.twig', [
|
||||||
|
'userOrganization' => $userOrganization,
|
||||||
|
'user' => $user,
|
||||||
|
'rolesArray' => $rolesArray,
|
||||||
|
'selectedRoleIds' => $selectedRoles,
|
||||||
|
'appsArray' => $appsArray,
|
||||||
|
'selectedAppIds' => $selectedApps,]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Form;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
|
||||||
|
class UserOrganization extends AbstractType
|
||||||
|
{
|
||||||
|
|
||||||
|
public function buildForm($builder, array $options): void
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('admin' , CheckboxType::class, [
|
||||||
|
'label' => 'Admin',
|
||||||
|
'required' => false])
|
||||||
|
->add('application' , ChoiceType::class, [
|
||||||
|
'label' => 'Application',
|
||||||
|
'choices' => [
|
||||||
|
'Application 1' => 'app1',
|
||||||
|
'Application 2' => 'app2',
|
||||||
|
'Application 3' => 'app3',
|
||||||
|
]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\UserOrganizationApp;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<UserOrganizationApp>
|
||||||
|
*/
|
||||||
|
class UserOrganizationAppRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, UserOrganizationApp::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return UserOrganizationApp[] Returns an array of UserOrganizationApp objects
|
||||||
|
// */
|
||||||
|
// public function findByExampleField($value): array
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('u')
|
||||||
|
// ->andWhere('u.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->orderBy('u.id', 'ASC')
|
||||||
|
// ->setMaxResults(10)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function findOneBySomeField($value): ?UserOrganizationApp
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('u')
|
||||||
|
// ->andWhere('u.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getOneOrNullResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\UserOrganizationRoles;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<UserOrganizationRoles>
|
||||||
|
*/
|
||||||
|
class UserOrganizationRolesRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, UserOrganizationRoles::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return UserOrganizationRoles[] Returns an array of UserOrganizationRoles objects
|
||||||
|
// */
|
||||||
|
// public function findByExampleField($value): array
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('u')
|
||||||
|
// ->andWhere('u.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->orderBy('u.id', 'ASC')
|
||||||
|
// ->setMaxResults(10)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function findOneBySomeField($value): ?UserOrganizationRoles
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('u')
|
||||||
|
// ->andWhere('u.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getOneOrNullResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace App\Service;
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Entity\Apps;
|
||||||
|
use App\Entity\Organizations;
|
||||||
use App\Entity\Roles;
|
use App\Entity\Roles;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Entity\UsersOrganizations;
|
use App\Entity\UsersOrganizations;
|
||||||
|
|
@ -9,16 +11,19 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
readonly class UserOrganizationService
|
readonly class UserOrganizationService
|
||||||
{
|
{
|
||||||
public function __construct(private readonly EntityManagerInterface $entityManager) {}
|
public function __construct(private readonly EntityManagerInterface $entityManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all organizations the given user belongs to,
|
* Returns all organizations the given user belongs to,
|
||||||
* including the unique roles and apps the user has in each organization.
|
* including the unique roles and apps the user has in each organization.
|
||||||
*
|
*
|
||||||
* @param User $user The user whose organizations are being fetched
|
* @param User $user The user whose organizations are being fetched
|
||||||
|
* @param int|null $organizationsId Optional organization ID to filter by
|
||||||
* @return array<array{organization:object, roles:Roles[], apps:object[]}>
|
* @return array<array{organization:object, roles:Roles[], apps:object[]}>
|
||||||
*/
|
*/
|
||||||
public function getUserOrganizations(User $user): array
|
public function getUserOrganizations(User $user, int $organizationsId = null): array
|
||||||
{
|
{
|
||||||
$userOrganizations = $this->entityManager
|
$userOrganizations = $this->entityManager
|
||||||
->getRepository(UsersOrganizations::class)
|
->getRepository(UsersOrganizations::class)
|
||||||
|
|
@ -28,8 +33,14 @@ readonly class UserOrganizationService
|
||||||
foreach ($userOrganizations as $uo) {
|
foreach ($userOrganizations as $uo) {
|
||||||
$orgId = $uo->getOrganization()->getId();
|
$orgId = $uo->getOrganization()->getId();
|
||||||
|
|
||||||
|
// If $organizationsId is provided, skip other organizations
|
||||||
|
if ($organizationsId !== null && $orgId !== $organizationsId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the organization entry if it doesn't exist
|
// Initialize the organization entry if it doesn't exist
|
||||||
$organizations[$orgId] = $organizations[$orgId] ?? $this->createEmptyOrganizationBucket($uo);
|
$organizations[$orgId] = $organizations[$orgId] ?? $this->createEmptyOrganizationBucket($uo);
|
||||||
|
$organizations[$orgId]['uoId'] = $uo->getId();
|
||||||
|
|
||||||
// Aggregate roles & apps
|
// Aggregate roles & apps
|
||||||
$this->addRole($organizations[$orgId]['roles'], $uo->getRole());
|
$this->addRole($organizations[$orgId]['roles'], $uo->getRole());
|
||||||
|
|
@ -44,23 +55,23 @@ readonly class UserOrganizationService
|
||||||
/**
|
/**
|
||||||
* Build the initial array structure for a fresh organization entry.
|
* Build the initial array structure for a fresh organization entry.
|
||||||
*
|
*
|
||||||
* @param UsersOrganizations $link
|
* @param UsersOrganizations $link
|
||||||
* @return array{organization:object, roles:Roles[], apps:array<int,object>}
|
* @return array{organization:object, roles:Roles[], apps:array<int,object>}
|
||||||
*/
|
*/
|
||||||
private function createEmptyOrganizationBucket(UsersOrganizations $link): array
|
private function createEmptyOrganizationBucket(UsersOrganizations $link): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'organization' => $link->getOrganization(),
|
'organization' => $link->getOrganization(),
|
||||||
'roles' => [],
|
'roles' => [],
|
||||||
'apps' => [],
|
'apps' => [],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a Role entity to the roles array only if it is not already present (by ID).
|
* Add a Role entity to the roles array only if it is not already present (by ID).
|
||||||
*
|
*
|
||||||
* @param Roles[] &$roles
|
* @param Roles[] &$roles
|
||||||
* @param Roles|null $role
|
* @param Roles|null $role
|
||||||
*/
|
*/
|
||||||
private function addRole(array &$roles, ?Roles $role): void
|
private function addRole(array &$roles, ?Roles $role): void
|
||||||
{
|
{
|
||||||
|
|
@ -78,8 +89,8 @@ readonly class UserOrganizationService
|
||||||
/**
|
/**
|
||||||
* Merge one or many apps into the apps map, keeping only one entry per id.
|
* Merge one or many apps into the apps map, keeping only one entry per id.
|
||||||
*
|
*
|
||||||
* @param array<int,object> &$apps
|
* @param array<int,object> &$apps
|
||||||
* @param iterable $appsToAdd Collection returned by $userOrganizations->getApps()
|
* @param iterable $appsToAdd Collection returned by $userOrganizations->getApps()
|
||||||
*/
|
*/
|
||||||
private function addApps(array &$apps, iterable $appsToAdd): void
|
private function addApps(array &$apps, iterable $appsToAdd): void
|
||||||
{
|
{
|
||||||
|
|
@ -92,7 +103,7 @@ readonly class UserOrganizationService
|
||||||
* Convert apps from associative maps (keyed by id) to plain indexed arrays,
|
* Convert apps from associative maps (keyed by id) to plain indexed arrays,
|
||||||
* so the final output is clean JSON-able.
|
* so the final output is clean JSON-able.
|
||||||
*
|
*
|
||||||
* @param array &$organizations
|
* @param array &$organizations
|
||||||
*/
|
*/
|
||||||
private function normalizeAppsIndexes(array &$organizations): void
|
private function normalizeAppsIndexes(array &$organizations): void
|
||||||
{
|
{
|
||||||
|
|
@ -100,4 +111,79 @@ readonly class UserOrganizationService
|
||||||
$org['apps'] = array_values($org['apps']);
|
$org['apps'] = array_values($org['apps']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setUserOrganizations(User $user, Organizations $organization, array $selectedRoles): void
|
||||||
|
{
|
||||||
|
$repo = $this->entityManager->getRepository(UsersOrganizations::class);
|
||||||
|
|
||||||
|
// 1. Get all current UsersOrganizations for this user/org
|
||||||
|
$currentUserOrgs = $repo->findBy([
|
||||||
|
'users' => $user,
|
||||||
|
'organization' => $organization
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 2. Build a map: roleId => UsersOrganizations entity
|
||||||
|
$currentRolesMap = [];
|
||||||
|
foreach ($currentUserOrgs as $uo) {
|
||||||
|
$currentRolesMap[$uo->getRole()->getId()] = $uo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Add new roles that are selected but not present
|
||||||
|
foreach ($selectedRoles as $roleId) {
|
||||||
|
if (!isset($currentRolesMap[$roleId])) {
|
||||||
|
$roleEntity = $this->entityManager->getRepository(Roles::class)->find($roleId);
|
||||||
|
if ($roleEntity) {
|
||||||
|
$newUserOrganization = new UsersOrganizations();
|
||||||
|
$newUserOrganization->setUsers($user);
|
||||||
|
$newUserOrganization->setRole($roleEntity);
|
||||||
|
$newUserOrganization->setOrganization($organization);
|
||||||
|
$this->entityManager->persist($newUserOrganization);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remove from map so we know which ones to delete later
|
||||||
|
unset($currentRolesMap[$roleId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Remove roles that are present but not selected (deactivate them)
|
||||||
|
foreach ($currentRolesMap as $uo) {
|
||||||
|
$uo->setIsActive(false);
|
||||||
|
$this->entityManager->persist($uo);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->entityManager->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUserOrganizationsApps(User $user, Organizations $organization, array $selectedApps)
|
||||||
|
{
|
||||||
|
$apps = [];
|
||||||
|
$userOrganizations = $this->entityManager
|
||||||
|
->getRepository(UsersOrganizations::class)
|
||||||
|
->findAllDistinctOrganizationsByUserId($user->getId());
|
||||||
|
foreach ($userOrganizations as $uo) {
|
||||||
|
$this->addApps($apps, $uo->getApps());
|
||||||
|
}
|
||||||
|
|
||||||
|
$roleUser = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'USER']);
|
||||||
|
$uoEntity = $this->entityManager
|
||||||
|
->getRepository(UsersOrganizations::class)
|
||||||
|
->findOneBy(['users' => $user, 'organization' => $organization, 'role' => $roleUser]);
|
||||||
|
// dd($roleUser);
|
||||||
|
// 1. Remove apps that are no longer selected
|
||||||
|
foreach ($uoEntity->getApps() as $existingApp) {
|
||||||
|
if (!in_array($existingApp->getId(), $selectedApps)) {
|
||||||
|
$uoEntity->removeApp($existingApp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Add newly selected apps (your existing logic)
|
||||||
|
foreach ($selectedApps as $appId) {
|
||||||
|
$appEntity = $this->entityManager->getRepository(Apps::class)->find($appId);
|
||||||
|
if ($appEntity && !$uoEntity->getApps()->contains($appEntity)) {
|
||||||
|
$uoEntity->addApp($appEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->entityManager->persist($uoEntity);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,8 @@
|
||||||
"assets/bootstrap.js",
|
"assets/bootstrap.js",
|
||||||
"assets/controllers.json",
|
"assets/controllers.json",
|
||||||
"assets/controllers/csrf_protection_controller.js",
|
"assets/controllers/csrf_protection_controller.js",
|
||||||
"assets/controllers/hello_controller.js"
|
"assets/controllers/hello_controller.js",
|
||||||
|
"assets/controllers/igg_controller.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"symfony/translation": {
|
"symfony/translation": {
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,21 @@
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|
||||||
|
|
||||||
<div class="card col-4 mt-3 me-3 user-org-card" style="cursor:pointer;" data-bs-toggle="collapse"
|
<div class="card col-4 mt-3 me-3" >
|
||||||
data-bs-target="#org-details-{{ organization.id }}" aria-expanded="false"
|
<div class="card-title shadow-sm p-3 d-flex justify-content-between align-items-center">
|
||||||
aria-controls="org-details-{{ organization.id }}">
|
{# Affichage du nom de l'organisation et de l'icône de flèche #}
|
||||||
<div class="card-title shadow-sm p-3 ">
|
<div class="d-flex user-org-card"
|
||||||
<div class="d-flex ">
|
style="cursor:pointer;" data-bs-toggle="collapse"
|
||||||
|
data-bs-target="#org-details-{{ organization.id }}" aria-expanded="false"
|
||||||
|
aria-controls="org-details-{{ organization.id }}">
|
||||||
<h2 class=" pe-2">{{ organization.name|capitalize }}</h2>
|
<h2 class=" pe-2">{{ organization.name|capitalize }}</h2>
|
||||||
<i class="pt-2" id="arrow-icon-{{ organization.id }}">
|
<i class="pt-2" id="arrow-icon-{{ organization.id }}">
|
||||||
{{ ux_icon('fa6-regular:circle-down', {height: '25px', width: '25px'}) }}
|
{{ ux_icon('fa6-regular:circle-down', {height: '25px', width: '25px'}) }}
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
{# <a href="{{ path('user_organization_edit', {'id': user.id}) }}" class="btn btn-primary">Modifier</a>#}
|
{% if is_granted("ROLE_ADMIN") %}
|
||||||
|
<a href="{{ path('user_organization_edit', {'id': uoId}) }}" class="btn btn-primary" >Modifier</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Information principale sur l'utilisateur dans l'organisation#}
|
{# Information principale sur l'utilisateur dans l'organisation#}
|
||||||
|
|
@ -35,10 +38,7 @@
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
{% if apps is not empty %}
|
{% if apps is not empty %}
|
||||||
{% for app in apps %}
|
{% for app in apps %}
|
||||||
<div class="col">
|
<img src="{{ asset(app.logoUrl) }}" alt="Logo {{ app.name }}" class="img-fluid ms-2" style="height: 30px; width: 30px;">
|
||||||
{{ app.name }}
|
|
||||||
<img src="{{ asset(app.logoUrl) }}" alt="Logo {{ app.name }}" class="img-fluid ms-2" style="height: 20px; width: 20px;">
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
Aucune application associée.
|
Aucune application associée.
|
||||||
|
|
@ -79,6 +79,7 @@
|
||||||
arrowEl.innerHTML = `{{ ux_icon('fa6-regular:circle-down', {height: '25px', width: '25px'})|e('js') }}`;
|
arrowEl.innerHTML = `{{ ux_icon('fa6-regular:circle-down', {height: '25px', width: '25px'})|e('js') }}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
{% block title %}User Profile{% endblock %}
|
{% block title %}User Profile{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="w-100 h-100 p-5 m-auto ">
|
<div class="w-100 h-100 p-5 m-auto " data-controller="user">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<h1>Gestion Utilisateurs</h1>
|
<h1>Gestion Utilisateurs</h1>
|
||||||
<a href="{{ path('user_new') }}" class="btn btn-primary">Ajouter un utilisateur</a>
|
<a href="{{ path('user_new') }}" class="btn btn-primary">Ajouter un utilisateur</a>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
<div class="col-md-10 m-auto p-5">
|
||||||
|
<div class="card">
|
||||||
|
{% for uo in userOrganization %}
|
||||||
|
<div class="card-title shadow-sm p-3 d-flex justify-content-between align-items-center">
|
||||||
|
<h3>
|
||||||
|
Modification de : <b>{{ user.name|capitalize }} {{ user.surname|capitalize }} </b> chez
|
||||||
|
<b> {{ uo.organization.name }}</b>
|
||||||
|
</h3>
|
||||||
|
<a href="{{ path('user_delete', {'id': user.id}) }}" class="btn btn-danger">Supprimer</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="POST" action="{{ path('user_organization_edit', {'id': 4}) }}"
|
||||||
|
data-controller="user"
|
||||||
|
data-user-roles-array-value="{{ rolesArray|json_encode }}"
|
||||||
|
data-user-selected-role-ids-value="{{ selectedRoleIds|json_encode }}"
|
||||||
|
data-user-applications-array-value="{{ appsArray|json_encode }}"
|
||||||
|
data-user-selected-application-ids-value="{{ selectedAppIds|json_encode }}">
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="form-group mb-3">
|
||||||
|
<label for="roles">Roles</label>
|
||||||
|
<select class="choices" data-type="select-multiple" id="roles" name="roles[]" multiple>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group mb-3">
|
||||||
|
<label for="applications">Applications</label>
|
||||||
|
<select class="choices" data-type="select-multiple" id="applications" name="applications[]"
|
||||||
|
multiple>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{# bouton d'envoie du formulaire#}
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">Modifier</button>
|
||||||
|
{# <a href="{{ path('user_organization_list') }}" class="btn btn-secondary">Annuler</a>#}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
{% for organization in userOrganizations %}
|
{% for organization in userOrganizations %}
|
||||||
{% include 'elements/userOrganizationInformation.html.twig'
|
{% include 'elements/userOrganizationInformation.html.twig'
|
||||||
with {'organization': organization.organization, 'roles': organization.roles, 'apps': organization.apps} %}
|
with {'organization': organization.organization, 'roles': organization.roles, 'apps': organization.apps, 'uoId': organization.uoId} %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue