src/AppBundle/Controller/AdminController.php line 179

Open in your IDE?
  1. <?php
  2. namespace AppBundle\Controller;
  3. use AppBundle\Entity\Instance;
  4. use AppBundle\Entity\InstanceUser;
  5. use AppBundle\Entity\Language;
  6. use AppBundle\Entity\Notification;
  7. use AppBundle\Entity\User;
  8. use AppBundle\Form\InstanceForm;
  9. use AppBundle\Form\InstanceType;
  10. use AppBundle\Form\JiraAccountsType;
  11. use AppBundle\Form\PermissionsOfUsersInInstanceType;
  12. use AppBundle\Form\RegexpAndMentorInstanceType;
  13. use AppBundle\Form\RegistrationType;
  14. use AppBundle\Form\UserType;
  15. use AppBundle\Service\ExerciseManager;
  16. use AppBundle\Service\GitHubManager;
  17. use AppBundle\Service\Instance as InstanceService;
  18. use AppBundle\Service\Participation;
  19. use AppBundle\Service\UserManager;
  20. use AppBundle\Service\UserService;
  21. use CodersLab\Lms\Modules\IdentityAccess\Application\ICourseInstanceContext;
  22. use CodersLab\Lms\Modules\Materials\Domain\ICourses;
  23. use CodersLab\Lms\SharedKernel\Application\Command\SendWelcomeEmail;
  24. use CodersLab\Lms\SharedKernel\Application\Mailer\IRegistrationMailer;
  25. use CodersLab\Lms\SharedKernel\Application\SecurityContext\PasswordEncoder;
  26. use CodersLab\Lms\SharedKernel\Domain\Bus\CommandBus;
  27. use CodersLab\Lms\SharedKernel\Domain\Bus\EventRecorder;
  28. use CodersLab\Lms\SharedKernel\Domain\Courses\MemberType;
  29. use CodersLab\Lms\SharedKernel\PublishedLanguage\Events\CourseInstanceAdded;
  30. use CodersLab\Lms\SharedKernel\PublishedLanguage\Events\CourseInstanceMemberAdded;
  31. use CodersLab\Lms\SharedKernel\PublishedLanguage\Events\SignatureUpdated;
  32. use CodersLab\Lms\SharedKernel\PublishedLanguage\Events\UserGithubUpdated;
  33. use Doctrine\ORM\EntityManagerInterface;
  34. use Exception;
  35. use GuzzleHttp\Exception\ClientException;
  36. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
  37. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  38. use Symfony\Component\Form\Form;
  39. use Symfony\Component\HttpFoundation\Request;
  40. use Symfony\Component\HttpFoundation\Response;
  41. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  42. final class AdminController extends AbstractController
  43. {
  44.     public function __construct(
  45.         private EventRecorder $eventRecorder,
  46.         private CommandBus $commandBus,
  47.         private Participation $participationService,
  48.         private InstanceService $instanceService,
  49.         private UserService $userService
  50.     ) {
  51.     }
  52.     /**
  53.      * @Route("/admin/user", name="users")
  54.      */
  55.     public function usersAction(Request $request): Response
  56.     {
  57.         if ($this->isGranted("ROLE_CS") || $this->isGranted("ROLE_ADMIN")) {
  58.             $users $this->userService->getAllUsers(
  59.                 $request,
  60.                 $request->query->getInt('page'1),
  61.                 10
  62.             );
  63.         } elseif ($this->isGranted("ROLE_MENTOR")) {
  64.             $instances = [];
  65.             foreach ($this->getUser()->getParticipations() as $participation) {
  66.                 if ($participation instanceof InstanceUser) {
  67.                     $instances[] = $participation->getInstance();
  68.                 }
  69.             }
  70.             return $this->render('mentor/users.html.twig', ['instances' => $instances]);
  71.         } else {
  72.             throw new AccessDeniedException();
  73.         }
  74.         return $this->render('admin/users.html.twig', ['users' => $users]);
  75.     }
  76.     /**
  77.      * @Route("/admin/user/{id}", name="user")
  78.      * @param User    $user
  79.      * @param Request $request
  80.      *
  81.      * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
  82.      * @throws \GuzzleHttp\Exception\GuzzleException
  83.      */
  84.     public function userAction(
  85.         User $user,
  86.         Request $request,
  87.         EntityManagerInterface $em,
  88.         PasswordEncoder $passwordEncoder
  89.     ): Response {
  90.         $oldGhAccount $user->getGithub();
  91.         $form $this->createForm(UserType::class, $user, ['role' => $this->getUser()->getRoles()]);
  92.         $form->handleRequest($request);
  93.         if ($form->isSubmitted() && $form->isValid()) {
  94.             if ($user->getPlainPassword()) {
  95.                 $password $passwordEncoder->encodeUserPassword((string)$user->getId(), $user->getPlainPassword());
  96.                 $user->setPassword($password);
  97.             }
  98.             if ($user->getGithub() !== $oldGhAccount) {
  99.                 $this->eventRecorder->record(new UserGithubUpdated(
  100.                     $user->getId(),
  101.                     $user->getGithub(),
  102.                     $oldGhAccount,
  103.                 ));
  104.             }
  105.             $em->persist($user);
  106.             $em->flush();
  107.             return $this->redirect($request->getUri());
  108.         }
  109.         $userCourseAudit $em->getRepository(InstanceUser::class)->findBy(['user' => $user]);
  110.         return $this->render('admin/user.html.twig', [
  111.             'user'            => $user,
  112.             'userCourseAudit' => $userCourseAudit,
  113.             'form'            => $form->createView(),
  114.         ]);
  115.     }
  116.     /**
  117.      * @Route("/admin/user_create", name="user_create")
  118.      */
  119.     public function userCreateAction(
  120.         Request $request,
  121.         EntityManagerInterface $em,
  122.         PasswordEncoder $passwordEncoder
  123.     ): Response {
  124.         $user = new User();
  125.         $form $this->createForm(UserType::class, $user, ['role' => $this->getUser()->getRoles()]);
  126.         $form->handleRequest($request);
  127.         if ($form->isSubmitted() && $form->isValid()) {
  128.             if ($user->getPlainPassword()) {
  129.                 $password $passwordEncoder->encodePassword($user->getPlainPassword());
  130.                 $user->setPassword($password);
  131.             } else {
  132.                 $user->setPassword(UserManager::generatePassword());
  133.                 $user->setConfirmationToken(UserManager::generatePassword());
  134.             }
  135.             $em->persist($user);
  136.             $em->flush();
  137.             $this->commandBus->dispatch(new SendWelcomeEmail((string)$user->getId()));
  138.             return $this->redirect($this->generateUrl('user', ['id' => $user->getId()]));
  139.         }
  140.         $userCourseAudit $em->getRepository('AppBundle:InstanceUser')->findBy(['user' => $user]);
  141.         return $this->render('admin/user.html.twig', [
  142.             'user'            => $user,
  143.             'userCourseAudit' => $userCourseAudit,
  144.             'form'            => $form->createView(),
  145.         ]);
  146.     }
  147.     /**
  148.      * @Route("/admin/report", name="admin_report")
  149.      */
  150.     public function reportAction(): Response
  151.     {
  152.         return $this->render('admin/report.html.twig');
  153.     }
  154.     /**
  155.      * @Route("/admin/instance", name="instances")
  156.      */
  157.     public function instancesAction(Request $request): Response
  158.     {
  159.         $this->denyAccessUnlessGranted(User::ROLE_MENTOR);
  160.         if ($this->isGranted(User::ROLE_CS)) {
  161.             $instances $this->instanceService->getAllInstances(
  162.                 $request,
  163.                 $request->query->getInt('page'1),
  164.                 15,
  165.                 [
  166.                     'signature' => 'ASC',
  167.                     'mode'      => 'ASC',
  168.                     'number'    => 'ASC',
  169.                 ]
  170.             );
  171.         } else {
  172.             $instances $this->instanceService->getAllInstancesByParticipation(
  173.                 $request,
  174.                 $this->getUser(),
  175.                 $request->query->getInt('page'1),
  176.                 15,
  177.                 [
  178.                     'signature' => 'ASC',
  179.                     'mode'      => 'ASC',
  180.                     'number'    => 'ASC',
  181.                 ],
  182.             );
  183.         }
  184.         return $this->render('admin/instances.html.twig', [
  185.             'instances' => $instances,
  186.         ]);
  187.     }
  188.     /**
  189.      * @Route("/admin/instance_create", name="instance_create")
  190.      */
  191.     public function instanceCreateAction(Request $requestEntityManagerInterface $em)
  192.     {
  193.         $this->denyAccessUnlessGranted("ROLE_CS");
  194.         $instance = new Instance();
  195.         $form $this->createForm(InstanceType::class, $instance, [
  196.             'participation_service' => $this->participationService,
  197.             'instance_service'      => $this->instanceService,
  198.             'user'                  => $this->getUser(),
  199.         ]);
  200.         $form->handleRequest($request);
  201.         if ($form->isSubmitted() && $form->isValid()) {
  202.             $em->beginTransaction();
  203.             $course $instance->getCourse();
  204.             $instance->setVersion($course->getDetails()->getVersion()->value());
  205.             $instance->setLanguage($em->getRepository(Language::class)->find(
  206.                 $course->getDetails()->getTechnologyId()->toString()
  207.             ));
  208.             $em->persist($instance);
  209.             $em->flush();
  210.             /** @var ExerciseManager $exerciseManager */
  211.             $exerciseManager $this->get('app.exercise.manager');
  212.             $exercises $exerciseManager->createExercisesForInstance($instance);
  213.             foreach ($exercises as $exercise) {
  214.                 $em->persist($exercise);
  215.             }
  216.             /** @var GitHubManager $gitHub */
  217.             $gitHub $this->get('app.github.students');
  218.             $ghTeam $gitHub->createNewTeam($instance->getSignature()) ?: $gitHub->findTeamByName($instance->getSignature());
  219.             if (!isset($ghTeam)) {
  220.                 throw new \Exception("Cannot create or find GitHub team with name: " $instance->getSignature());
  221.             }
  222.              $instance->setGhTeamId($ghTeam->id);
  223.             foreach ($instance->getParticipants() as $participant) {
  224.                 if ($participant instanceof InstanceUser) {
  225.                     if ((in_array($participant->getRole(), [InstanceUser::ROLE_MENTOR InstanceUser::ROLE_USER])) &&
  226.                         !empty($participant->getUser()->getGithub())) {
  227.                         try {
  228.                             $gitHub->addUserToTeam(
  229.                                 $instance->getGhTeamId(),
  230.                                 $participant->getUser()->getGithubId(),
  231.                                 $participant->getRole() === InstanceUser::ROLE_MENTOR
  232.                             );
  233.                         } catch (ClientException $e) {
  234.                             throw new Exception('Cannot add user to github team.');
  235.                         }
  236.                     }
  237.                     $this->eventRecorder->record(new CourseInstanceMemberAdded(
  238.                         $instance->getId(),
  239.                         $instance->getCourse()->id(),
  240.                         $participant->getUser()->getId(),
  241.                         new MemberType($participant->getRole())
  242.                     ));
  243.                     $em->persist($participant);
  244.                 }
  245.             }
  246.             $em->flush();
  247.             $em->commit();
  248.             $this->eventRecorder->record(new CourseInstanceAdded((string)$instance->getId()));
  249.             return $this->redirectToRoute('instances');
  250.         }
  251.         return $this->render('admin/instance_create.html.twig', [
  252.             'form' => ($form instanceof Form) ? $form->createView() : null,
  253.         ]);
  254.     }
  255.     /**
  256.      * @Route("/admin/instance/{id}", name="instance")
  257.      * @param Instance $instance
  258.      * @param Request  $request
  259.      *
  260.      * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
  261.      * @throws \JiraRestApi\JiraException
  262.      * @throws \JsonMapper_Exception
  263.      */
  264.     public function instanceAction(
  265.         Instance $instance,
  266.         Request $request,
  267.         ICourses $courses,
  268.         EventRecorder $eventRecorder,
  269.         IRegistrationMailer $registrationMailer,
  270.         ICourseInstanceContext $instanceContext
  271.     ) {
  272.         if (!$this->getUser()->hasRole(User::ROLE_CS) &&
  273.             !$this->getUser()->hasRole(User::ROLE_SUPER_ADMIN)) {
  274.             if (!$instanceContext->isMentorOnCourseByEmail($this->getUser()->getUsername(), (string)$instance->getId())) {
  275.                 throw new AccessDeniedException("You are not assigned to this course");
  276.             }
  277.         }
  278.         $instanceForm $this->createForm(InstanceForm::class, $instance, [
  279.             'user' => $this->getUser(),
  280.             'id' => $instance->getCourse()->id()->toString(),
  281.         ]);
  282.         $instanceForm->handleRequest($request);
  283.         $em $this->getDoctrine()->getManager();
  284.         if ($instanceForm->isSubmitted() && $instanceForm->isValid()) {
  285.             $course $courses->getById($instance->getCourse()->id());
  286.             $instance->setVersion($course->getDetails()->getVersion()->value());
  287.             $instance->setLanguage($em->getRepository(Language::class)->find(
  288.                 $course->getDetails()->getTechnologyId()->toString()
  289.             ));
  290.             $em->persist($instance);
  291.             $em->flush();
  292.             $eventRecorder->record(...$instance->getEventRecorder()->pullEvents());
  293.             if ($instance->isSignatureUpdated() === true) {
  294.                 $this->eventRecorder->record(new SignatureUpdated((string)$instance->getId(), $instance->getSignature()));
  295.             }
  296.             return $this->redirectToRoute('instance', ['id' => $instance->getId()]);
  297.         }
  298.         $user = (new User())
  299.             ->setPassword($this->get('app.user.manager')::generatePassword())
  300.             ->setConfirmationToken($this->get('app.user.manager')::generatePassword());
  301.         $form $this->createForm(RegexpAndMentorInstanceType::class, $instance, [
  302.             'participation_service' => $this->participationService,
  303.             'instance_service'      => $this->instanceService,
  304.         ]);
  305.         $form->setParent(null);
  306.         $registerForm $this->createForm(RegistrationType::class, $user);
  307.         $participantsPermissionForm $this->createForm(PermissionsOfUsersInInstanceType::class, $instance);
  308.         $participantsPermissionForm->handleRequest($request);
  309.         $registerForm->handleRequest($request);
  310.         if ($registerForm->isSubmitted() && $registerForm->isValid()) {
  311.             foreach ($instance->getParticipants(InstanceUser::ROLE_MENTOR) as $participant) {
  312.                 $notification = (new Notification())
  313.                     ->setReceiver($participant->getUser())
  314.                     ->setCreator($user)
  315.                     ->setType('reg')
  316.                     ->setInstance($instance);
  317.                 $em->persist($notification);
  318.             }
  319.             $em->persist($instance);
  320.             $em->persist($user);
  321.             $em->flush();
  322.             $eventRecorder->record(...$instance->getEventRecorder()->pullEvents());
  323.             $registrationMailer->send($user);
  324.             return $this->redirectToRoute('instance', ['id' => $instance->getId()]);
  325.         }
  326.         //        THIS FORM IS HANDLED IT OTHER ROUTE
  327.         if ($participantsPermissionForm->isSubmitted() && $participantsPermissionForm->isValid()) {
  328.             foreach ($instance->getParticipants() as $participant) {
  329.                 $em->persist($participant);
  330.             }
  331.             $em->flush();
  332.             $eventRecorder->record(...$instance->getEventRecorder()->pullEvents());
  333.             return $this->redirect($request->getUri());
  334.         }
  335.         $jiraAccountsTesterForm $this->createForm(JiraAccountsType::class);
  336.         $jiraAccountsTesterForm->handleRequest($request);
  337.         $jiraAccountsCreationResult = [];
  338.         if ($jiraAccountsTesterForm->isSubmitted() && $jiraAccountsTesterForm->isValid()) {
  339.             $jiraAccountsCreationResult $this->instanceService->createJiraAccounts($instance);
  340.         }
  341.         $inactiveParticipants $this->participationService->getInactiveParticipants($instance);
  342.         $permisssionFormView = (isset($participantsPermissionForm) &&
  343.             $participantsPermissionForm instanceof Form
  344.         ) ? $participantsPermissionForm->createView() : null;
  345.         return $this->render('admin/instance.html.twig', [
  346.             'instance'                      => $instance,
  347.             'form'                          => ($form instanceof Form) ? $form->createView() : null,
  348.             'register_form'                 => (isset($registerForm) && $registerForm instanceof Form) ? $registerForm->createView() : null,
  349.             'inactive_participants'         => $inactiveParticipants,
  350.             'modules'                       => $em->getRepository('AppBundle:Module')->findBy([
  351.                 'language' => $instance->getLanguage(),
  352.                 'country'  => $instance->getMode()->getCountry(),
  353.             ]),
  354.             'participants_permission_form'  => $permisssionFormView,
  355.             'instance_form'                 => $instanceForm->createView(),
  356.             'jira_accounts_tester'          => $instance->getLanguage()->isJiraAccountCreation(),
  357.             'jira_accounts_tester_form'     => $jiraAccountsTesterForm->createView(),
  358.             'jira_accounts_creation_result' => $jiraAccountsCreationResult,
  359.         ]);
  360.     }
  361. }