<?php
namespace App\Controller;
use App\Entity\CompanyClient;
use App\Entity\ResetPasswordRequest;
use App\Entity\User;
use App\Entity\Company;
use App\Entity\Supplier;
use App\Entity\CompanySupplier;
use App\Entity\NotificationsConfig;
use App\Form\ClientSearchType;
use App\Form\UserFormType;
use App\Form\UserAutoEditFormType;
use App\Form\UserSearchType;
use App\Repository\CompanyClientRepository;
use App\Repository\UserRepository;
use App\Repository\SupplierRepository;
use App\Service\UtilService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mime\Address;
use App\Security\EmailVerifier;
use App\Security\Voter\UserVoter;
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Security\Core\Security;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/**
* @Route({"en": "/user",
* "es": "/usuario"})
*/
class UserController extends AbstractController
{
private $emailVerifier;
private $emailApp;
public const PAGE_ELEMENTS = 25;
private $translator;
private $util;
private $params;
private $security;
private $em;
public function __construct(
EmailVerifier $emailVerifier,
string $emailApp,
Security $security,
TranslatorInterface $translator,
ParameterBagInterface $params,
ManagerRegistry $doctrine,
UtilService $utilService)
{
$this->emailVerifier = $emailVerifier;
$this->emailApp = $emailApp;
$this->security = $security;
$this->translator = $translator;
$this->util = $utilService;
$this->params = $params;
$this->em = $doctrine->getManager();
}
/**
* @Route({"en": "/list",
* "es": "/listado"}, name="user_index", methods={"GET","POST"})
*/
public function index(Request $request, UserRepository $userRepository, PaginatorInterface $paginator): Response
{
$admin =$this->getUser();
$this->denyAccessUnlessGranted(UserVoter::EDIT, $admin);
$searchUser = [];
$usersAvailable = $this->util->getCompanyUsersAvailable($admin->getCompany());
$form = $this->createForm(UserSearchType::class, $searchUser, ['user_admin' => $admin,'users_available'=>$usersAvailable,'method' => 'GET']);
$form->handleRequest($request);
$orderBy = null;
$filters = [
['field'=>'company','title'=>'Empresa'],
['field'=>'ref','title'=>'Referencia'],
['field'=>'name','title'=>'Nombre'],
['field'=>'surname','title'=>'Apellidos'],
['field'=>'role','title'=>'Rol'],
['field'=>'email','title'=>'Email'],
['field'=>'active','title'=>'Activo']
];
if ($form->isSubmitted() && $form->isValid())
{
$orderBy = $request->query->get('order_by');
$users = $userRepository->findByName($form->getData(), $admin, $orderBy);
} else {
$users = $userRepository->buscarTodos($admin);
}
// Creating pagnination
$pagination = $paginator->paginate(
$users,
$request->query->getInt('page', 1),
self::PAGE_ELEMENTS
);
return $this->render('user/index.html.twig', [
'pagination' => $pagination,
'search_form' => $form->createView(),
'filters' => $filters,
'order_by' => $orderBy,
'user_logged' => $this->getUser(),
'navbarTitle' => $this->translator->trans("Usuarios")
]);
}
/**
* @Route({"en": "/new",
* "es": "/nuevo"}, name="user_new", methods={"GET","POST"})
*/
public function new(Request $request, UserRepository $userRepository, SupplierRepository $supplierRepository): Response
{
$admin = $this->getUser();
// check for "edit" access: calls all voters
$this->denyAccessUnlessGranted(UserVoter::EDIT, $admin);
$em = $this->em;
$usersAvailable = $this->util->getCompanyUsersAvailable($admin->getCompany());
$formWcErrors = null;
$formCliErrors = null;
$allowNew = true;
if($admin->getRole()!='ROLE_ADMIN'){
//límites licencia
$usersAvailable = $this->util->getCompanyUsersAvailable($admin->getCompany());
$allowNew = !empty($usersAvailable['all']['available']);
}
$user = new User();
$license = null;
if($request->getMethod()=='POST'){
$cid = !empty($request->request->get('user_form')['company']) ? intval($request->request->get('user_form')['company']) : 0;
if($cid){
$company = $em->getRepository(Company::class)->find($cid);
$usersAvailable = $this->util->getCompanyUsersAvailable($company);
$license = $this->util->getActiveLicense($company);
}
}
$form = $this->createForm(UserFormType::class, $user, ['user_admin' => $admin,'users_available'=>$usersAvailable,'license'=>$license]);
$form->handleRequest($request);
$this->vichUploaderFixBug($request, $user); //corregimos bug
if ($form->isSubmitted() && $form->isValid()) {
$company = $form->get('company')->getData();
$role = $form->get('role')->getData();
$wc_name = !empty($request->request->get('user_form')['wc_name']) ? $request->request->get('user_form')['wc_name'] : '';
$wc_address = !empty($request->request->get('user_form')['wc_address']) ? $request->request->get('user_form')['wc_address'] : '';
$wc_collab = !empty($request->request->get('user_form')['wc_collab']) ? true : false;
$cli_name = !empty($request->request->get('user_form')['cli_name']) ? $request->request->get('user_form')['cli_name'] : '';
$cli_nif = !empty($request->request->get('user_form')['cli_nif']) ? $request->request->get('user_form')['cli_nif'] : '';
$cli_address = !empty($request->request->get('user_form')['cli_address']) ? $request->request->get('user_form')['cli_address'] : '';
$cli_description = !empty($request->request->get('user_form')['cli_description']) ? $request->request->get('user_form')['cli_description'] : '';
//límites licencia
if($admin->getRole()!='ROLE_ADMIN'){
$usersAvailable = $this->util->getCompanyUsersAvailable($admin->getCompany());
$userType = strtolower(str_replace('ROLE_','',$role));
$allowNew = !empty($usersAvailable[$userType]['available']);
if(!$allowNew){
$msg_name = in_array($userType,['supplier','user','client']) ? $this->translator->trans('usuarios') : $this->translator->trans('administradores');
$user->setPhotoFile(null); //corregimos bug
$this->addFlash('danger', $this->translator->trans('Ha alcanzado el límite de {name} para su licencia.',['{name}'=>$msg_name]));
return $this->redirectToRoute('user_index');
}
}
if($admin->getRole()=='ROLE_ADMIN' && empty($company)){
try{
$nif = $this->params->get('app.addvance3d_nif');
}
catch(\Exception $e){
$nif = 'B88352091';
}
$company = $em->getRepository(Company::class)->findOneBy(['nif'=>$nif]);
$user->setCompany($company);
if(empty($company)){
$user->setPhotoFile(null); //corregimos bug
$this->addFlash('danger', $this->translator->trans('No se ha encontrado a la empresa Addvance3d con NIF {nif}',['{nif}'=>$nif]));
return $this->redirectToRoute('user_index');
}
}
if(in_array($form->get('role')->getData(),['ROLE_SUPPLIER','ROLE_SUPPLIER_CHIEF'])){
if(empty($wc_name)){
$formWcErrors['wc_name']=true;
}
if(empty($wc_address)){
$formWcErrors['wc_address']=true;
}
}
if(in_array($form->get('role')->getData(),['ROLE_CLIENT'])){
if(empty($cli_name)){
$formCliErrors['cli_name']=true;
}
if(empty($cli_nif)){
$formCliErrors['cli_nif']=true;
}
if(empty($cli_address)){
$formCliErrors['cli_address']=true;
}
}
if(empty($formWcErrors) && empty($formCliErrors)){
$lastId = $userRepository->findLastRef($company);
$user->setRef($lastId);
$user->setType($company->getType());
$em->persist($user);
$em->flush();
$user->setPhotoFile(null); //corregimos bug
if(!empty($wc_name) && !empty($wc_address)){
$supplier = new Supplier();
$supplier->setCompany($company);
$supplier->setUser($user);
$supplier->setAddress($wc_address);
$supplier->setName($wc_name);
$supplier->setCollab($wc_collab);
$supplier->setCertifications('');
$lastRef = $supplierRepository->findLastRef();
$supplier->setRef($lastRef);
$em->persist($supplier);
$user->setSupplier($supplier);
$em->flush();
$cs = new CompanySupplier();
$cs->setCompany($company);
$cs->setSupplier($supplier);
$cs->setConfigStepBudget(true);
$cs->setConfigStepChiefConfirm(true);
$cs->setConfigStepInDelivery(true);
$cs->setType(1);
$em->persist($cs);
$em->flush();
}
if(!empty($cli_name) && !empty($cli_nif) && !empty($cli_address)){
$cli = new CompanyClient();
$cli->setCompany($company);
$cli->setName($cli_name);
$cli->setNif($cli_nif);
$cli->setAddress($cli_address);
$cli->setDescription($cli_description);
$cli->setUser($user);
$em->persist($cli);
$user->setCompanyClient($cli);
$em->flush();
}
$this->addFlash('success', $this->translator->trans('Usuario creado correctamente'));
// Notificaciones
$data['message']='Nuevo usuario';
$data['name']=$user->getName();
$data['reference']=$user->getRef();
$data['path_name']='user_show';
$data['path_parameters']='id:'.$user->getId();
$this->util->notifications($user->getCompany(), 1, $data, $this->getUser());
// generate a signed url and email it to the user
$this->emailVerifier->sendEmailConfirmation('app_validate_user', $user,
(new TemplatedEmail())
->from(new Address($this->emailApp, 'Addvance3D'))
->to($user->getEmail())
->subject('Please confirm your Email')
->htmlTemplate('registration/confirmation_email.html.twig')
->context([
'user' => $user,
])
);
return $this->redirectToRoute('user_index');
}
}
return $this->render('user/new.html.twig', [
'user' => $user,
'form' => $form->createView(),
'allowNew' => $allowNew,
'formWcErrors' => $formWcErrors,
'formCliErrors' => $formCliErrors,
'navbarTitle' => $this->translator->trans("Crear nuevo usuario")
]);
}
/**
* @Route({"en": "/show/{id}",
* "es": "/mostrar/{id}"}, name="user_show", methods={"GET"})
*/
public function show(User $user): Response
{
return $this->render('user/show.html.twig', [
'user' => $user,
'navbarTitle' => $this->translator->trans("Usuario")
]);
}
/**
* @Route({"en": "/edit/{id}",
* "es": "/editar/{id}"}, name="user_edit", methods={"GET","POST"})
*/
public function edit(Request $request, User $user, UserPasswordHasherInterface $passwordEncoder): Response
{
// check for "edit" access: calls all voters
$this->denyAccessUnlessGranted(UserVoter::EDIT, $user);
$admin = $this->getUser();
$adminRole = $admin->getRole();
$userRole = $user->getRole();
$userActive = $user->getActive();
$autoedit = $admin->getId() === $user->getId() ? true : false;
$usersAvailable = $this->util->getCompanyUsersAvailable($admin->getCompany());
if ($autoedit)
{
$form = $this->createForm(UserAutoEditFormType::class, $user, ['user_admin' => $admin]);
}else
{
$form = $this->createForm(UserFormType::class, $user, ['user_admin' => $admin,'users_available'=>$usersAvailable]);
}
$form->handleRequest($request);
$this->vichUploaderFixBug($request, $user, $autoedit); //corregimos bug
if ($form->isSubmitted() && $form->isValid()) {
if ($form->has('newPassword'))
{
if ($form->get('newPassword')->getData() !== null && $form->get('oldPassword')->getData() !== null) {
if ( $passwordEncoder->isPasswordValid($user, $form->get('oldPassword')->getData()) )
{
$user->setPassword(
$passwordEncoder->hashPassword(
$user,
$form->get('newPassword')->getData()
)
);
}else{
$user->setPhotoFile(null); //corregimos bug
$this->addFlash('error', $this->translator->trans('Clave introducida incorrecta'));
return $this->redirectToRoute('user_edit',['id'=>$user->getId()]);
}
}
}
if (!$autoedit){
//Control de roles
$newRole = $user->getRole();
if($userRole != $newRole){
$error = false;
$cType = $user->getCompany()->getType();
if($adminRole=='ROLE_ADMIN'){
if( ($cType==1 && !in_array($newRole,['ROLE_CLIENT','ROLE_USER','ROLE_CHIEF','ROLE_ADMIN'])) || ($cType==2 && !in_array($newRole,['ROLE_SUPPLIER','ROLE_SUPPLIER_CHIEF'])) ){
$error = 'Los roles no son intercambiables entre usuarios OEMs y Service bureaus';
}
}
else{
$userType = strtolower(str_replace('ROLE_','',$newRole));
$allowNew = !empty($usersAvailable[$userType]['available']);
if(!$allowNew){
$msg_name = in_array($userType,['supplier','user','client']) ? $this->translator->trans('usuarios') : $this->translator->trans('administradores');
$error = $this->translator->trans('Ha alcanzado el límite de {name} para su licencia.',['{name}'=>$msg_name]);
}
}
if(!$error){
//Si se quita un usuario administrador verificamos que exista otro
if($userRole=='ROLE_CHIEF' || $userRole=='ROLE_SUPPLIER_CHIEF'){
$usersChief = $this->em->getRepository(User::class)->findBy(['company'=>$user->getCompany(),'role'=>$userRole]);
if(empty($usersChief) || count($usersChief)==1){
$error = 'Como mínimo debe haber un usuario administrador por empresa';
}
}
}
if($error){
$user->setPhotoFile(null); //corregimos bug
$this->addFlash('error', $this->translator->trans($error));
return $this->redirectToRoute('user_index');
}
}
//Activar usuario sin verificar con password genérico
if($adminRole=='ROLE_ADMIN' && $form->has('not_verified') && $form->get('not_verified')->getData()){
$user->setActive(true);
$user->setPassword(
$passwordEncoder->hashPassword(
$user,
123456
)
);
}
}
$cli_name = !empty($request->request->get('user_form')['cli_name']) ? $request->request->get('user_form')['cli_name'] : '';
$cli_nif = !empty($request->request->get('user_form')['cli_nif']) ? $request->request->get('user_form')['cli_nif'] : '';
$cli_address = !empty($request->request->get('user_form')['cli_address']) ? $request->request->get('user_form')['cli_address'] : '';
$cli_description = !empty($request->request->get('user_form')['cli_description']) ? $request->request->get('user_form')['cli_description'] : '';
$cli = $user->getCompanyClient();
if($cli_name != null) { $cli->setName($cli_name); }
if($cli_nif != null) { $cli->setNif($cli_nif); }
if($cli_address != null) { $cli->setAddress($cli_address); }
if($cli_description != null) { $cli->setDescription($cli_description); }
$this->em->persist($cli);
$this->em->flush();
$user->markAsUpdated();
$this->em->flush();
$user->setPhotoFile(null); //corregimos bug
$this->addFlash('success', $this->translator->trans('Usuario editado correctamente'));
if($user->getActive()!=$userActive){
// Notificaciones
$data['message']=$user->getActive()?'Usuario activado':'Usuario desactivado';
$data['name']=$user->getName();
$data['reference']=$user->getRef();
$data['path_name']='user_show';
$data['path_parameters']='id:'.$user->getId();
$this->util->notifications($user->getCompany(), 1, $data, $this->getUser());
}
if ($autoedit)
{
return $this->redirectToRoute('app_index');
}else
{
return $this->redirectToRoute('user_index');
}
}
return $this->render('user/edit.html.twig', [
'user' => $user,
'form' => $form->createView(),
'formHasErrors' => $form->isSubmitted() && !$form->isValid(),
'autoedit' => $autoedit,
'navbarTitle' => $this->translator->trans("Editar usuario")
]);
}
//Requerido para evitar bug VichUploaderBundle
private function vichUploaderFixBug(Request $request, User $user, $autoedit=false){
$formName = $autoedit ? 'user_auto_edit_form' : 'user_form';
if (!empty($request->files->get($formName)['photoFile']['file'])) {
$file = $request->files->get($formName)['photoFile']['file'];
$mimesAllowed = ["image/jpeg", "image/gif", "image/png"];
$errorMsg = '';
if($file->getSize()>20000000){
$errorMsg.= $this->translator->trans('El tamaño máximo permitido del archivo es {limit} MB.',['{limit}'=>2]).'<br>';
}
if(!in_array($file->getMimeType(),$mimesAllowed)){
$errorMsg.= $this->translator->trans('Los tipos de archivos permitidos son : {mime}',['{mime}'=>implode(',',$mimesAllowed)]);
}
if(!empty($errorMsg)){
$user->setPhotoFile(null); //corregimos bug
$this->addFlash('danger', $this->translator->trans($errorMsg));
if($user->getId()>0){
return $this->redirectToRoute('user_edit',['id'=>$user->getId()]);
}
else{
return $this->redirectToRoute('user_new');
}
}
}
}
/**
* @Route({"en": "/delete/{id}",
* "es": "/borrar/{id}"}, name="user_delete", methods={"DELETE"})
*/
public function delete(Request $request, User $user, MailerInterface $mailer): Response
{
$this->denyAccessUnlessGranted(UserVoter::DELETE, $user);
if ($this->isCsrfTokenValid('delete'.$user->getId(), $request->request->get('_token'))) {
$entityManager = $this->em;
try
{
$admin = $this->getUser();
$userEmail = $user->getEmail();
$entityManager->remove($user);
$entityManager->flush();
$this->addFlash('success', $this->translator->trans('Usuario eliminado correctamente'));
// Notificaciones
$data['message']='Usuario borrado';
$data['name']=$user->getName();
$data['reference']=$user->getRef();
$data['path_name']='user_index';
$this->util->notifications($user->getCompany(), 1, $data, $this->getUser());
} catch (ForeignKeyConstraintViolationException $e) {
$this->addFlash('danger', $this->translator->trans('No se puede eliminar un usuario asociado') );
return $this->redirectToRoute('user_index');
}
}
return $this->redirectToRoute('user_index');
}
/**
* @Route({"en": "/export",
* "es": "/exportar"}, name="user_export")
*/
public function export(UserRepository $userRepository)
{
$admin =$this->getUser();
$company = $admin->getCompany();
$colorARGB = $company && $company->getCorporateColor() ? str_replace('#','',$company->getCorporateColor()) : 'DD9933';
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setTitle('Addvance '.$this->translator->trans('Usuarios'));
$cells = ['A1','B1','C1','D1','E1','F1','G1','H1','I1','J1','K1','L1','M1','N1','O1'];
$fields = ['Referencia','Nombre','Apellidos','Rol','Email','Activo','Centro de trabajo','Departamento','Puesto','Teléfono',
'Terminos aceptados','Aceptado el','Verificado','Fecha creación','Fecha modificación'];
if($admin->getRole()=='ROLE_ADMIN'){
array_unshift($fields,'Empresa');
$cells[]='P1';
}
foreach($fields as $k=>$field){
$sheet->getCell($cells[$k])->setValue($this->translator->trans($field));
}
$styleArrayFirstRow = [
'font' => [
'bold' => true,
'color' => array('rgb' => 'FFFFFF'),
]
];
$lastCell = end($cells);
$sheet->getStyle('A1:'.$lastCell)->applyFromArray($styleArrayFirstRow);
$sheet
->getStyle('A1:'.$lastCell)
->getFill()
->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
->getStartColor()
->setARGB($colorARGB);
$sheet->getDefaultColumnDimension()->setWidth(30);
// Increase row cursor after header write
$sheet->fromArray($userRepository->generateExport($admin),null, 'A2', true);
$writer = new Xlsx($spreadsheet);
$response = new StreamedResponse(
function () use ($writer) {
$writer->save('php://output');
}
);
$filename = $this->translator->trans("AD2_usuarios_"). time() . ".xlsx";
$response->headers->set('Content-Type', 'application/vnd.ms-excel');
$response->headers->set('Content-Disposition', 'attachment;filename="'.$filename.'"');
$response->headers->set('Cache-Control','max-age=0');
return $response;
}
/**Clientes **********************************************************/
/**
* @Route({"en": "/client/list",
* "es": "/clientes/listado"}, name="client_index", methods={"GET","POST"})
*/
public function client(Request $request, CompanyClientRepository $ccRepository, PaginatorInterface $paginator): Response
{
$admin =$this->getUser();
$search = [];
$usersAvailable = $this->util->getCompanyUsersAvailable($admin->getCompany());
$form = $this->createForm(ClientSearchType::class, $search, ['user_admin' => $admin,'users_available'=>$usersAvailable,'method' => 'GET']);
$form->handleRequest($request);
$orderBy = null;
$filters = [
['field'=>'company','title'=>'Empresa'],
['field'=>'name','title'=>'Nombre'],
['field'=>'nif','title'=>'NIF'],
['field'=>'address','title'=>'Dirección'],
['field'=>'description','title'=>'Descripción']
];
if ($form->isSubmitted() && $form->isValid())
{
$orderBy = $request->query->get('order_by');
$clients = $ccRepository->findClient($form->getData(), $admin, $orderBy);
} else {
$clients = $ccRepository->findClient([],$admin);
}
// Creating pagnination
$pagination = $paginator->paginate(
$clients,
$request->query->getInt('page', 1),
self::PAGE_ELEMENTS
);
return $this->render('user/client.html.twig', [
'pagination' => $pagination,
'search_form' => $form->createView(),
'filters' => $filters,
'order_by' => $orderBy,
'user_logged' => $this->getUser(),
'navbarTitle' => $this->translator->trans("Clientes")
]);
}
/**
* @Route({"en": "/manual",
* "es": "/manual"}, name="user_manual", methods={"GET","POST"})
*/
public function manual(Request $request) {
$webPath = $this->getParameter('kernel.project_dir') . '/public/';
if($request->getLocale() == 'es') {
$md = file_get_contents('user-manual/manual_ES.md');
} else {
$md = file_get_contents('user-manual/manual_EN.md');
}
return $this->render('user/manual.html.twig', [
'md' => $md,
'navbarTitle' => $this->translator->trans("Manual de usuario")
]);
}
}