Skip to content

Conversation

MHajoha
Copy link
Member

@MHajoha MHajoha commented Oct 6, 2025

Siehe auch questionpy-org/moodle-qbehaviour_questionpy#4.

Um "etwas mehr" von dem Standard-Moodle-Code (insb. question_file_saver) wiedererwenden zu können, passiert das speichern von abgegebenen Dateien in zwei Schritten:

  1. In qbehaviour_questionpy::process_action werden alle Draft-Areas, die Teil der Abgabe sind (Mitgeliefert durch ein Hidden Input außerhalb des Iframes), in eine Draft-Area vereint, und dort unter /<url-encodeter Upload-Feld-Name>/ abgelegt. Dann wird ein subdirs_question_file_saver (der normale macht keine Unterordner) erstellt.
  2. Beim speichern der Step-Daten ruft Moodle subdirs_question_file_saver::save_files auf, und speichert den ganzen Inhalt der Draft-Area in die "permanente" File-Area. Als value wird in den Step-Daten ein Hash über alle Dateien (oder '' falls keine hochgeladen wurden) abgelegt. Der wird später (u.A.?) genutzt, um zu prüfen, ob sich der Step vom vorherigen unterscheidet.

Beim Laden wird in question_ui_renderer direkt aus der persistenten File-Area in eine Draft-Area pro File-Upload kopiert.

⚠️ Das form_filemanager-Rendering hat Nebeneffekte ($PAGE->requires), daher muss question_ui_renderer::render jetzt immer im Iframe aufgerufen werden (war auch vorher so, aber ich denke nur durch Zufall, ich bin zwischendurch in diese Falle gelaufen.)

TODOs

  • Dem Paket von den hochgeladenen Dateien erzählen. TBD: Eigenes Feld oder Teil der Response? So oder so können wir es nicht in die QT-Var qpy_response schreiben (nachträgliches Setzen von normalen QT-Vars ist nicht vorgesehen). Das müsste dann vorm API-Call vereint werden.
  • Einschränkungen enforcen. Hier stellt sich die Frage, wie wir an die Einschräkungen im POST-Request kommen. (Ein hidden Input wäre offensichtlich witzlos). Vermutlich müsste der question_ui_metadata_extractor das machen, oder wir setzen beim ersten rendern eine QT-Var...
  • Der min-height-Hack ist ein Hack. Die Größe eines ggf. offenen Modals wird nicht in die Iframe-scrollHeight einberechnet, deshalb ist der File-Manager ohne das quasi unbenutzbar. Mittelfristig denke ich, die min-height sollte automagisch nur gesetzt werden, wenn tatsächlich ein File-Upload benutzt wird. Langfristig wäre es dann ideal, eine Möglichkeit zu finden, das Modal außerhalb des Iframes anzuzeigen.
  • Zum Laden erst file_prepare_draft_area (oder question_attempt::prepare_response_files_draft_itemid) aufrufen, da passieren magische und potenziell wichtige Hacks bzgl. $filerecord->source.

question.php Outdated
public function get_expected_data(): array|string {
return [
constants::QT_VAR_RESPONSE => PARAM_RAW_TRIMMED,
constants::QT_VAR_DRAFT_AREAS => PARAM_RAW_TRIMMED,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Das ist nicht ganz ideal, weil die draft area ids dann auch zu jedem Step in der Datenbank abgespeichert werden, obwohl diese Information später gar keinen Nutzen mehr hat. In ISIS ist question_attempt_step_data unsere mit Abstand größte Tabelle. Ich würde daher eine andere Lösung bevorzugen.
Mir fallen ein:

  1. Wir greifen selber auf die Daten via optional_param zu. Die Lösung ist nicht perfekt, weil \question_usage_by_activity::process_all_actions eigentlich auch ein optionales Argument $postdata hat, das aber nur für Testzwecke gedacht ist. Sollte also hinnehmbar sein.
  2. Wir speichern die Info in der User-Session, z.B. unter $SESSION->qtype_questionpy_draft_areas[$attemptid]. Du kannst in diese globale Variable einfach reinschreiben. Nachteil ist, dass man den Attempt dann nicht in mehreren Tabs öffnen und einen beliebigen davon speichern kann!?

Was denkst du?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ich glaube de Nachteil von 2. ist schon ein Blocker... Ich würde morgen eher 1. umsetzen.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im Behaviour: questionpy-org/moodle-qbehaviour_questionpy@6691384

Hier habe ich einfach den großen Commit amended.

/** @var string */
public const FILEAREA_ATTEMPT_FILES = 'response_files';
/** @var string */
public const QT_VAR_ATTEMPT_FILES = '_files';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Der Unterstrich wird uns Probleme bereiten. Beim Regrading mit \question_attempt::regrade wird \question_attempt_step::get_submitted_data aufgerufen und das überspringt "cached data", also Felder beginnend mit Unterstrich.

Ich verstehe, dass du das gemacht hast, damit im Behaviour set_qt_var benutzt werden kann. Das macht es jetzt richtig blöd, oder?

Copy link
Member Author

@MHajoha MHajoha Oct 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Es hat mir physische Schmerzen bereitet und ich habe die Edge-Cases nicht getestet, aber hier wäre ein Commit, der das Problem löst: questionpy-org/moodle-qbehaviour_questionpy@4b3b22c

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MHajoha MHajoha force-pushed the attempt-file-upload branch from d9808e0 to 67d012a Compare October 6, 2025 17:20
@MHajoha MHajoha force-pushed the attempt-file-upload branch from 67d012a to a1b52a3 Compare October 7, 2025 15:38
@MHajoha MHajoha changed the title Abgabe von Dateien qtype: Abgabe von Dateien Oct 7, 2025
return dom_utils::html_to_fragment($this->doc, $html);
}

private function render_readonly(question_attempt $qa, question_ui_renderer $renderer): DOMNode {
Copy link
Contributor

@MartinGauk MartinGauk Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hier wäre es besser, die Moodle-Renderer-Logik zu benutzen (z.B. als weitere Methode im bestehenden Renderer, ggf. mit einem Template), damit Themes die Möglichkeit zu Anpassungen haben. Dann können wir diese Ansicht auch in assignsubmission_qpy praktischerweise verwenden.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Das verstehe ich nicht ganz. question_ui_renderer ist doch gar kein Renderer im Moodle-Sinne bzw. er implementiert renderer_base nicht

Copy link
Contributor

@MartinGauk MartinGauk Oct 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So meinte ich das auch nicht. Das Erzeugen des HTMLs für die Dateiliste und die dazugehörige Logik sollte aber besser in qtype_questionpy_renderer liegen.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MartinGauk
Copy link
Contributor

MartinGauk commented Oct 8, 2025

Mir ist gerade noch eine Sache durch den Kopf gegangen. Die Bezeichnung "Attempt File" (u.a. attempt_file_service) ist ungünstig, weil ich im Konzept darunter schon die Dateien vorsehe, die vom Paket dynamisch für einen Attempt erzeugt werden (ähnlich zum attempt_state).
"Response File" ist passender.

@MHajoha MHajoha force-pushed the attempt-file-upload branch from 5de7eff to 62be6ca Compare October 9, 2025 12:13
public function get_limits_in(context $context): validatable_upload_limits {
global $CFG, $PAGE;

$maxfiles = $this->element->getAttribute('max_files');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Für die XML-Attribute sollten wir wahrscheinlich besser Bindestriche benutzen, oder?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WYSIWYG-Editor und Upload-Feld in Fragen unterstützen

2 participants