22 require_once
'./Modules/Test/classes/inc.AssessmentConstants.php';
43 private \ILIAS\ResourceStorage\Services
$irss;
79 $this->irss = $DIC->resourceStorage();
80 $this->file_delivery = $DIC->fileDelivery();
81 $this->file_upload = $DIC->upload();
82 $this->current_cmd = $DIC[
'ilCtrl']->getCmd();
121 $ilDB = $DIC[
'ilDB'];
129 ) .
' (question_fi, maxsize, allowedextensions, compl_by_submission) VALUES (%s, %s, %s, %s)',
130 [
'integer',
'float',
'text',
'integer' ],
148 $ilDB = $DIC[
'ilDB'];
149 $result =
$ilDB->queryF(
153 .
'.question_fi = qpl_questions.question_id WHERE qpl_questions.question_id = %s',
157 if ($result->numRows() == 1) {
159 $this->
setId($question_id);
161 $this->
setComment((
string) $data[
'description']);
170 $this->
setMaxSize(($data[
'maxsize'] ?? null) ? (
int) $data[
'maxsize'] : null);
185 parent::loadFromDb($question_id);
192 bool $for_test =
true,
198 if ($this->
id <= 0) {
203 $this_id = $this->
getId();
207 $original_id = $this->questioninfo->getOriginalId($this->
id);
210 if ((
int) $testObjId > 0) {
211 $clone->setObjId($testObjId);
232 $clone->copyPageOfQuestion($this_id);
234 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
236 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
246 if ($this->
getId() <= 0) {
247 throw new RuntimeException(
'The question has not been saved. It cannot be duplicated');
251 $original_id = $this->questioninfo->getOriginalId($this->
id);
253 $source_questionpool_id = $this->
getObjId();
254 $clone->setObjId($target_questionpool_id);
265 $clone->onCopy($source_questionpool_id,
$original_id, $clone->getObjId(), $clone->getId());
272 if ($this->
getId() <= 0) {
273 throw new RuntimeException(
'The question has not been saved. It cannot be duplicated');
277 $sourceParentId = $this->
getObjId();
283 $clone->setObjId($targetParentId);
285 if ($targetQuestionTitle) {
286 $clone->setTitle($targetQuestionTitle);
291 $clone->copyPageOfQuestion($sourceQuestionId);
293 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
295 $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
320 public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution =
true, $returndetails =
false): float
322 if ($returndetails) {
323 throw new ilTestException(
'return details not implemented for ' . __METHOD__);
327 if (is_null($pass)) {
335 while (
$data = $DIC->database()->fetchAssoc($result)) {
350 is_array($userSolution) &&
351 count($userSolution)) {
365 $this->
lng->loadLanguageModule(
'form');
368 $this->file_upload->getResults() as $upload_result
370 if (!$upload_result->isOK()) {
371 $this->tpl->setOnScreenMessage(
'failure', $upload_result->getStatus()->getMessage(),
true);
376 $size_bytes = $upload_result->getSize();
378 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'form_msg_file_size_exceeds'),
true);
384 $filename_arr = pathinfo($upload_result->getName());
385 $suffix = $filename_arr[
'extension'] ??
'';
386 $mimetype = $upload_result->getMimeType();
387 if ($suffix ===
'') {
388 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'form_msg_file_missing_file_ext'),
true);
393 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'form_msg_file_wrong_file_type'),
true);
407 if (is_null($question_id)) {
408 $question_id = $this->
getId();
410 return CLIENT_WEB_DIR .
"/assessment/tst_{$test_id}/{$active_id}/{$question_id}/files/";
418 return CLIENT_WEB_DIR .
"/assessment/qst_preview/{$userId}/{$this->getId()}/fileuploads/";
428 if (is_null($question_id)) {
429 $question_id = $this->
getId();
432 .
"/assessment/tst_{$test_id}/{$active_id}/{$question_id}/files/";
446 .
"/assessment/qst_preview/{$userId}/{$this->getId()}/fileuploads/";
462 $ilDB = $DIC[
'ilDB'];
464 if (is_null($pass)) {
468 $result =
$ilDB->queryF(
469 'SELECT * FROM tst_solutions WHERE active_fi = %s ' 470 .
'AND question_fi = %s AND pass = %s AND authorized = %s ' 471 .
'AND value1 IS NOT NULL ORDER BY tstamp',
472 [
'integer',
'integer',
'integer',
'integer'],
473 [$active_id, $this->
getId(), $pass, (
int) $authorized]
479 array_push($found,
$data);
502 $result = $this->db->queryF(
503 'SELECT test_fi FROM tst_active WHERE active_id = %s',
507 if ($result->numRows() == 1) {
508 $row = $this->db->fetchAssoc($result);
511 foreach ($found as $idx =>
$data) {
516 if (
$data[
'value2'] ===
'rid') {
517 $rid = $this->irss->manage()->find(
$data[
'value1']);
521 $revision = $this->irss->manage()->getCurrentRevision($rid);
522 $stream = $this->irss->consume()->stream($rid)->getStream();
523 $url = $this->file_delivery->buildTokenURL(
525 $revision->getTitle(),
526 Disposition::ATTACHMENT,
527 $this->current_user->getId(),
532 $found[$idx][
'webpath'] =
$path;
533 $found[$idx][
'value2'] = $revision->getTitle();
535 $found[$idx][
'webpath'] =
$path;
549 protected function deleteUnusedFiles(array $rids_to_delete,
$test_id, $active_id, $pass):
void 552 if ($rids_to_delete !== []) {
553 foreach ($rids_to_delete as $rid_to_delete) {
554 $rid_to_delete = $this->irss->manage()->find($rid_to_delete);
555 if ($rid_to_delete === null) {
558 $this->irss->manage()->remove(
570 $solutions = array_merge(
578 foreach ($solutions as $solution) {
579 $used_files[] = $solution[
'value1'];
585 if (is_dir($uploadPath) && is_readable($uploadPath)) {
586 $iter = new \RegexIterator(
new \DirectoryIterator($uploadPath),
'/^file_' . $active_id .
'_' . $pass .
'_(.*)/');
587 foreach ($iter as $file) {
589 if ($file->isFile() && !in_array($file->getFilename(), $used_files)) {
590 unlink($file->getPathname());
599 foreach ($files as $name) {
600 if (isset($userSolution[$name])) {
601 unset($userSolution[$name]);
606 return $userSolution;
613 return sprintf(
'%d Bytes', $size);
616 if ($size < 1024 * 1024) {
617 return sprintf(
'%.1f KB', $size / 1024);
620 return sprintf(
'%.1f MB', $size / 1024 / 1024);
635 $upload_max_filesize = ini_get(
'upload_max_filesize');
636 $post_max_size = ini_get(
'post_max_size');
639 $multiplier_a = [
"K" => 1024,
"M" => 1024 * 1024,
"G" => 1024 * 1024 * 1024 ];
640 $umf_parts = preg_split(
642 $upload_max_filesize,
644 PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
646 $pms_parts = preg_split(
650 PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
653 if (count($umf_parts) === 2) {
654 $upload_max_filesize = $umf_parts[0] * $multiplier_a[$umf_parts[1]];
657 if (count($pms_parts) === 2) {
658 $post_max_size = $pms_parts[0] * $multiplier_a[$pms_parts[1]];
662 $max_filesize = min($upload_max_filesize, $post_max_size);
664 if (!$max_filesize) {
665 $max_filesize = max($upload_max_filesize, $post_max_size);
666 return $max_filesize;
669 return $max_filesize;
679 if ($pass === null || $pass < 0) {
683 $test_id = $this->testParticipantInfo->lookupTestIdByActiveId($active_id);
686 $upload_handling_required = $this->current_cmd !==
'submitSolution' 687 && $this->current_cmd !==
'showInstantResponse' 692 $this->tpl->setOnScreenMessage(
'failure', $e->getMessage(),
true);
698 if ($upload_handling_required) {
700 $upload_results = $this->file_upload->getResults();
701 $upload_result = end($upload_results);
702 $rid = $this->irss->manage()->upload(
708 $entered_values =
false;
720 $upload_handling_required,
727 if ($authorized ===
false) {
733 foreach ($_POST[self::DELETE_FILES_TBL_POSTVAR] as $solution_id) {
737 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'no_checkbox'),
true);
741 foreach ($_POST[self::REUSE_FILES_TBL_POSTVAR] as $solutionId) {
755 if ($upload_handling_required && $rid !== null) {
757 $revision = $this->irss->manage()->getCurrentRevision($rid);
768 $entered_values =
true;
784 $this->deleteUnusedFiles(
791 if ($entered_values) {
795 'log_user_entered_values',
797 ), $active_id, $this->
getId());
803 'log_user_not_entered_values',
805 ), $active_id, $this->
getId());
814 $rids_to_delete = [];
816 $res = $this->db->query(
817 "SELECT value1 FROM tst_solutions WHERE value2 = 'rid' AND " . $this->db->in(
819 $_POST[self::DELETE_FILES_TBL_POSTVAR],
824 while (
$d = $this->db->fetchAssoc(
$res)) {
825 $rids_to_delete[] =
$d[
'value1'];
828 return $rids_to_delete;
833 return parent::removeSolutionRecordById($solution_id);
844 if (!count($solution)) {
848 foreach ($solution as $row) {
849 if (!empty($row[
'value1'])) {
853 $solution = $cleaned;
862 parent::removeIntermediateSolution($active_id, $pass);
864 $test_id = $this->testParticipantInfo->lookupTestIdByActiveId($active_id);
867 $this->deleteUnusedFiles([],
$test_id, $active_id, $pass);
876 if (!is_array($userSolution)) {
888 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'no_checkbox'),
true);
893 $fileUploadAvailable = $this->current_cmd !==
'instantResponse' 896 $this->tpl->setOnScreenMessage(
'failure', $e->getMessage(),
true);
899 if ($fileUploadAvailable) {
907 $filename_arr = pathinfo($_FILES[
'upload'][
'name']);
908 $extension = $filename_arr[
'extension'];
909 $newfile =
'file_' . md5($_FILES[
'upload'][
'name']) .
'_' .
$version .
'.' . $extension;
911 $_FILES[
'upload'][
'tmp_name'],
912 $_FILES[
'upload'][
'name'],
916 $userSolution[$newfile] = [
917 'solution_id' => $newfile,
918 'value1' => $newfile,
919 'value2' => $_FILES[
'upload'][
'name'],
930 protected function handleSubmission(
int $active_id,
int $pass,
bool $obligations_answered,
bool $authorized): void
938 $maxpoints = $this->questioninfo->getMaximumPoints($this->
getId());
952 return 'assFileUpload';
957 return 'qpl_qst_fileupload';
978 return parent::getRTETextWithMediaObjects();
986 parent::setExportDetailsXLSX($worksheet, $startrow, $col, $active_id, $pass);
990 foreach ($solutions as $solution) {
991 $worksheet->
setCell($startrow + $i, $col, $this->
lng->txt(
'result'));
993 if (strlen($solution[
'value1'])) {
994 $worksheet->
setCell($startrow + $i, $col + 2, $solution[
'value1']);
995 $worksheet->
setCell($startrow + $i, $col + 3, $solution[
'value2']);
1000 return $startrow + $i + 1;
1015 public function fromXML($item,
int $questionpool_id, ?
int $tst_id, &$tst_object,
int &$question_counter, array $import_mapping, array &$solutionhints = []): array
1018 return $import->fromXML($item, $questionpool_id, $tst_id, $tst_object, $question_counter, $import_mapping);
1021 public function toXML($a_include_header =
true, $a_include_binary =
true, $a_shuffle =
false, $test_output =
false, $force_image_references =
false): string
1024 return $export->toXML($a_include_header, $a_include_binary, $a_shuffle, $test_output, $force_image_references);
1029 $user_solution = [];
1030 return $user_solution;
1040 $this->maxsize = $value;
1045 if ($this->allowedextensions ===
'') {
1049 return array_filter(array_map(
'trim', explode(
',', $this->allowedextensions)));
1059 $this->allowedextensions = strtolower(trim($a_value));
1065 SELECT tst_solutions.solution_id 1066 FROM tst_solutions, tst_active, qpl_questions 1067 WHERE tst_solutions.active_fi = tst_active.active_id 1068 AND tst_solutions.question_fi = qpl_questions.question_id 1069 AND tst_solutions.question_fi = %s AND tst_active.test_fi = %s 1070 AND tst_solutions.value1 is not null';
1071 $result = $this->db->queryF(
1073 [
'integer',
'integer'],
1074 [$this->
getId(), $test_id]
1076 if ($result->numRows() > 0) {
1092 $exporter->setTestTitle($test_title);
1093 $exporter->setQuestion($this);
1095 $exporter->buildAndDownload();
1105 $this->completion_by_submission = (bool) $bool;
1116 return parent::buildTestPresentationConfig()
1153 if (!$this->file_upload->hasBeenProcessed()) {
1154 $this->file_upload->process();
1156 return $this->file_upload->hasUploads();
static _replaceMediaObjectImageSrc(string $a_text, int $a_direction=0, string $nic='')
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
getPreviewFileUploadPathWeb($userId)
Returns the filesystem path for file uploads.
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
getSolutionValues($active_id, $pass=null, bool $authorized=true)
Loads solutions of a given user from the database an returns it.
setFormChangeDetectionEnabled($enableFormChangeDetection)
Set if the detection of form changes is enabled.
ILIAS FileUpload FileUpload $file_upload
setNrOfTries(int $a_nr_of_tries)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstance($identifier)
savePreviewData(ilAssQuestionPreviewSession $previewSession)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
saveWorkingData($active_id, $pass=null, $authorized=true)
public
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static _getParticipantId($active_id)
Get user id for active id.
getBestSolution($active_id, $pass)
$completion_by_submission
updateCurrentSolutionsAuthorization(int $activeId, int $pass, bool $authorized, bool $keepTime=false)
Abstract basic class which is to be extended by the concrete assessment question type classes...
fromXML($item, int $questionpool_id, ?int $tst_id, &$tst_object, int &$question_counter, array $import_mapping, array &$solutionhints=[])
Creates a question from a QTI file.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
getColumnCoord(int $a_col)
Get column "name" from number.
isDummySolutionRecord(array $solutionRecord)
static isObligationPossible(int $question_id)
__construct(string $title="", string $comment="", string $author="", int $owner=-1, string $question="")
assQuestion constructor
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
isComplete()
Returns true, if the question is complete for use.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle='')
getParticipantsSolution()
deletePreviewFileUploads($userId, $userSolution, $files)
Class IllegalStateException.
const REUSE_FILES_TBL_POSTVAR
getFileUploadPathWeb($test_id, $active_id, $question_id=null)
Returns the file upload path for web accessible files of a question.
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
setComment(string $comment="")
isFileReuseHandlingRequired()
Class for file upload questions.
float $points
The maximum available points for the question.
getAllowedExtensionsArray()
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Base Exception for all Exceptions relating to Modules/Test.
static removeTrailingPathSeparators(string $path)
setParticipantsSolution($participantSolution)
deleteDummySolutionRecord(int $activeId, int $passIndex)
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
setBold(string $a_coords)
Set cell(s) to bold.
string $allowedextensions
static _enabledAssessmentLogging()
const DELETE_FILES_TBL_POSTVAR
getUserSolutionPreferingIntermediate($active_id, $pass=null)
setCompletionBySubmission(bool $bool)
static logAction(string $logtext, int $active_id, int $question_id)
deliverFileUploadZIPFile(int $ref_id, int $test_id, string $test_title)
checkUpload()
Check file upload.
calculateReachedPointsForSolution($userSolution)
hasFileUploads(int $test_id)
intermediateSolutionExists(int $active_id, int $pass)
getPreviewFileUploads(ilAssQuestionPreviewSession $previewSession)
ILIAS FileDelivery Services $file_delivery
static moveUploadedFile(string $a_file, string $a_name, string $a_target, bool $a_raise_errors=true, string $a_mode="move_uploaded")
move uploaded file
removeIntermediateSolution(int $active_id, int $pass)
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
string $question
The question text.
isNonEmptyItemListPostSubmission(string $postSubmissionFieldname)
getUploadedFilesForWeb($active_id, $pass)
Returns the web accessible uploaded files for an active user in a given pass.
const DELETE_FILES_ACTION
int $test_id
The database id of a test in which the question is contained.
handleSubmission(int $active_id, int $pass, bool $obligations_answered, bool $authorized)
const HAS_SPECIFIC_FEEDBACK
buildTestPresentationConfig()
setExportDetailsXLSX(ilAssExcelFormatHelper $worksheet, int $startrow, int $col, int $active_id, int $pass)
{}
toXML($a_include_header=true, $a_include_binary=true, $a_shuffle=false, $test_output=false, $force_image_references=false)
saveQuestionDataToDb(int $original_id=-1)
getPreviewFileUploadPath($userId)
Returns the filesystem path for file uploads.
getSolutionMaxPass(int $active_id)
ILIAS ResourceStorage Services $irss
removeCurrentSolution(int $active_id, int $pass, bool $authorized=true)
getFileUploadPath($test_id, $active_id, $question_id=null)
Returns the filesystem path for file uploads.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
copyObject($target_questionpool_id, $title='')
Copies an assFileUpload object.
setOriginalId(?int $original_id)
getTestPresentationConfig()
setTitle(string $title="")
removeSolutionRecordById(int $solution_id)
setLifecycle(ilAssQuestionLifecycle $lifecycle)
loadFromDb($question_id)
Loads a assFileUpload object from a database.
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
getUploadedFiles($active_id, $pass=null, $authorized=true)
Returns the uploaded files for an active user in a given pass.
isFileDeletionSubmitAvailable()
forceExistingIntermediateSolution(int $activeId, int $passIndex, bool $considerDummyRecordCreation)
setAuthor(string $author="")
duplicate(bool $for_test=true, string $title='', string $author='', int $owner=-1, $testObjId=null)
Duplicates an assFileUpload.
getSolutionRecordById(int $solutionId)
static _setReachedPoints(int $active_id, int $question_id, float $points, float $maxpoints, int $pass, bool $manualscoring, bool $obligationsEnabled, ?int $test_id=null)
Sets the points, a learner has reached answering the question Additionally objective results are upda...
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
saveToDb($original_id='')
Saves a assFileUpload object to a database.
static getDraftInstance()
deleteAnswers($question_id)
setAllowedExtensions(string $a_value)
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
isCompletionBySubmissionEnabled()
setQuestion(string $question="")
isFileReuseSubmitAvailable()