Skip to content

Commit

Permalink
add user on partner #3308
Browse files Browse the repository at this point in the history
  • Loading branch information
numew committed Jan 16, 2025
1 parent b7136ef commit 1d7b17e
Show file tree
Hide file tree
Showing 27 changed files with 854 additions and 138 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ CLAMAV_SCAN_ENABLE=1
HISTORY_TRACKING_ENABLE=1
DELAY_MIN_CHECK_NEW_SIGNALEMENT_FILES=30 #minutes
ALBERT_API_KEY=
FEATURE_MULTI_TERRITORIES=0
### histologe ###

### object storage S3 ###
Expand Down
1 change: 1 addition & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ CLAMAV_STRATEGY=clamd_unix
CLAMAV_SCAN_ENABLE=1
DELAY_MIN_CHECK_NEW_SIGNALEMENT_FILES=30 #minutes
ALBERT_API_KEY=
FEATURE_MULTI_TERRITORIES=1
###> knplabs/knp-snappy-bundle ###
WKHTMLTOPDF_PATH=wkhtmltopdf
WKHTMLTOIMAGE_PATH=wkhtmltoimage
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ env:
CLAMAV_SOCKET: '/tmp/clamd.socket'
CLAMAV_HOST: 127.0.0.1
CLAMAV_PORT: 3310
FEATURE_MULTI_TERRITORIES: 1
jobs:
code-quality:
name: Histologe (PHP ${{ matrix.php-versions }})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ function histoUpdatePermissionsFromRole (editOrCreate, toggleValue) {
if (!elementTogglePermissionAffectation || !elementTextPermissionAffectation) {
return
}
const rolesSelect = document.querySelector('#user_' + editOrCreate + '_roles')
let rolesSelect = null
if(editOrCreate === 'partner'){
rolesSelect = document.querySelector('#user_partner_role')
}else{
rolesSelect = document.querySelector('#user_' + editOrCreate + '_roles')
}
if (rolesSelect.value === 'ROLE_ADMIN' || rolesSelect.value === 'ROLE_ADMIN_TERRITORY') {
if (!elementTogglePermissionAffectation.checked) {
elementTogglePermissionAffectation.click()
Expand Down Expand Up @@ -234,6 +239,7 @@ deletePartnerForm.forEach(form => {
})
})

//TODO : delete with feature_multi_territories deletion
const checkUserMail = (el) => {
const formData = new FormData()
formData.append('email', el.value)
Expand Down Expand Up @@ -275,9 +281,57 @@ emailInputs.forEach(emailInput => {
checkUserMail(this)
})
})
//END TODO

loadWindowWithLocalStorage('click', '[data-filter-list-partner]', 'search-partner-form')
updateLocalStorageOnEvent('input', '#partner-input', 'back_link_partners')
updateLocalStorageOnEvent('change', '#partner-filters-territories', 'back_link_partners')
updateLocalStorageOnEvent('change', '#partner-filters-types', 'back_link_partners')
updateLocalStorageWithPaginationParams('click', '#partner-pagination a', 'back_link_partners')

//add for multi territories
const modalPartnerUserCreate = document?.querySelector('#fr-modal-user-create')
const btnSubmit = modalPartnerUserCreate?.querySelector('button[type="submit"]')
if(modalPartnerUserCreate){
modalPartnerUserCreate.addEventListener('dsfr.conceal', (event) => {
const refreshUrl = event.target.dataset.refreshUrl;
btnSubmit.disabled = true
fetch(refreshUrl).then(response => {
managePartnerAddUserFormResponse(response)
})
})
}

function attachSubmitPartnerAddUserForm () {
document.querySelector('#partner-add-user-form').addEventListener('submit', (e) => {
e.preventDefault()
btnSubmit.disabled = true
const formData = new FormData(e.target)
fetch(e.target.action, {method: 'POST', body: formData}).then(response => {
managePartnerAddUserFormResponse(response)
})
})
}

