21
21
use App \Model \Entity \ExerciseEnvironmentConfig ;
22
22
use App \Model \Entity \ExerciseTest ;
23
23
use App \Model \Repository \Exercises ;
24
+ use App \Model \Repository \ExerciseTests ;
24
25
use App \Model \Repository \HardwareGroups ;
25
26
use App \Model \Repository \Pipelines ;
26
27
use App \Model \Repository \ReferenceSolutionSubmissions ;
@@ -43,6 +44,12 @@ class ExercisesConfigPresenter extends BasePresenter {
43
44
*/
44
45
public $ exercises ;
45
46
47
+ /**
48
+ * @var ExerciseTests
49
+ * @inject
50
+ */
51
+ public $ exerciseTests ;
52
+
46
53
/**
47
54
* @var Pipelines
48
55
* @inject
@@ -598,35 +605,52 @@ public function actionSetTests(string $id) {
598
605
$ req = $ this ->getRequest ();
599
606
$ tests = $ req ->getPost ("tests " );
600
607
608
+ /*
609
+ * We need to implement CoW on tests.
610
+ * All modified tests has to be newly created (with new IDs) and these
611
+ * new IDs has to be propagated into configuration and limits.
612
+ * Therefore a replacement mapping of updated tests is kept.
613
+ */
614
+
601
615
$ newTests = [];
616
+ $ namesToOldIds = []; // new test name => old test ID
617
+
602
618
foreach ($ tests as $ test ) {
619
+ // Perform checks on the test name...
603
620
if (!array_key_exists ("name " , $ test )) {
604
621
throw new InvalidArgumentException ("tests " , "name item not found in particular test " );
605
622
}
606
623
607
- $ name = $ test ["name " ];
624
+ $ name = trim ($ test ["name " ]);
625
+ if (!preg_match ('/^[-a-zA-Z0-9_()\[\].! ]+$/ ' , $ name )) {
626
+ throw new InvalidArgumentException ("tests " , "test name contains illicit characters " );
627
+ }
628
+ if (strlen ($ name ) > 64 ) {
629
+ throw new InvalidArgumentException ("tests " , "test name too long (exceeds 64 characters) " );
630
+ }
631
+ if (array_key_exists ($ name , $ newTests )) {
632
+ throw new InvalidArgumentException ("tests " , "two tests with the same name ' $ name' were specified " );
633
+ }
634
+
608
635
$ id = Arrays::get ($ test , "id " , null );
609
- $ description = Arrays::get ($ test , "description " , "" );
636
+ $ description = trim ( Arrays::get ($ test , "description " , "" ) );
610
637
638
+ // Prepare a test entity that is to be inserted into the new list of tests...
611
639
$ testEntity = $ id ? $ exercise ->getExerciseTestById ($ id ) : null ;
612
640
if ($ testEntity === null ) {
613
641
// new exercise test was requested to be created
614
642
if ($ exercise ->getExerciseTestByName ($ name )) {
615
643
throw new InvalidArgumentException ("tests " , "given test name ' $ name' is already taken " );
616
644
}
617
645
618
- $ testEntity = new ExerciseTest (trim ($ name ), $ description , $ this ->getCurrentUser ());
619
- } else {
620
- // update of existing exercise test with all appropriate fields
621
- $ testEntity ->setName (trim ($ name ));
622
- $ testEntity ->setDescription ($ description );
623
- $ testEntity ->updatedNow ();
646
+ $ testEntity = new ExerciseTest ($ name , $ description , $ this ->getCurrentUser ());
647
+ } elseif ($ testEntity ->getName () !== $ name || $ testEntity ->getDescription () !== $ description ) {
648
+ // an update is needed => a copy is made and old ID mapping is kept
649
+ $ namesToOldIds [$ name ] = $ id ;
650
+ $ testEntity = new ExerciseTest ($ name , $ description , $ testEntity ->getAuthor ());
624
651
}
652
+ // otherwise, the $testEntity is unchanged
625
653
626
-
627
- if (array_key_exists ($ name , $ newTests )) {
628
- throw new InvalidArgumentException ("tests " , "two tests with the same name ' $ name' were specified " );
629
- }
630
654
$ newTests [$ name ] = $ testEntity ;
631
655
}
632
656
@@ -638,20 +662,39 @@ public function actionSetTests(string $id) {
638
662
);
639
663
}
640
664
641
- // clear old tests and set new ones
642
- $ exercise ->getExerciseTests ()->clear ();
643
- $ exercise ->setExerciseTests (new ArrayCollection ($ newTests ));
665
+ $ this ->exercises ->beginTransaction ();
666
+ try {
667
+ // clear old tests and set new ones
668
+ $ exercise ->getExerciseTests ()->clear ();
669
+ $ exercise ->setExerciseTests (new ArrayCollection ($ newTests ));
670
+ $ this ->exercises ->flush ();
644
671
645
- // update exercise configuration and test in here
646
- $ this ->exerciseConfigUpdater ->testsUpdated ($ exercise , $ this ->getCurrentUser (), false );
672
+ // now we need to get IDs of newly created tests
673
+ $ idMapping = []; // old ID => new ID
674
+ foreach ($ newTests as $ test ) {
675
+ $ this ->exerciseTests ->refresh ($ test );
676
+ if (array_key_exists ($ test ->getName (), $ namesToOldIds )) {
677
+ $ oldId = $ namesToOldIds [$ test ->getName ()];
678
+ $ idMapping [$ oldId ] = $ test ->getId ();
679
+ }
680
+ }
647
681
648
- $ exercise-> updatedNow ();
649
- $ this ->exercises -> flush ( );
682
+ // update exercise configuration and test in here
683
+ $ this ->exerciseConfigUpdater -> testsUpdated ( $ exercise , $ this -> getCurrentUser (), $ idMapping , false );
650
684
651
- $ this -> configChecker -> check ( $ exercise );
652
- $ this ->exercises ->flush ();
685
+ $ exercise -> updatedNow ( );
686
+ $ this ->exercises ->flush ();
653
687
654
- $ this ->sendSuccessResponse ($ exercise ->getExerciseTests ()->getValues ());
688
+ $ this ->configChecker ->check ($ exercise );
689
+ $ this ->exercises ->flush ();
690
+ $ this ->exercises ->commit ();
691
+ }
692
+ catch (\Exception $ e ) {
693
+ $ this ->exercises ->rollBack ();
694
+ throw $ e ;
695
+ }
696
+
697
+ $ this ->sendSuccessResponse (array_values ($ newTests ));
655
698
}
656
699
657
700
}
0 commit comments