8
8
use App \Entity \Problem ;
9
9
use App \Entity \Team ;
10
10
use App \Entity \User ;
11
+ use App \Form \Type \JuryClarificationType ;
11
12
use App \Service \ConfigurationService ;
12
13
use App \Service \DOMJudgeService ;
13
14
use App \Service \EventLogService ;
14
15
use App \Utils \Utils ;
15
16
use Doctrine \ORM \EntityManagerInterface ;
16
17
use Doctrine \ORM \Query \Expr \Join ;
17
- use Symfony \Component \HtmlSanitizer \ HtmlSanitizerInterface ;
18
+ use Symfony \Component \Form \ FormInterface ;
18
19
use Symfony \Component \HttpKernel \Attribute \MapQueryParameter ;
19
20
use Symfony \Component \Security \Http \Attribute \IsGranted ;
20
21
use Symfony \Bundle \FrameworkBundle \Controller \AbstractController ;
@@ -122,32 +123,62 @@ public function indexAction(
122
123
}
123
124
124
125
#[Route(path: '/{id<\d+>} ' , name: 'jury_clarification ' )]
125
- public function viewAction (int $ id ): Response
126
+ public function viewAction (Request $ request , int $ id ): Response
126
127
{
127
128
$ clarification = $ this ->em ->getRepository (Clarification::class)->find ($ id );
128
129
if (!$ clarification ) {
129
130
throw new NotFoundHttpException (sprintf ('Clarification with ID %s not found ' , $ id ));
130
131
}
131
132
132
- $ clardata = ['list ' =>[]];
133
- $ clardata ['clarform ' ] = $ this ->getClarificationFormData ($ clarification ->getSender ());
134
- $ clardata ['showExternalId ' ] = $ this ->eventLogService ->externalIdFieldForEntity (Clarification::class);
135
-
136
- $ categories = $ clardata ['clarform ' ]['subjects ' ];
137
- $ queues = $ this ->config ->get ('clar_queues ' );
138
- $ clar_answers = $ this ->config ->get ('clar_answers ' );
139
-
140
133
if ($ inReplyTo = $ clarification ->getInReplyTo ()) {
141
134
$ clarification = $ inReplyTo ;
142
135
}
143
- $ clarlist = [$ clarification ];
136
+ $ clarificationList = [$ clarification ];
144
137
$ replies = $ clarification ->getReplies ();
145
- foreach ($ replies as $ clar_reply ) {
146
- $ clarlist [] = $ clar_reply ;
138
+ foreach ($ replies as $ reply ) {
139
+ $ clarificationList [] = $ reply ;
140
+ }
141
+
142
+ $ parameters = ['list ' => []];
143
+ $ parameters ['showExternalId ' ] = $ this ->eventLogService ->externalIdFieldForEntity (Clarification::class);
144
+
145
+ $ formData = [
146
+ 'recipient ' => JuryClarificationType::RECIPIENT_MUST_SELECT ,
147
+ 'subject ' => sprintf ('%s-%s ' , $ clarification ->getContest ()->getCid (), $ clarification ->getProblem ()?->getProbid() ?? $ clarification ->getCategory ()),
148
+ ];
149
+ if ($ clarification ->getRecipient ()) {
150
+ $ formData ['recipient ' ] = $ clarification ->getRecipient ()->getTeamid ();
151
+ }
152
+
153
+ /** @var Clarification $lastClarification */
154
+ $ lastClarification = end ($ clarificationList );
155
+ $ formData ['message ' ] = "> " . str_replace ("\n" , "\n> " , Utils::wrapUnquoted ($ lastClarification ->getBody ())) . "\n\n" ;
156
+
157
+ $ form = $ this ->createForm (JuryClarificationType::class, $ formData , ['limit_to_team ' => $ clarification ->getSender ()]);
158
+
159
+ $ form ->handleRequest ($ request );
160
+
161
+ if ($ form ->isSubmitted () && $ form ->isValid ()) {
162
+ return $ this ->processSubmittedClarification ($ form , $ clarification );
163
+ }
164
+
165
+ $ parameters ['form ' ] = $ form ->createView ();
166
+
167
+ $ categories = array_flip ($ form ->get ('subject ' )->getConfig ()->getOptions ()['choices ' ]);
168
+ $ groupedCategories = [];
169
+ foreach ($ categories as $ key => $ value ) {
170
+ if ($ this ->dj ->getCurrentContest ()) {
171
+ $ groupedCategories [$ this ->dj ->getCurrentContest ()->getShortname ()][$ key ] = $ value ;
172
+ } else {
173
+ [$ group ] = explode (' - ' , $ value , 2 );
174
+ $ groupedCategories [$ group ][$ key ] = $ value ;
175
+ }
147
176
}
177
+ $ parameters ['subjects ' ] = $ groupedCategories ;
178
+ $ queues = $ this ->config ->get ('clar_queues ' );
179
+ $ clarificationAnswers = $ this ->config ->get ('clar_answers ' );
148
180
149
- $ concernsteam = null ;
150
- foreach ($ clarlist as $ clar ) {
181
+ foreach ($ clarificationList as $ clar ) {
151
182
$ data = ['clarid ' => $ clar ->getClarid (), 'externalid ' => $ clar ->getExternalid ()];
152
183
$ data ['time ' ] = $ clar ->getSubmittime ();
153
184
@@ -161,7 +192,6 @@ public function viewAction(int $id): Response
161
192
if ($ fromteam = $ clar ->getSender ()) {
162
193
$ data ['from_teamname ' ] = $ fromteam ->getEffectiveName ();
163
194
$ data ['from_team ' ] = $ fromteam ;
164
- $ concernsteam = $ fromteam ->getTeamid ();
165
195
}
166
196
if ($ toteam = $ clar ->getRecipient ()) {
167
197
$ data ['to_teamname ' ] = $ toteam ->getEffectiveName ();
@@ -181,7 +211,7 @@ public function viewAction(int $id): Response
181
211
$ concernssubject = "" ;
182
212
}
183
213
if ($ concernssubject !== "" ) {
184
- $ data ['subject ' ] = $ categories [$ clarcontest ][ $ concernssubject ];
214
+ $ data ['subject ' ] = $ categories [$ concernssubject ];
185
215
} else {
186
216
$ data ['subject ' ] = $ clarcontest ;
187
217
}
@@ -192,104 +222,36 @@ public function viewAction(int $id): Response
192
222
$ data ['answered ' ] = $ clar ->getAnswered ();
193
223
194
224
$ data ['body ' ] = $ clar ->getBody ();
195
- $ clardata ['list ' ][] = $ data ;
196
- }
197
-
198
- if ($ concernsteam ) {
199
- $ clardata ['clarform ' ]['toteam ' ] = $ concernsteam ;
200
- }
201
- if ($ concernssubject ) {
202
- $ clardata ['clarform ' ]['onsubject ' ] = $ concernssubject ;
203
- }
204
-
205
- $ clardata ['clarform ' ]['quotedtext ' ] = "> " . str_replace ("\n" , "\n> " , Utils::wrapUnquoted ($ data ['body ' ])) . "\n\n" ;
206
- $ clardata ['clarform ' ]['queues ' ] = $ queues ;
207
- $ clardata ['clarform ' ]['answers ' ] = $ clar_answers ;
208
-
209
- return $ this ->render ('jury/clarification.html.twig ' ,
210
- $ clardata
211
- );
212
- }
213
-
214
- /**
215
- * @return array{teams: array<string|int, string>, subjects: array<string, array<string, string>>}
216
- */
217
- protected function getClarificationFormData (?Team $ team = null ): array
218
- {
219
- $ teamlist = [];
220
- $ em = $ this ->em ;
221
- if ($ team !== null ) {
222
- $ teamlist [$ team ->getTeamid ()] = sprintf ("%s (t%s) " , $ team ->getEffectiveName (), $ team ->getTeamid ());
223
- } else {
224
- $ teams = $ em ->getRepository (Team::class)->findAll ();
225
- foreach ($ teams as $ team ) {
226
- $ teamlist [$ team ->getTeamid ()] = sprintf ("%s (t%s) " , $ team ->getEffectiveName (), $ team ->getTeamid ());
227
- }
228
- }
229
- asort ($ teamlist , SORT_STRING | SORT_FLAG_CASE );
230
- $ teamlist = ['domjudge-must-select ' => '(select...) ' , '' => 'ALL ' ] + $ teamlist ;
231
-
232
- $ data = ['teams ' => $ teamlist ];
233
-
234
- $ subject_options = [];
235
-
236
- $ categories = $ this ->config ->get ('clar_categories ' );
237
- $ contest = $ this ->dj ->getCurrentContest ();
238
- $ hasCurrentContest = $ contest !== null ;
239
- if ($ hasCurrentContest ) {
240
- $ contests = [$ contest ->getCid () => $ contest ];
241
- } else {
242
- $ contests = $ this ->dj ->getCurrentContests ();
243
- }
244
-
245
- /** @var ContestProblem[] $contestproblems */
246
- $ contestproblems = $ this ->em ->createQueryBuilder ()
247
- ->from (ContestProblem::class, 'cp ' )
248
- ->select ('cp, p ' )
249
- ->innerJoin ('cp.problem ' , 'p ' )
250
- ->where ('cp.contest IN (:contests) ' )
251
- ->setParameter ('contests ' , $ contests )
252
- ->orderBy ('cp.shortname ' )
253
- ->getQuery ()->getResult ();
254
-
255
- foreach ($ contests as $ cid => $ cdata ) {
256
- $ cshort = $ cdata ->getShortName ();
257
- $ namePrefix = '' ;
258
- if (!$ hasCurrentContest ) {
259
- $ namePrefix = $ cshort . ' - ' ;
260
- }
261
- foreach ($ categories as $ name => $ desc ) {
262
- $ subject_options [$ cshort ]["$ cid- $ name " ] = "$ namePrefix $ desc " ;
263
- }
264
-
265
- foreach ($ contestproblems as $ cp ) {
266
- if ($ cp ->getCid ()!=$ cid ) {
267
- continue ;
268
- }
269
- $ subject_options [$ cshort ]["$ cid- " . $ cp ->getProbid ()] =
270
- $ namePrefix . $ cp ->getShortname () . ': ' . $ cp ->getProblem ()->getName ();
271
- }
225
+ $ parameters ['list ' ][] = $ data ;
272
226
}
273
227
274
- $ data ['subjects ' ] = $ subject_options ;
228
+ $ parameters ['queues ' ] = $ queues ;
229
+ $ parameters ['answers ' ] = $ clarificationAnswers ;
275
230
276
- return $ data ;
231
+ return $ this -> render ( ' jury/clarification.html.twig ' , $ parameters ) ;
277
232
}
278
233
279
- #[Route(path: '/send ' , methods: [ ' GET ' ], name: 'jury_clarification_new ' )]
234
+ #[Route(path: '/send ' , name: 'jury_clarification_new ' )]
280
235
public function composeClarificationAction (
236
+ Request $ request ,
281
237
#[MapQueryParameter]
282
- ?string $ teamto = null
238
+ ?string $ teamto = null ,
283
239
): Response {
284
- // TODO: Use a proper Symfony form for this.
285
-
286
- $ data = $ this ->getClarificationFormData ();
240
+ $ formData = ['recipient ' => JuryClarificationType::RECIPIENT_MUST_SELECT ];
287
241
288
242
if ($ teamto !== null ) {
289
- $ data ['toteam ' ] = $ teamto ;
243
+ $ formData ['recipient ' ] = $ teamto ;
244
+ }
245
+
246
+ $ form = $ this ->createForm (JuryClarificationType::class, $ formData );
247
+
248
+ $ form ->handleRequest ($ request );
249
+
250
+ if ($ form ->isSubmitted () && $ form ->isValid ()) {
251
+ return $ this ->processSubmittedClarification ($ form );
290
252
}
291
253
292
- return $ this ->render ('jury/clarification_new.html.twig ' , ['clarform ' => $ data ]);
254
+ return $ this ->render ('jury/clarification_new.html.twig ' , ['form ' => $ form -> createView () ]);
293
255
}
294
256
295
257
#[Route(path: '/{clarId<\d+>}/claim ' , name: 'jury_clarification_claim ' )]
@@ -387,30 +349,25 @@ public function changeQueueAction(Request $request, int $clarId): Response
387
349
return $ this ->redirectToRoute ('jury_clarification ' , ['id ' => $ clarId ]);
388
350
}
389
351
390
- #[Route(path: '/send ' , methods: ['POST ' ], name: 'jury_clarification_send ' )]
391
- public function sendAction (Request $ request , HtmlSanitizerInterface $ htmlSanitizer ): Response
392
- {
352
+ protected function processSubmittedClarification (
353
+ FormInterface $ form ,
354
+ ?Clarification $ inReplTo = null
355
+ ): Response {
356
+ $ formData = $ form ->getData ();
393
357
$ clarification = new Clarification ();
358
+ $ clarification ->setInReplyTo ($ inReplTo );
394
359
395
- if ($ respid = $ request ->request ->get ('id ' )) {
396
- $ respclar = $ this ->em ->getRepository (Clarification::class)->find ($ respid );
397
- $ clarification ->setInReplyTo ($ respclar );
398
- }
399
-
400
- $ sendto = $ request ->request ->get ('sendto ' );
401
- if (empty ($ sendto )) {
402
- $ sendto = null ;
403
- } elseif ($ sendto === 'domjudge-must-select ' ) {
404
- $ message = 'You must select somewhere to send the clarification to. ' ;
405
- $ this ->addFlash ('danger ' , $ message );
406
- return $ this ->redirectToRoute ('jury_clarification_send ' );
360
+ $ recipient = $ formData ['recipient ' ];
361
+ if (empty ($ recipient )) {
362
+ $ recipient = null ;
407
363
} else {
408
- $ team = $ this ->em ->getReference (Team::class, $ sendto );
364
+ $ team = $ this ->em ->getReference (Team::class, $ recipient );
409
365
$ clarification ->setRecipient ($ team );
410
366
}
411
367
412
- $ problem = $ request ->request ->get ('problem ' );
413
- [$ cid , $ probid ] = explode ('- ' , $ problem );
368
+
369
+ $ subject = $ formData ['subject ' ];
370
+ [$ cid , $ probid ] = explode ('- ' , $ subject );
414
371
415
372
$ contest = $ this ->em ->getReference (Contest::class, $ cid );
416
373
$ clarification ->setContest ($ contest );
@@ -428,8 +385,8 @@ public function sendAction(Request $request, HtmlSanitizerInterface $htmlSanitiz
428
385
}
429
386
}
430
387
431
- if ($ respid ) {
432
- $ queue = $ respclar ->getQueue ();
388
+ if ($ inReplTo ) {
389
+ $ queue = $ inReplTo ->getQueue ();
433
390
} else {
434
391
$ queue = $ this ->config ->get ('clar_default_problem_queue ' );
435
392
if ($ queue === "" ) {
@@ -440,14 +397,13 @@ public function sendAction(Request $request, HtmlSanitizerInterface $htmlSanitiz
440
397
441
398
$ clarification ->setJuryMember ($ this ->getUser ()->getUserIdentifier ());
442
399
$ clarification ->setAnswered (true );
443
- $ clarification ->setBody ($ htmlSanitizer -> sanitize ( $ request -> request -> get ( ' bodytext ' )) );
400
+ $ clarification ->setBody ($ formData [ ' message ' ] );
444
401
$ clarification ->setSubmittime (Utils::now ());
445
402
446
403
$ this ->em ->persist ($ clarification );
447
- if ($ respid ) {
448
- $ respclar ->setAnswered (true );
449
- $ respclar ->setJuryMember ($ this ->getUser ()->getUserIdentifier ());
450
- $ this ->em ->persist ($ respclar );
404
+ if ($ inReplTo ) {
405
+ $ inReplTo ->setAnswered (true );
406
+ $ inReplTo ->setJuryMember ($ this ->getUser ()->getUserIdentifier ());
451
407
}
452
408
$ this ->em ->flush ();
453
409
@@ -457,9 +413,8 @@ public function sendAction(Request $request, HtmlSanitizerInterface $htmlSanitiz
457
413
// Reload clarification to make sure we have a fresh one after calling the event log service.
458
414
$ clarification = $ this ->em ->getRepository (Clarification::class)->find ($ clarId );
459
415
460
- if ($ sendto ) {
461
- $ team = $ this ->em ->getRepository (Team::class)->find ($ sendto );
462
- $ team ->addUnreadClarification ($ clarification );
416
+ if ($ clarification ->getRecipient ()) {
417
+ $ clarification ->getRecipient ()->addUnreadClarification ($ clarification );
463
418
} else {
464
419
$ teams = $ this ->em ->getRepository (Team::class)->findAll ();
465
420
foreach ($ teams as $ team ) {
0 commit comments