3232use qtype_questionpy \local \api \scoring_code ;
3333use qtype_questionpy \local \api \wysiwyg_editor_data ;
3434use qtype_questionpy \local \attempt_ui \question_ui_metadata_extractor ;
35- use qtype_questionpy \local \files \file_metadata ;
35+ use qtype_questionpy \local \api \file_metadata ;
3636use qtype_questionpy \local \files \response_file_service ;
3737use qtype_questionpy \question_bridge_base ;
3838use qtype_questionpy \utils ;
@@ -201,25 +201,19 @@ public function apply_attempt_state(question_attempt_step $step) {
201201 question_attempt->start_question_based_on, where we shouldn't need to get the UI. */
202202 try {
203203 $ lastresponsestep = $ qa ->get_last_step_with_qt_var (constants::QT_VAR_RESPONSE );
204- $ lastresponse = utils::get_qpy_response ($ lastresponsestep ->get_qt_data ());
205-
206- $ allfiles = $ this ->rfs ->get_all_files_from_qt_data ($ lastresponsestep ->get_qt_data ());
207- $ editors = utils::get_qpy_editors_data ($ lastresponsestep ->get_qt_data ());
208- array_walk (
209- $ editors ,
210- fn (&$ editordata , $ editorname ) => $ editordata = $ this ->build_wysiwyg_data ($ editorname , $ editordata , $ allfiles )
211- );
204+ [$ lastresponse , $ uploads , $ editors ] = $ this ->prepare_responses_for_server ($ lastresponsestep ->get_qt_data ());
212205
213206 $ attributes = $ this ->get_requested_attributes ();
214207
215208 $ attempt = $ this ->api ->package ($ this ->packagehash , $ this ->packagefile )
216209 ->view_attempt (
217- $ this ->questionstate ,
218- $ attributes ,
219- $ this ->attemptstate ,
220- $ this ->scoringstate ,
221- $ lastresponse ,
222- $ editors ,
210+ questionstate: $ this ->questionstate ,
211+ attributes: $ attributes ,
212+ attemptstate: $ this ->attemptstate ,
213+ scoringstate: $ this ->scoringstate ,
214+ response: $ lastresponse ,
215+ uploads: $ uploads ,
216+ editors: $ editors ,
223217 );
224218 $ this ->update_attempt ($ attempt );
225219 $ this ->errorduringload = false ;
@@ -444,30 +438,6 @@ public function get_validation_error(array $response) {
444438 return '' ;
445439 }
446440
447- /**
448- * Joins the raw editor data with the files that belong to it ands returns a {@see wysiwyg_editor_data} object.
449- *
450- * @param string $editorname
451- * @param object $rawdata
452- * @param stored_file[] $allfiles
453- * @return wysiwyg_editor_data
454- * @throws coding_exception
455- */
456- private function build_wysiwyg_data (string $ editorname , object $ rawdata , array $ allfiles ): wysiwyg_editor_data {
457- $ filemetas = [];
458- foreach (response_file_service::filter_combined_files_for_field ($ allfiles , $ editorname ) as $ filename => $ file ) {
459- $ filemetas [] = file_metadata::from_stored_file ($ file , overridename: $ filename );
460- }
461-
462- // TODO: Turn @@PLUGINFILE@@-links into QPy-URLs?
463-
464- return new wysiwyg_editor_data (
465- text: $ rawdata ->text ,
466- textformat: $ rawdata ->format ,
467- files: $ filemetas ,
468- );
469- }
470-
471441 /**
472442 * Grade a response to the question, returning a fraction between
473443 * get_min_fraction() and get_max_fraction(), and the corresponding {@see question_state}
@@ -485,20 +455,16 @@ public function grade_response(array $response): array {
485455 try {
486456 $ attributes = $ this ->get_requested_attributes ();
487457
488- $ allfiles = $ this ->rfs ->get_all_files_from_qt_data ($ response );
489- $ editors = utils::get_qpy_editors_data ($ response );
490- array_walk (
491- $ editors ,
492- fn (&$ editordata , $ editorname ) => $ editordata = $ this ->build_wysiwyg_data ($ editorname , $ editordata , $ allfiles )
493- );
458+ [$ qpyresponse , $ uploads , $ editors ] = $ this ->prepare_responses_for_server ($ response );
494459
495460 $ attemptscored = $ this ->api ->package ($ this ->packagehash , $ this ->packagefile )->score_attempt (
496- $ this ->questionstate ,
497- $ attributes ,
498- $ this ->attemptstate ,
499- $ this ->scoringstate ,
500- utils::get_qpy_response ($ response ) ?? (object )[],
501- $ editors
461+ questionstate: $ this ->questionstate ,
462+ attributes: $ attributes ,
463+ attemptstate: $ this ->attemptstate ,
464+ scoringstate: $ this ->scoringstate ,
465+ response: $ qpyresponse ?? (object )[],
466+ uploads: $ uploads ,
467+ editors: $ editors ,
502468 );
503469 $ this ->update_attempt ($ attemptscored );
504470 } catch (Throwable $ t ) {
@@ -537,6 +503,48 @@ public function grade_response(array $response): array {
537503 return [$ attemptscored ->score , $ newqstate ];
538504 }
539505
506+ /**
507+ * Converts the given QT data to the response, uploads, and editors that are expected by the QuestionPy server.
508+ *
509+ * @param array $responseqtdata The qt data that is being scored or viewed.
510+ * @return array A tuple of `[$response, $uploads, $editors]`.
511+ * @throws coding_exception
512+ */
513+ private function prepare_responses_for_server (array $ responseqtdata ): array {
514+ $ lastresponse = utils::get_qpy_response ($ responseqtdata );
515+
516+ $ filesbyfield = $ this ->rfs ->get_all_files_from_qt_data ($ responseqtdata );
517+ $ raweditors = utils::get_qpy_editors_data ($ responseqtdata );
518+
519+ $ editors = [];
520+ foreach ($ raweditors as $ editorname => $ editordata ) {
521+ $ filemetas = [];
522+ if (isset ($ filesbyfield [$ editorname ])) {
523+ foreach ($ filesbyfield [$ editorname ] as $ filename => $ file ) {
524+ $ filemetas [] = file_metadata::from_stored_file ($ file , overridename: $ filename );
525+ }
526+ }
527+
528+ // TODO: Turn @@PLUGINFILE@@-links into QPy-URLs?
529+
530+ $ editors [$ editorname ] = new wysiwyg_editor_data (
531+ text: $ editordata ->text ,
532+ textformat: $ editordata ->format ,
533+ files: $ filemetas ,
534+ );
535+ }
536+
537+ $ uploads = [];
538+ // Any files that don't belong to editors must belong to file upload elements.
539+ foreach (array_diff_key ($ filesbyfield , $ editors ) as $ fieldname => $ files ) {
540+ foreach ($ files as $ filename => $ file ) {
541+ $ uploads [$ fieldname ][] = file_metadata::from_stored_file ($ file , overridename: $ filename );
542+ }
543+ }
544+
545+ return [$ lastresponse , $ uploads , $ editors ];
546+ }
547+
540548 /**
541549 * Work out a final grade for this attempt, taking into account all the
542550 * tries the student made.
0 commit comments