function managePartnerAddUserFormResponse(response) {
console.log(response);
if (response.redirected) {
window.location.href = response.url
}else if (response.ok) {
response.json().then((response) => {
document.querySelector('#partner-add-user-title').innerHTML = response.title
document.querySelector('#partner-add-user-form-container').innerHTML = response.content
attachSubmitPartnerAddUserForm()
if (document.querySelector('#user_partner_role')) {
document.querySelector('#user_partner_role').addEventListener('change', () => {
histoUpdatePermissionsFromRole('partner', null)
})
histoUpdatePermissionsFromRole('partner', null)
}
btnSubmit.disabled = false
})
}else{
const content = '<div class="fr-alert fr-alert--error" role="alert"><p class="fr-alert__title">Erreur</p><p>Une erreur est survenue veuillez fermer cette fenêtre.</p></div>'
document.querySelector('#partner-add-user-form-container').innerHTML = content
}
}
1 change: 1 addition & 0 deletions config/packages/twig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ twig:
banner_message: '%maintenance_banner_message%'
enable: '%maintenance_enable%'
mise_en_berne: '%env(FEATURE_MISE_EN_BERNE)%'
feature_multi_territories: '%env(bool:FEATURE_MULTI_TERRITORIES)%'
paths:
# point this wherever your images live
'%kernel.project_dir%/public/img': images
Expand Down
1 change: 1 addition & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ parameters:
delay_min_check_new_signalement_files: '%env(DELAY_MIN_CHECK_NEW_SIGNALEMENT_FILES)%'
albert_api_key: '%env(ALBERT_API_KEY)%'
standard_max_list_pagination: 50
feature_multi_territories: '%env(bool:FEATURE_MULTI_TERRITORIES)%'

