src/Lms/UserInterface/WebApp/Controller/QuizWebhookController.php line 77

Open in your IDE?
  1. <?php
  2. namespace CodersLab\Lms\UserInterface\WebApp\Controller;
  3. use CodersLab\Lms\Modules\Learning\Application\Command\AddMaterialResultAsync;
  4. use CodersLab\Lms\Modules\Materials\Application\Query\QuizQuery;
  5. use CodersLab\Lms\Modules\Materials\Application\Service\SurveyMonkeyProxy\ProxyClient;
  6. use CodersLab\Lms\Modules\Materials\Domain\Materials;
  7. use CodersLab\Lms\Modules\Materials\Domain\Quiz\State;
  8. use CodersLab\Lms\Modules\Materials\Domain\Quizzes;
  9. use CodersLab\Lms\SharedKernel\Common\Assert;
  10. use CodersLab\Lms\SharedKernel\Common\Exception\InvalidArgumentException;
  11. use CodersLab\Lms\SharedKernel\Domain\Bus\CommandBus;
  12. use CodersLab\Lms\SharedKernel\Domain\Bus\IEventRecorder;
  13. use CodersLab\Lms\SharedKernel\Domain\Identity\Uuid;
  14. use Exception;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use Symfony\Component\HttpFoundation\Response;
  17. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  18. use Symfony\Component\Routing\Annotation\Route;
  19. final class QuizWebhookController
  20. {
  21.     public function __construct(
  22.         private Quizzes $quizzes,
  23.         private CommandBus $commandBus,
  24.         private IEventRecorder $eventRecorder,
  25.         private ProxyClient $proxyClient,
  26.         private Materials $materials,
  27.         private QuizQuery $quizQuery
  28.     ) {
  29.     }
  30.     /**
  31.      * @Route("/webhooks/quiz/update/{quizProviderId}", name="webhook_quiz_update", methods={"GET", "POST"})
  32.      */
  33.     public function quizUpdate(Request $request): Response
  34.     {
  35.         if ($request->getMethod() === Request::METHOD_HEAD) {
  36.             return new Response();
  37.         }
  38.         $content json_decode((string)$request->getContent(), true);
  39.         try {
  40.             Assert::isArray($content);
  41.             Assert::keyExists($content'object_type');
  42.             Assert::keyExists($content'event_type');
  43.             Assert::keyExists($content'object_id');
  44.             Assert::keyExists($content'resources');
  45.             Assert::eq($content['object_type'], 'survey');
  46.             Assert::eq($content['event_type'], 'survey_updated');
  47.             Assert::notEmpty($content['object_id']);
  48.             Assert::string($content['object_id']);
  49.             Assert::isArray($content['resources']);
  50.             Assert::keyExists($content['resources'], 'survey_id');
  51.             Assert::string($content['resources']['survey_id']);
  52.             $quiz $this->quizzes->findByProviderId($content['resources']['survey_id']);
  53.             Assert::notNull($quiz);
  54.         } catch (InvalidArgumentException $exception) {
  55.             throw new BadRequestHttpException($exception->getMessage(), $exception);
  56.         }
  57.         if ($quiz->state()->hasDetails()) {
  58.             $quiz->subtractState(State::DETAILS());
  59.         }
  60.         $this->eventRecorder->record(...$quiz->getEventRecorder()->pullEvents());
  61.         return new Response();
  62.     }
  63.     /**
  64.      * @Route("/webhooks/quiz/result/{quizProviderId}", name="webhook_quiz_response", methods={"GET", "POST"})
  65.      */
  66.     public function quizResponse(Request $request): Response
  67.     {
  68.         if ($request->getMethod() === Request::METHOD_HEAD) {
  69.             return new Response();
  70.         }
  71.         $content json_decode((string)$request->getContent(), true);
  72.         if ($content === null) {
  73.             throw new Exception((string)$request->getContent());
  74.         }
  75.         try {
  76.             Assert::isArray($content);
  77.             Assert::keyExists($content'object_type');
  78.             Assert::keyExists($content'event_type');
  79.             Assert::keyExists($content'object_id');
  80.             Assert::keyExists($content'resources');
  81.             Assert::eq($content['object_type'], 'response');
  82.             Assert::eq($content['event_type'], 'response_completed');
  83.             Assert::notEmpty($content['object_id']);
  84.             Assert::string($content['object_id']);
  85.             Assert::isArray($content['resources']);
  86.             Assert::keyExists($content['resources'], 'survey_id');
  87.             Assert::string($content['resources']['survey_id']);
  88.             $quiz $this->quizzes->findByProviderId($content['resources']['survey_id']);
  89.             Assert::notNull($quiz);
  90.         } catch (InvalidArgumentException $exception) {
  91.             throw new BadRequestHttpException($exception->getMessage(), $exception);
  92.         }
  93.         $response $this->proxyClient->getResponse(
  94.             $content['resources']['survey_id'],
  95.             $content['object_id']
  96.         );
  97.         $materials $this->materials->findByQuizAndCourse($quiz->id(), new Uuid($response->getCourseId()));
  98.         foreach ($materials as $material) {
  99.             $command = new AddMaterialResultAsync(
  100.                 $response->getCourseId(),
  101.                 $response->getCourseInstanceId(),
  102.                 $response->getStudentId(),
  103.                 $this->quizQuery->getMaterialCriterionIdForQuiz($material->getUuid()),
  104.                 $response->getStudentId(),
  105.                 'student',
  106.                 $response->getScore()
  107.             );
  108.             $this->commandBus->dispatch($command);
  109.         }
  110.         return new Response();
  111.     }
  112. }