diff --git a/webapp/src/Controller/Jury/ClarificationController.php b/webapp/src/Controller/Jury/ClarificationController.php index a31a3000ee..094c4f5fb3 100644 --- a/webapp/src/Controller/Jury/ClarificationController.php +++ b/webapp/src/Controller/Jury/ClarificationController.php @@ -151,7 +151,7 @@ public function viewAction(Request $request, int $id): Response $lastClarification = end($clarificationList); $formData['message'] = "> " . str_replace("\n", "\n> ", Utils::wrapUnquoted($lastClarification->getBody())) . "\n\n"; - $form = $this->createForm(JuryClarificationType::class, $formData, ['limit_to_team' => $clarification->getSender()]); + $form = $this->createForm(JuryClarificationType::class, $formData, ['limit_to_team' => $clarification->getSender(), 'clarid' => $id]); $form->handleRequest($request); @@ -224,6 +224,13 @@ public function viewAction(Request $request, int $id): Response $parameters['queues'] = $queues; $parameters['answers'] = $clarificationAnswers; + $parameters['jurymember'] = $this->em->createQueryBuilder() + ->select('clar.jury_member') + ->from(Clarification::class, 'clar') + ->where('clar.clarid = :clarid') + ->setParameter('clarid', $id) + ->getQuery() + ->getSingleResult()['jury_member']; return $this->render('jury/clarification.html.twig', $parameters); } diff --git a/webapp/src/Form/Type/JuryClarificationType.php b/webapp/src/Form/Type/JuryClarificationType.php index cb6c7d2eab..a379c8ed5f 100644 --- a/webapp/src/Form/Type/JuryClarificationType.php +++ b/webapp/src/Form/Type/JuryClarificationType.php @@ -2,6 +2,7 @@ namespace App\Form\Type; +use App\Entity\Clarification; use App\Entity\ContestProblem; use App\Entity\Team; use App\Service\ConfigurationService; @@ -9,15 +10,21 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Validator\Constraints\NotEqualTo; +use Symfony\Component\Validator\Constraints\Callback; +use Symfony\Component\Validator\Context\ExecutionContextInterface; class JuryClarificationType extends AbstractType { public const RECIPIENT_MUST_SELECT = 'domjudge-must-select'; + /** @var int The clarification entity id if the entity exists in the database */ + private $clarid; + public function __construct( private readonly EntityManagerInterface $em, private readonly ConfigurationService $config, @@ -26,6 +33,7 @@ public function __construct( public function buildForm(FormBuilderInterface $builder, array $options): void { + $this->clarid = $options['clarid']; $recipientOptions = [ '(select...)' => static::RECIPIENT_MUST_SELECT, 'ALL' => '', @@ -104,11 +112,18 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'cols' => 85, ], ]); + + $builder->add('jurymember', HiddenType::class, [ + 'constraints' => [ + new Callback([$this, 'checkJuryMember']) + ] + ]); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefault('limit_to_team', null); + $resolver->setDefault('clarid', null); } private function getTeamLabel(Team $team): string @@ -119,4 +134,25 @@ private function getTeamLabel(Team $team): string return sprintf('%s (%s)', $team->getEffectiveName(), $team->getExternalId()); } + + public function checkJuryMember(mixed $value, ExecutionContextInterface $context, mixed $payload): void + { + if ($this->clarid) { + $juryMember = $this->em->createQueryBuilder() + ->select('clar.jury_member') + ->from(Clarification::class, 'clar') + ->where('clar.clarid = :clarid') + ->setParameter('clarid', $this->clarid) + ->getQuery() + ->getSingleResult()['jury_member']; + + // If jury member changed, and we are not currently assigned, warn. + if ($value !== $juryMember && $this->dj->getUser()->getUserIdentifier() !== $juryMember) { + $context->buildViolation("Jury Member '%jury%' claimed this clarification in the meantime. + Please resubmit if you want to continue.") + ->setParameter('%jury%', $juryMember) + ->addViolation(); + } + } + } } diff --git a/webapp/templates/jury/partials/clarification_form.html.twig b/webapp/templates/jury/partials/clarification_form.html.twig index ca2423d258..48d676bbe9 100644 --- a/webapp/templates/jury/partials/clarification_form.html.twig +++ b/webapp/templates/jury/partials/clarification_form.html.twig @@ -10,6 +10,7 @@ +{{ form_errors(form) }}