services:
# default configuration for services in *this* file
Expand Down
139 changes: 137 additions & 2 deletions src/Controller/Back/PartnerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use App\Form\PartnerPerimetreType;
use App\Form\PartnerType;
use App\Form\SearchPartnerType;
use App\Form\UserPartnerEmailType;
use App\Form\UserPartnerType;
use App\Manager\AffectationManager;
use App\Manager\InterventionManager;
use App\Manager\PartnerManager;
Expand All @@ -32,9 +34,12 @@
use App\Validator\EmailFormatValidator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
Expand All @@ -46,6 +51,12 @@
#[Route('/bo/partenaires')]
class PartnerController extends AbstractController
{
public function __construct(
#[Autowire(env: 'FEATURE_MULTI_TERRITORIES')]
private readonly bool $featureMultiTerritories,
) {
}

#[Route('/', name: 'back_partner_index', methods: ['GET', 'POST'])]
#[IsGranted('ROLE_ADMIN_TERRITORY')]
public function index(
Expand Down Expand Up @@ -331,6 +342,94 @@ private function cancelOrReplanVisites(
}
}

#[Route('/{id}/add-user-multi', name: 'back_partner_add_user_multi', methods: ['POST'])]
#[IsGranted('ROLE_ADMIN_PARTNER')]
public function addUserPartnerMulti(
Request $request,
Partner $partner,
UserRepository $userRepository,
UserManager $userManager,
NotificationMailerRegistry $notificationMailerRegistry,
): JsonResponse|RedirectResponse {
if (!$this->featureMultiTerritories) {
throw $this->createNotFoundException();
}
$this->denyAccessUnlessGranted('USER_CREATE', $partner);
$userTmp = new User();
$userPartner = (new UserPartner())->setUser($userTmp)->setPartner($partner);
$userTmp->addUserPartner($userPartner);
$checkMailRoute = $this->generateUrl('back_partner_add_user_email', ['id' => $partner->getId()]);
$formMultiMail = $this->createForm(UserPartnerEmailType::class, $userTmp, ['action' => $checkMailRoute]);
$formMultiMail->handleRequest($request);
if ($formMultiMail->isSubmitted() && $formMultiMail->isValid()) {
$user = $userRepository->findAgentByEmail($userTmp->getEmail());
if ($user) {
$userPartner->setUser($user);
$userManager->save($userPartner);
$notificationMailerRegistry->send(
new NotificationMail(
type: NotificationMailerType::TYPE_ACCOUNT_NEW_TERRITORY,
to: $user->getEmail(),
user: $user,
territory: $partner->getTerritory(),
params: ['partner_name' => $partner->getNom()]
)
);
$message = 'L\'utilisateur a bien été créé. Un e-mail de confirmation a été envoyé à '.$user->getEmail();
$this->addFlash('success', $message);

return $this->redirectToRoute('back_partner_view', ['id' => $partner->getId(), '_fragment' => 'agents']);
}
$formMultiMail->get('email')->addError(new FormError('Agent introuvalbe avec cette adresse e-mail.'));
}
$content = $this->renderView('_partials/_modal_user_create_email.html.twig', ['formCheckMail' => $formMultiMail]);

return $this->json(['content' => $content, 'title' => 'Ajouter un utilisateur']);
}

#[Route('/{id}/add-user', name: 'back_partner_add_user', methods: ['POST'])]
#[IsGranted('ROLE_ADMIN_PARTNER')]
public function addUserPartner(
Request $request,
Partner $partner,
UserManager $userManager,
): JsonResponse|RedirectResponse {
if (!$this->featureMultiTerritories) {
throw $this->createNotFoundException();
}
$this->denyAccessUnlessGranted('USER_CREATE', $partner);
$user = new User();
$userPartner = (new UserPartner())->setUser($user)->setPartner($partner);
$user->addUserPartner($userPartner);
$addUserRoute = $this->generateUrl('back_partner_add_user', ['id' => $partner->getId()]);
$formUserPartner = $this->createForm(UserPartnerType::class, $user, ['action' => $addUserRoute]);
$formUserPartner->handleRequest($request);
if ($formUserPartner->isSubmitted() && $formUserPartner->isValid()) {
$userExist = $userManager->findOneBy(['email' => $user->getEmail()]);
if ($userExist && !\in_array('ROLE_USAGER', $userExist->getRoles())) {
$addUserOnPartnerRoute = $this->generateUrl('back_partner_add_user_multi', ['id' => $partner->getId()]);
$formMultiMail = $this->createForm(UserPartnerEmailType::class, $user, ['action' => $addUserOnPartnerRoute]);
$content = $this->renderView('_partials/_modal_user_create_multi.html.twig', ['formMultiMail' => $formMultiMail, 'user' => $userExist, 'partner' => $partner]);

return $this->json(['content' => $content, 'title' => 'Compte existant sur un autre territoire']);
}
if ($userExist) {
$user->setStatut(User::STATUS_INACTIVE);
}
$user->setRoles([$formUserPartner->get('role')->getData()]);
$userManager->persist($userPartner);
$userManager->save($user);
$message = 'L\'utilisateur a bien été créé. Un e-mail de confirmation a été envoyé à '.$user->getEmail();
$this->addFlash('success', $message);

return $this->redirectToRoute('back_partner_view', ['id' => $partner->getId(), '_fragment' => 'agents']);
}
$content = $this->renderView('_partials/_modal_user_create_form.html.twig', ['formUserPartner' => $formUserPartner]);

return $this->json(['content' => $content, 'title' => 'Ajouter un utilisateur']);
}

// TODO : delete with feature_multi_territories deletion
#[Route('/{id}/ajoututilisateur', name: 'back_partner_user_add', methods: ['POST'])]
public function addUser(
Request $request,
Expand All @@ -340,6 +439,9 @@ public function addUser(
PartnerRepository $partnerRepository,
ValidatorInterface $validator,
): Response {
if ($this->featureMultiTerritories) {
throw $this->createNotFoundException();
}
$this->denyAccessUnlessGranted('USER_CREATE', $partner);
$data = $request->get('user_create');
if (!$this->isCsrfTokenValid('partner_user_create', $request->request->get('_token'))) {
Expand Down Expand Up @@ -593,12 +695,45 @@ public function deleteUser(
return $this->redirectToRoute('back_partner_view', ['id' => $partner->getId()], Response::HTTP_SEE_OTHER);
}

#[Route('/checkmail', name: 'back_partner_check_user_email', methods: ['POST'])]
#[Route('/{id}/add-user-email', name: 'back_partner_add_user_email')]
#[IsGranted('ROLE_ADMIN_PARTNER')]
public function checkMail(
public function addUserEmail(
Request $request,
Partner $partner,
UserRepository $userRepository,
): Response {
$this->denyAccessUnlessGranted('USER_CREATE', $partner);
$user = new User();
$user->setIsMailingActive(true);
$user->addUserPartner((new UserPartner())->setUser($user)->setPartner($partner));
$checkMailRoute = $this->generateUrl('back_partner_add_user_email', ['id' => $partner->getId()]);
$formCheckMail = $this->createForm(UserPartnerEmailType::class, $user, ['action' => $checkMailRoute]);
$formCheckMail->handleRequest($request);
if ($formCheckMail->isSubmitted() && $formCheckMail->isValid()) {
$userExist = $userRepository->findAgentByEmail($user->getEmail());
if ($userExist) {
$addUserOnPartnerRoute = $this->generateUrl('back_partner_add_user_multi', ['id' => $partner->getId()]);
$formMultiMail = $this->createForm(UserPartnerEmailType::class, $user, ['action' => $addUserOnPartnerRoute]);
$content = $this->renderView('_partials/_modal_user_create_multi.html.twig', ['formMultiMail' => $formMultiMail, 'user' => $userExist, 'partner' => $partner]);

return $this->json(['content' => $content, 'title' => 'Compte existant sur un autre territoire']);
}
$addUserRoute = $this->generateUrl('back_partner_add_user', ['id' => $partner->getId()]);
$formUserPartner = $this->createForm(UserPartnerType::class, $user, ['action' => $addUserRoute]);
$content = $this->renderView('_partials/_modal_user_create_form.html.twig', ['formUserPartner' => $formUserPartner]);

return $this->json(['content' => $content, 'title' => 'Ajouter un utilisateur']);
}
$content = $this->renderView('_partials/_modal_user_create_email.html.twig', ['formCheckMail' => $formCheckMail]);

return $this->json(['content' => $content, 'title' => 'Ajouter un utilisateur']);
}

// TODO : delete with feature_multi_territories deletion
#[Route('/checkmail', name: 'back_partner_check_user_email', methods: ['POST'])]
#[IsGranted('ROLE_ADMIN_PARTNER')]
public function checkMail(Request $request, UserRepository $userRepository): Response
{
if ($this->isCsrfTokenValid('partner_checkmail', $request->request->get('_token'))) {
$userExist = $userRepository->findOneBy(['email' => $request->get('email')]);
if (
Expand Down
9 changes: 9 additions & 0 deletions src/DataFixtures/Files/User.yml
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,15 @@ users:
statut: 1
is_generique: 0
is_mailing_active: 1
-
email: [email protected]
roles: "[\"ROLE_USER_PARTNER\"]"
partners:
- "CAF 30"
statut: 1
is_generique: 0
is_mailing_active: 1
has_permission_affectation: 1
-
email: [email protected]
roles: "[\"ROLE_ADMIN_TERRITORY\"]"
Expand Down
4 changes: 4 additions & 0 deletions src/DataFixtures/Loader/LoadUserData.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ private function loadUsers(ObjectManager $manager, array $row): void
->setPrenom($faker->firstName())
->setNom($faker->lastName());

if (isset($row['has_permission_affectation'])) {
$user->setHasPermissionAffectation($row['has_permission_affectation']);
}

if (User::STATUS_ARCHIVE === $row['statut']) {
$user->setEmail(Sanitizer::tagArchivedEmail($row['email']));
} else {
Expand Down
12 changes: 7 additions & 5 deletions src/Entity/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use App\Entity\Behaviour\TimestampableTrait;
use App\Entity\Enum\HistoryEntryEvent;
use App\Repository\UserRepository;
use App\Validator as AppAssert;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
Expand All @@ -22,6 +23,7 @@
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[UniqueEntity('email', message: '{{ value }} existe déja, merci de saisir un nouvel e-mail')]
#[ORM\HasLifecycleCallbacks()]
#[AppAssert\UserPartnerEmail(groups: ['user_partner_mail'])]
class User implements UserInterface, EntityHistoryInterface, PasswordAuthenticatedUserInterface, TwoFactorInterface
{
use TimestampableTrait;
Expand Down Expand Up @@ -68,7 +70,7 @@ class User implements UserInterface, EntityHistoryInterface, PasswordAuthenticat
#[ORM\Column(type: 'string', length: 180, unique: false)]
#[Email(mode: Email::VALIDATION_MODE_STRICT, groups: ['registration'])]
#[Assert\NotBlank(message: 'Merci de saisir une adresse e-mail.')]
#[Assert\Length(max: 255)]
#[Assert\Length(max: 255, groups: ['user_partner', 'Default'])]
private $email;

#[ORM\Column(type: 'json')]
Expand Down Expand Up @@ -107,13 +109,13 @@ class User implements UserInterface, EntityHistoryInterface, PasswordAuthenticat
private $partner; // @phpstan-ignore-line

#[ORM\Column(type: 'string', length: 255, nullable: true)]
#[Assert\NotBlank(message: 'Merci de saisir un nom.')]
#[Assert\Length(max: 255)]
#[Assert\NotBlank(message: 'Merci de saisir un nom.', groups: ['user_partner', 'Default'])]
#[Assert\Length(max: 255, groups: ['user_partner', 'Default'])]
private $nom;

#[ORM\Column(type: 'string', length: 255, nullable: true)]
#[Assert\NotBlank(message: 'Merci de saisir un prénom.')]
#[Assert\Length(max: 255)]
#[Assert\NotBlank(message: 'Merci de saisir un prénom.', groups: ['user_partner', 'Default'])]
#[Assert\Length(max: 255, groups: ['user_partner', 'Default'])]
private $prenom;

#[ORM\Column(type: 'integer')]
Expand Down
Loading

0 comments on commit 1d7b17e

Please sign in to comment.