<?php
namespace App\Controller\admin;
use App\Entity\Company;
use App\Entity\FormationRegistration;
use App\Entity\Log;
use App\Entity\Role;
use App\Entity\User;
use App\Entity\UserActivity;
use App\Events\Events;
use App\Form\UserType;
use App\Security\Voter\CompanyVoter;
use App\Service\completion\CompletionService;
use App\Service\datatable\Builder;
use App\Service\profile\ProfileService;
use App\Service\subscription\SubscriptionService;
use Doctrine\Persistence\ManagerRegistry;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class UserController extends AbstractController
{
private ManagerRegistry $managerRegistry;
public function __construct(ManagerRegistry $managerRegistry)
{
$this->managerRegistry = $managerRegistry;
}
/**
* @param Request $request
* @Security("is_granted('ROLE_RH')")
* @Route("/api/subscription/users", name="subscription-users", methods={"POST"})
*/
public function fetchUsers(Request $request, ManagerRegistry $managerRegistry){
$companyID = $request->request->get('ID');
$company = $managerRegistry->getRepository(Company::class)->find($companyID);
/* @see CompanyVoter */
$this->denyAccessUnlessGranted(CompanyVoter::COMPANY_SHOW,$company);
if(!$company) {
return new JsonResponse("ko",400);
}
$dt_ajax_url = $this->generateUrl('dt-users', ['company' => $company->getId()]);
$content = $this->renderView('pages/admin/company/blocks/company.users.html.twig',[
"company"=>$company,
"users_count"=>$company->getUsers()->count(),
"dt_url"=>$dt_ajax_url,
'context'=> 'users'
]);
$actions = $this->renderView('pages/admin/company/blocks/tab.actions.html.twig',[
'context'=> 'users',
"users_count"=>$company->getUsers()->count(),
'company' => $company
]);
return new JsonResponse(["content"=>$content,"actions"=>$actions]);
}
/**
* @param Request $request
* @Security("is_granted('ROLE_RH')")
* @Route("/api/subscription/user", name="subscription-show-user", methods={"POST"})
*/
public function fetchUser(Request $request, ManagerRegistry $managerRegistry,CompletionService $completionService,ProfileService $profileService){
$ID = $request->request->get('ID');
$user = $managerRegistry->getRepository(User::class)->find($ID);
/* @see CompanyVoter */
$this->denyAccessUnlessGranted(CompanyVoter::USER_EDIT,$user);
if(!$user) {
return new JsonResponse("ko",400);
}
$proCompletion = $completionService->getProfessional($user);
$privateCompletion = $completionService->getPrivate($user);
$userProActivities = $profileService->transformProActivitiesForRead($user);
$privateActivities = $profileService->transformPrivateActivitiesForRead($user);
//Stats visio
$logs = $this->managerRegistry->getRepository(Log::class)->getHistory($user, Events::VIDEO_COMPLETE);
$loginHistory = $this->managerRegistry->getRepository(Log::class)->getLoginHistory($user);
// if (!$this->isGranted('ROLE_ADMIN')){
// //VIDEOS only CAT === ERGO
// $logs = array_filter($logs, function ($log) {
// return isset($log['sources']['feedData']) && $log['sources']['feedData']['CAT'] === 'ERGO';
// });
// }
//FORMATION
if( $this->isGranted('ROLE_ADMIN') ){
$formations = $this->managerRegistry->getRepository(FormationRegistration::class)->getAllFormationViewed($user);
}
//si j suis gestionnaire > on retire les formations qui ne m'appartiennent pas
else{
$formations = $this->managerRegistry->getRepository(FormationRegistration::class)->getAllFormationViewed($user,true);
}
$content = $this->renderView('pages/admin/user/show.user.html.twig',[
"user"=>$user,
"proCompletion"=>$proCompletion,
"privateCompletion"=>$privateCompletion,
"proActivities" => $userProActivities,
"privateActivities" => $privateActivities,
"history_visio"=>$logs,
"loginHistory"=>$loginHistory,
"formations"=>$formations,
'context'=> 'users'
]);
return new JsonResponse(["content"=>$content]);
}
/**
* RH OR ADMIN add users
* @param Request $request
* @Security("is_granted('ROLE_RH')")
* @Route("/admin/subscription/{slug}/add-users", name="admin-add-users")
* @ParamConverter("company", options={"mapping": {"slug": "slug"}})
*/
public function addUsers(Request $request, Company $company, EventDispatcherInterface $eventDispatcher,
ValidatorInterface $validator,SubscriptionService $subscriptionService)
{
/* @see CompanyVoter */
$this->denyAccessUnlessGranted(CompanyVoter::COMPANY_SHOW,$company);
/* @var $currentUser User*/
$currentUser = $this->getUser();
$hasErrors = false;
if($request->isMethod('POST')){
$em = $this->managerRegistry->getManager();
$data = $request->request->all();
//retire les lignes vides du formulaire
$allData = array_filter($data,function ($v,$k){
return $v && $v !== "";
},ARRAY_FILTER_USE_BOTH);
//Group data by user
$usersToSave=[];
foreach ($allData as $k => $v){
list($entity,$field,$index) = explode("_",$k);
if(!isset( $usersToSave[$index]) && empty($usersToSave[$index])){
$usersToSave[$index] = [];
}
$usersToSave[$index][$field] = $v;
}
$entityUserSaved=[];
foreach ($usersToSave as &$user){
$_user = new User();
if (in_array($user['role'], User::getAssignableRoleNames(), true)) {
$user_role =$em->getRepository(Role::class)->findOneBy(['name' => $user['role']]);
}
else{
$user_role =$em->getRepository(Role::class)->findOneBy(['name' => User::ROLE_USER_ACTIF]);
}
$_user->setRoles($user_role);
$_user->setEmail(trim($user['email']));
$_user->setLastname(trim($user['lastname']));
$_user->setFirstname(trim($user['firstname']));
if(isset($user['contact']) && $user['contact'] === "on"){
$_user->setIsContact(1);
}
else{
$_user->setIsContact(0);
}
$_user->setCompany($company);
$_errors = $validator->validate($_user);
if($_errors->count() > 0){
$hasErrors = true;
$user['errors'] = $_errors;
}
if($_errors->count() === 0){
$em->persist($_user);
//save user entities for emails
array_push($entityUserSaved,$_user);
}
}
if($subscriptionService->checkUserLimitReached($company,sizeof($usersToSave))){
$hasErrors = true;
$this->addFlash('notice-warning','Vous avez utilisé toutes vos licences ! Contactez votre administrateur pour en ajouter.');
}
if (!$hasErrors){
$em->flush();
if(sizeof($usersToSave) > 1){
$this->addFlash('notice-success',sprintf('%d utilisateurs ont été ajoutés',sizeof($usersToSave)));
}
else if(sizeof($usersToSave) === 1){
$this->addFlash('notice-success',sprintf('%d utilisateur a été ajouté',1));
}
//send email
foreach ($entityUserSaved as $userSaved){
/*Notify user by email*/
$event = new GenericEvent($userSaved);
$eventDispatcher->dispatch($event, Events::EMAIL_NEW_ACCOUNT);
}
return $this->redirectToRoute('admin-subscription-company',['slug'=>$company->getSlug(),'tab'=>'users']);
}
}
return $this->render('pages/admin/user/add.users.html.twig', [
'title_page' => $currentUser->hasRole('ROLE_RH') ? 'Mon établissement' : 'Abonnements',
'company'=> $company,
'user_data' => ( isset($usersToSave) && $hasErrors )? $usersToSave : null
]);
}
/**
* @param Request $request
* @Security("is_granted('ROLE_RH') or is_granted('ROLE_ADMIN')")
* @Route("/admin/user/{user}", name="admin-update-user")
*/
public function updateUser(Request $request, User $user, TokenStorageInterface $tokenStorage)
{
/* @see CompanyVoter */
$this->denyAccessUnlessGranted(CompanyVoter::USER_EDIT,$user);
/** @var User $connectedUser */
$connectedUser = $this->getUser();
$editingSelf = $connectedUser->getId() === $user->getId();
$previousRole = $user->getRoles()[0] ?? null;
// Les choix dépendent du compte connecté ; la valeur initiale appartient au compte modifié.
$personal_form = $this->createForm(UserType::class, $user, [
'current_role' => $previousRole,
'actor_role' => $connectedUser->getRoles()[0] ?? null,
]);
// $personal_form->remove('birth')->remove('gender');
if (!$this->isGranted('ROLE_RH')) {
$personal_form->remove('role');
}
$personal_form->handleRequest($request);
if ($personal_form->isSubmitted() && $personal_form->isValid()) {
$em = $this->managerRegistry->getManager();
$em->persist($user);
$em->flush();
// Renouveler uniquement la session du compte connecté après la sauvegarde.
if ($editingSelf && $previousRole !== $user->getRole()->getName()) {
$connectedUser->setRoles($user->getRole());
$tokenStorage->setToken(new PostAuthenticationGuardToken($connectedUser, 'main', $connectedUser->getRoles()));
}
$this->addFlash('notice-success', 'L\' utilisateur a bien été modifié');
if ($editingSelf && $user->isStandardUser()) {
return $this->redirectToRoute('user_dashboard');
}
return $this->redirectToRoute('admin-subscription-company',['slug'=>$user->getCompany()->getSlug(),"tab"=>"users"]);
}
return $this->render('pages/admin/user/user.html.twig', [
'title_page' => 'Utilisateurs',
'personal_form' => $personal_form->createView(),
'current_user' => $user,
'context' => "update",
'company' => $user->getCompany()
]);
}
/*AJAX*/
/**
* Alimente la datatable
* @param Request $request
* @Security("is_granted('ROLE_RH') or is_granted('ROLE_ADMIN')")
* @Route("/api/dt/company/users/{company}", name="dt-users", methods={"GET"})
* @return JsonResponse
*/
public function dtCompanyUsers(Request $request, Company $company, Builder $dtBuilder, CompletionService $completionService)
{
$em = $this->managerRegistry->getManager();
$params = $request->query->all();
$roles = User::getStandardAndManagerRoleNames();
if ($this->isGranted(User::ROLE_ADMIN)) {
$roles[] = User::ROLE_ADMIN;
}
$query = $em->getRepository(User::class)->getQueryUsers($roles, $company->getId());
$columns=[
'id' => 'u.id',
'contact'=>'u.isContact',
'lastname' => 'u.lastname',
'firstname' => 'u.firstname',
'email' => 'u.email',
'role' => 'r.name',
'lastLoginAt' => 'u.lastLoginAt',
'updatedAt' => 'u.updatedAt',
];
$dataTables = $dtBuilder
->withColumnAliases($columns)
->withIndexColumn('u.id')
->withQueryBuilder($query)
->withRequestParams($params);
$data = $dataTables->getResponse();
foreach ($data['data'] as &$d){
$user = $this->managerRegistry->getRepository(User::class)->find($d["id"]);
$d['profile'] = $completionService->getTotalUserCompletionRate($user);
}
return new JsonResponse($data);
}
/**
* check user limit process
* @param Request $request
* @Security("is_granted('ROLE_RH') or is_granted('ROLE_ADMIN')")
* @Route("/api/subscription/check-user-limit", name="check-user-limit", methods={"POST"})
* @return JsonResponse
*/
public function checkUserLimit(Request $request,SubscriptionService $subscriptionService){
$ID = $request->request->get('ID');
$comp = $this->managerRegistry->getRepository(Company::class)->find($ID);
$userLimitReached = $subscriptionService->checkUserLimitReached($comp,1);
if($userLimitReached){
return new JsonResponse(0,200);
}
return new JsonResponse(1,200);
}
/**
* send invitation for given users
* @param Request $request
* @Security("is_granted('ROLE_RH') or is_granted('ROLE_ADMIN')")
* @Route("/api/user/send-invitation", name="send-invitation", methods={"POST"})
* @return JsonResponse
*/
public function sendInvitation(Request $request,EventDispatcherInterface $eventDispatcher,CompletionService $completionService){
$ids = $request->request->has('ids') ? $request->request->get('ids') : null;
$companyId = $request->request->has('company') ? $request->request->get('company') : null;
$context = $request->request->has('context') ? $request->request->get('context') : null;
$mode = $request->request->has('mode') ? $request->request->get('mode') : 'exec';
$em = $this->managerRegistry->getManager();
//selection utilisateurs dans datatable
if ($ids and !empty($ids)) {
$users = $em->getRepository(User::class)->findBy(['id' => $ids]);
foreach ($users as $user) {
/*Notify user by email*/
$event = new GenericEvent($user);
$eventDispatcher->dispatch($event, Events::NEW_ACCOUNT_RELANCE);
}
}
//Action globale de recherche des utilisateurs
else if($ids === null && $companyId){
try{
$company = $em->getRepository(Company::class)->find($companyId);
if(!$company) return new JsonResponse('Company error',500);
if($context === 'connection'){
$users = $em->getRepository(User::class)->findBy(['password'=>null,'company'=>$company]);
if($mode === 'dry'){
return new JsonResponse([
'users'=>sizeof($users)
]);
}
else{
foreach ($users as $user) {
/*Notify user by email*/
$event = new GenericEvent($user);
$eventDispatcher->dispatch($event, Events::NEW_ACCOUNT_RELANCE);
}
}
}
else if($context === 'completion'){
$users = $em->getRepository(User::class)->findUsersRegistered($company);
$count = $completionService->findUsersCompletionLessThan($users,$mode);
return new JsonResponse([
'users'=>$count
]);
}
else{
return new JsonResponse('Context error',500);
}
}
catch (\Exception $e){
return new JsonResponse($e->getMessage(),500);
}
}
return new JsonResponse('ok');
}
/**
* @param Request $request
* @Security("is_granted('ROLE_RH')")
* @Route("/api/user/delete", name="delete-user", methods={"DELETE"})
*/
public function deleteUser(Request $request)
{
$selfUser = $this->getUser();
$em =$this->managerRegistry->getManager();
$data = $request->query->get('ids');
$outDatas = [];
if (!empty($data)) {
$users = $em->getRepository(User::class)->findBy(['id' => $data]);
foreach ($users as $user) {
$this->denyAccessUnlessGranted(CompanyVoter::USER_DELETE,$user);
//pas de suppression role admin
if($user->hasRole('ROLE_ADMIN')){
continue;
}
//pas de suppression RH par un RH
if($selfUser->hasRole('ROLE_RH') && $user->hasRole('ROLE_RH')){
return new JsonResponse('Vous ne pouvez pas supprimer un gestionnaire ! Contactez un administrateur.',403);
}
$em->remove($user);
array_push($outDatas, $user->getId());
}
$em->flush();
}
return new JsonResponse($outDatas);
}
}