src/Diplix/KMGBundle/Controller/Admin/UserController.php line 165

Open in your IDE?
  1. <?php
  2. namespace Diplix\KMGBundle\Controller\Admin;
  3. use Diplix\KMGBundle\Controller\BaseController;
  4. use Diplix\KMGBundle\Entity\Accounting\CoopMember;
  5. use Diplix\KMGBundle\Entity\Customer;
  6. use Diplix\KMGBundle\Entity\Role;
  7. use Diplix\KMGBundle\Entity\User;
  8. use Diplix\KMGBundle\Form\Admin\CustomerForm;
  9. use Diplix\KMGBundle\Form\Admin\WizardForm;
  10. use Diplix\KMGBundle\Form\DefaultDeleteForm;
  11. use Diplix\KMGBundle\Form\Admin\UserForm;
  12. use Diplix\KMGBundle\Helper\ClientConfigProvider;
  13. use Diplix\KMGBundle\Repository\UserRepository;
  14. use Diplix\KMGBundle\Service\MailHelper;
  15. use Symfony\Component\EventDispatcher\EventDispatcher;
  16. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  17. use Symfony\Component\Form\FormError;
  18. use Symfony\Component\HttpFoundation\Request;
  19. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  20. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  21. use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
  22. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  23. use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
  24. class UserController extends BaseController
  25. {
  26.     /**
  27.      * @var UserRepository;
  28.      */
  29.     protected $rep;
  30.     public function __construct(
  31.         protected EventDispatcherInterface $dispatcher,
  32.         protected MailHelper $mailHelper,
  33.         protected UserPasswordHasherInterface $hasher,
  34.         protected ClientConfigProvider $clientConfigProvider
  35.     )
  36.     {
  37.     }
  38.     protected function init()
  39.     {
  40.         $this->rep $this->getDoctrine()->getManager()->getRepository('Diplix\KMGBundle\Entity\User');
  41.         if (
  42.             (!$this->hasUserRole(Role::USER_ADMIN))
  43.             &&
  44.             (!$this->hasUserRole(Role::SUB_USER_ADMIN))
  45.             &&
  46.             (!$this->hasUserRole(Role::ADMIN1))
  47.             )
  48.         {
  49.             throw new AccessDeniedException();
  50.         }
  51.         $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
  52.     }
  53.     /**
  54.      * Generate a new random password
  55.      * @return string
  56.      */
  57.     protected function generatePw()
  58.     {
  59.         $out "";
  60.         for ($i 0$i 4;$i++)
  61.         {
  62.             $out .= chrrand(97,122));
  63.         }
  64.         for ($i 0$i 4;$i++)
  65.         {
  66.             $out .= rand(0,9);
  67.         }
  68.         return $out;
  69.     }
  70.     /**
  71.      * Generate a new random username
  72.      * @return string
  73.      */
  74.     public static function generateUsername()
  75.     {
  76.         $out "";
  77.         for ($i 0$i 8;$i++)
  78.         {
  79.             $out .= chrrand(97,122));
  80.         }
  81.         $out .= uniqid();
  82.         return $out;
  83.     }
  84.     /**
  85.      * Set encrypted pw using the default provider
  86.      * @param User $row
  87.      * @param string $newPw
  88.      * @return true
  89.      */
  90.     protected function setEncryptedUserPw(User $row$newPw)
  91.     {
  92.         $password $this->hasher->hashPassword($row,$newPw);
  93.         $row->setPassword($password);
  94.         return true;
  95.     }
  96.     /**
  97.      * @return User
  98.      */
  99.     protected function getNewUserObject()
  100.     {
  101.         $row = new User();
  102.         // since the username is currently not really used, except for the admin account, just use a random one
  103.         $row->setUsername($this->generateUsername());
  104.         $newPassword $this->generatePw();
  105.         $this->setEncryptedUserPw($row$newPassword);
  106.         $role $this->rep->getRoleObjectByRoleName(Role::USER);
  107.         $row->addRole($role);
  108.         if (!$this->hasUserRole(Role::USER_ADMIN))
  109.         {
  110.             // when not being an global user admin, limit the user to our group
  111.             $row->setCustomer$this->getCurrentUser()->getCustomer());
  112.         }
  113.         return $row;
  114.     }
  115.     public function indexAction(Request $request)
  116.     {
  117.         $this->init();
  118.         $f $request->get('filter','customers');
  119.         // TODO : change to array hydration
  120.         // TODO: use iterator and paging as well as dynamic json loading for dataTable !
  121.         if ( ($this->hasUserRole(Role::USER_ADMIN)) || ($this->hasUserRole(Role::ADMIN1)) )
  122.         {
  123.             $list $this->rep->findUserForList($f,null);
  124.         }
  125.         else
  126.         {
  127.             $list $this->rep->findUserForList('customers',$this->getCurrentUser()->getCustomer());
  128.         }
  129.         return $this->render('@DiplixKMG/Admin/User/list.html.twig', array(
  130.             "dataList"=>$list"filter"=>$f));
  131.     }
  132.     protected function removeRoleIfNotHavingItSelf($roleNameUser $data)
  133.     {
  134.         if (!$this->hasUserRole($roleName))
  135.         {
  136.             $remove null;
  137.             /** @var Role $r */
  138.             foreach ($data->getRoles(true) as $r)
  139.             {
  140.                 if ($r->getRole() == $roleName$remove $r;
  141.             }
  142.             if (is_object($remove))
  143.             {
  144.                 $data->removeRole($remove);
  145.                 $this->addFlash("warning","Zuweisen der ".$roleName."-Rolle nicht zulässig.");
  146.             }
  147.         }
  148.     }
  149.    public function editAction(Request $request)
  150.     {
  151.         $newUser false;
  152.         User::$roles_as_object true;
  153.         $this->init();
  154.         $id $request->query->get('id');
  155.         if ($id>0)
  156.         {
  157.             if ( ($this->hasUserRole(Role::USER_ADMIN)) || ($this->hasUserRole(Role::ADMIN1)) )
  158.                 $row $this->rep->findOneBy(array("id"=>$id,"hidden"=>false));
  159.             else    // for SUB_USER_ADMIN
  160.                 $row $this->rep->findOneBy(array("id"=>$id,"hidden"=>false,"customer"=>$this->getCurrentUser()->getCustomer()));
  161.             if ($row===null)
  162.             {
  163.                 $this->addFlash('warning','Invalid ID');
  164.                 return  $this->redirect($this->generateUrl('admin-users'));
  165.             }
  166.         }
  167.         else
  168.         {
  169.             $row $this->getNewUserObject();
  170.             $newUser true;
  171.             $newGeneratedPassword $this->generatePw();
  172.             $this->setEncryptedUserPw($row,$newGeneratedPassword);
  173.         }
  174.         // Only sys_admin may edit sys_admin users
  175.         if ( ($row->hasRole(Role::SYS_ADMIN)) && (!$this->hasUserRole(Role::SYS_ADMIN,true)) )
  176.         {
  177.             throw new AccessDeniedException();
  178.         }
  179.         $originalPasswordHash $row->getPassword(); // NOTE: not accessible anymore after used with createForm()!!!
  180.         // render form
  181.         $sameCustomer false;
  182.         if ( ($row->getCustomer()!==null) && ($this->getCurrentUser()->getCustomer()!==null) )
  183.         {
  184.             $sameCustomer $row->getCustomer()->getId() === $this->getCurrentUser()->getCustomer()->getId();
  185.         }
  186.         $opts = array(
  187.             UserForm::SUPER => $this->hasUserRole(Role::SUPER_ADMIN),
  188.             UserForm::ALLOW_PW_CHANGE =>  !$row->hasRole(Role::SYS_ADMIN) && (  $this->hasUserRole(Role::SUPER_ADMIN) || ($this->hasUserRole(Role::SUB_USER_ADMIN) && $sameCustomer) ),
  189.             UserForm::ALLOW_ROLE_CHANGE => !$row->hasRole(Role::SYS_ADMIN),
  190.             UserForm::DASHBOARDS => $this->clientConfigProvider->getDashboardCategories()
  191.         );
  192.         $form $this->createForm(UserForm::class,$row,$opts);
  193.         $form->handleRequest($request);
  194.         if ($form->isSubmitted())
  195.         {
  196.             $valid $form->isValid();
  197.             /** @var User $data */
  198.             $data $form->getData();
  199.             // check email uniqueness
  200.             $ret $this->rep->findBy(array('email'=>$data->getEmail()));
  201.             if (count($ret)>0)
  202.             {
  203.                 if ($ret[0]->getId() != $data->getId())
  204.                 {
  205.                     /*
  206.                     $valid = false;
  207.                     $form->get('email')->addError(new FormError("Diese eMail-Adresse existiert bereits"));
  208.                     */
  209.                     // eMail-Adressen dĂĽrfen mehrfach vorkommen
  210.                     $this->addFlash('info',sprintf('Hinweis: Diese eMail-Adresse (%s) wird mehrfach verwendet. Ein Login/Passwortreset per eMail ist zukĂĽnftig nicht mehr möglich.',$data->getEmail()));
  211.                 }
  212.             }
  213.             // check username uniqueness
  214.             $ret $this->rep->findOneBy(array('username'=>$data->getUsername()));
  215.             if (is_object($ret))
  216.             {
  217.                 if ($ret->getId() != $data->getId())
  218.                 {
  219.                     $valid false;
  220.                     $form->get('username')->addError(new FormError("Dieser Benutzername existiert bereits"));
  221.                 }
  222.             }
  223.             if (!$valid)
  224.             {
  225.                 $form->addError(new FormError("Bitte ĂĽberprĂĽfen Sie Ihre Eingaben"));
  226.                 return $this->render('@DiplixKMG/Admin/User/edit.html.twig',array ( "form" => $form->createView(),
  227.                     "row"=> $row,
  228.                 ));
  229.             }
  230.             if (strlen(trim($data->getPassword()))<1)
  231.             {
  232.                 // no pw entered keep old one
  233.                 $data->setPassword($originalPasswordHash);
  234.             }
  235.             else
  236.             {
  237.                 if ($newUser)
  238.                 {
  239.                     $data->setPassword($originalPasswordHash);
  240.                 }
  241.                 else
  242.                 {
  243.                     // set new pw
  244.                     $this->setEncryptedUserPw($data$data->getPassword());
  245.                     $data->setLastPasswordChange(new \DateTime());
  246.                 }
  247.             }
  248.             // do not allow to set superadmin rights when not being a superadmin
  249.             $this->removeRoleIfNotHavingItSelf(Role::SUPER_ADMIN,$data);
  250.             $this->removeRoleIfNotHavingItSelf(Role::SYS_ADMIN,$data);
  251. //            if (!$this->hasUserRole(Role::SUPER_ADMIN))
  252. //            {
  253. //                $remove = null;
  254. //                /** @var User $data*/
  255. //                /** @var Role $r */
  256. //                foreach ($data->getRoles(true) as $r)
  257. //                {
  258. //                    if ($r->getRole() == Role::SUPER_ADMIN) $remove = $r;
  259. //                }
  260. //                if (is_object($remove))
  261. //                {
  262. //                    $data->removeRole($remove);
  263. //                    $this->addFlash("warning","Zuweisen der SuperAdmin-Rolle nicht zulässig.");
  264. //                }
  265. //            }
  266.             $this->rep->persistFlush($data);
  267.             $this->addFlash('success','Record has been saved.');
  268.             if ($newUser)
  269.             {
  270.                $this->addFlash("info",sprintf("Neues Passwort: %s",$newGeneratedPassword));
  271.             }
  272.             return  $this->redirect($this->generateUrl'admin-users', array("lastRecordId"=>$data->getId())));
  273.         }
  274.         else
  275.         {
  276.             return $this->render('@DiplixKMG/Admin/User/edit.html.twig',array ( "form" => $form->createView(),
  277.                 "row"=> $row,
  278.             ));
  279.         }
  280.     }
  281.     public function deleteAction(Request $request)
  282.     {
  283.         $this->init();
  284.         $id $request->get('id'); // _GET or _POST
  285.         /** @var User $row */
  286.         if ($this->hasUserRole(Role::USER_ADMIN))
  287.                 $row $this->rep->findOneBy(array("id"=>$id,"hidden"=>false));
  288.             else    // for SUB_USER_ADMIN
  289.                 $row $this->rep->findOneBy(array("id"=>$id,"hidden"=>false,"customer"=>$this->getCurrentUser()->getCustomer()));
  290.         if ($row===null)
  291.         {
  292.             $this->addFlash('warning','Invalid record ID');
  293.             return  $this->redirect($this->generateUrl('admin-users'));
  294.         }
  295.         if ($row->getSysUser())
  296.         {
  297.             $this->addFlash('warning','This is a internal system user. Please contact support if you want to delete it.');
  298.             return  $this->redirect($this->generateUrl('admin-users'));
  299.         }
  300.         // Only sys_admin may delete sys_admin users
  301.         if ( ($row->hasRole(Role::SYS_ADMIN)) && (!$this->hasUserRole(Role::SYS_ADMIN,true)) )
  302.         {
  303.             throw new AccessDeniedException();
  304.         }
  305.         $form $this->createFormDefaultDeleteForm::class,array("id"=>$id));
  306.         $form->handleRequest($request);
  307.         if ($form->isSubmitted())
  308.         {
  309.             if ($form->get('commit')->getData() == 1)
  310.             {
  311.                 $row->eraseMyself();
  312.                 $this->rep->persistFlush($row);
  313.                 $this->addFlash('success','Record has been deleted.');
  314.             }
  315.             return  $this->redirect($this->generateUrl('admin-users'));
  316.         }
  317.         else
  318.         {
  319.             return $this->render('@DiplixKMG/Admin/User/delete.html.twig',array ( "row"=> $row"form"=>$form->createView()));
  320.         }
  321.     }
  322.     public function wizardAction(Request $request)
  323.     {
  324.         $this->init();
  325.         $this->ensureUserHasRole(Role::USER_ADMIN);
  326.         $form $this->createForm(WizardForm::class,array());
  327.         $form->handleRequest($request);
  328.         if ($form->isSubmitted())
  329.         {
  330.             $valid $form->isValid();
  331.             if ($valid)
  332.             {
  333.                 // check email uniqueness
  334.                 $ret $this->rep->findOneBy(array('email' => $form->get("email")->getData()));
  335.                 if (is_object($ret))
  336.                 {
  337.                     $valid false;
  338.                     $form->get('email')->addError(new FormError("Diese eMail-Adresse existiert bereits"));
  339.                 }
  340.                 if ($valid)
  341.                 {
  342.                     $U $this->getNewUserObject();
  343.                     $newPassword $this->generatePw();
  344.                     $this->setEncryptedUserPw($U$newPassword);
  345.                     $U->setEmail($form->get("email")->getData());
  346.                     $U->setPhone($form->get('phone')->getData());
  347.                     $U->setFirstName($form->get("firstName")->getData());
  348.                     $U->setLastName($form->get("lastName")->getData());
  349.                     // ensure unique username
  350.                     $unameBase substr(strtolower($U->getFirstName()), 01) ."."strtolower($U->getLastName());
  351.                     $idx 0;
  352.                     do
  353.                     {
  354.                         $uname $unameBase . ($idx sprintf("%d"$idx) : "");
  355.                         $U->setUsername($uname);
  356.                         $ret $this->rep->findOneBy(array('username' => $uname));
  357.                         $idx++;
  358.                     } while (is_object($ret));
  359.                     // store
  360.                     $this->rep->persistFlush($U);
  361.                     if ($form->get('type')->getData()==WizardForm::CUSTOMER)
  362.                     {
  363.                         // create customer
  364.                         $C = new Customer();
  365.                         $C->setName($form->get("company")->getData());
  366.                         $C->setCustomerNo($form->get("customerNo")->getData());
  367.                         $this->getDoctrine()->getManager()->persist($C);
  368.                         $U->setCustomer($C);
  369.                     }
  370.                     else
  371.                     if ($form->get('type')->getData()==WizardForm::MEMBER)
  372.                     {
  373.                         $M = new CoopMember();
  374.                         $M->setName($form->get("company")->getData());
  375.                         $M->setNumber($form->get("memberNo")->getData());
  376.                         $M->setShortCode($form->get('shortCode')->getData());
  377.                         $this->getDoctrine()->getManager()->persist($M);
  378.                         $U->setMember($M);
  379.                     }
  380.                     else
  381.                     {
  382.                         throw $this->createAccessDeniedException('Unbekannter Typ');
  383.                     }
  384.                     $this->rep->flush($U);
  385.                     $this->addFlash('success''Benutzer/Kunde wurde angelegt.');
  386.                     // inform user
  387.                     try
  388.                     {
  389.                         $mh $this->mailHelper;
  390.                         $mh->NewAccountMail($U$newPassword);
  391.                         $this->addFlash('info''Zugangsdaten wurden per eMail versendet.');
  392.                     }
  393.                     catch (\Throwable $ex)
  394.                     {
  395.                         $this->addFlash('warning','Automatischer Versand der Zugangsdaten fehlgeschlagen !');
  396.                     }
  397.                     return $this->redirectToRoute("admin-users");
  398.                 }
  399.             }
  400.         }
  401.         return $this->render('@DiplixKMG/Admin/User/wizard.html.twig',array ( "form"=>$form->createView()));
  402.     }
  403.     public function loginAsAction(Request $request)
  404.     {
  405.         $this->init();
  406.         $this->ensureUserHasRole(Role::SUPER_ADMIN);
  407.         $id $request->get('id'); // _GET or _POST
  408.         /** @var User $user */
  409.         $user $this->rep->findOneBy(array("id" => $id"hidden" => false));
  410.         if ($user === null)
  411.         {
  412.             $this->addFlash('warning''Invalid record ID');
  413.             return $this->redirect($this->generateUrl('admin-users'));
  414.         }
  415.         if ( ($user->hasRole(Role::SYS_ADMIN)) && (!$this->hasUserRole(Role::SYS_ADMIN,true)) )
  416.         {
  417.             throw new AccessDeniedException();
  418.         }
  419.         // Impersonate
  420.         $firewall "admin_area";
  421.         $session $request->getSession();
  422.         // clean eventually existing session
  423.         $this->container->get('security.token_storage')->setToken(null);
  424.         // set new token
  425.         $token = new UsernamePasswordToken($user"no-password"$firewall$user->getRoles());
  426.         $this->container->get('security.token_storage')->setToken($token);
  427.         // save token in session
  428.         $session->set('_security_'.$firewallserialize($token));
  429.         $session->save();
  430.         // Fire the login event
  431.         $this->dispatcher->dispatch(new InteractiveLoginEvent($request$token));
  432.         $this->addFlash("info","Sie befinden sich nun im Benutzerkontext von ".$user->getUsername());
  433.         $home $this->generateUrl("kmg_home");
  434.         if ($user->getCustomer() != null)
  435.         {
  436.             return $this->redirectToRoute("admin-switch-customer",
  437.                         array(  "customerId"=>$user->getCustomer()->getId(),
  438.                                 "referTo"=>$home));
  439.         }
  440.         return $this->redirect($home);
  441.     }
  442. }