Skip to content

Commit fcc2acf

Browse files
authored
Merge pull request #7124 from christianbeeznest/GH-7121
Exercise: Make attempt_file and attempt_feedback entities into resour…
2 parents 4e608a6 + 642acc3 commit fcc2acf

File tree

13 files changed

+1485
-217
lines changed

13 files changed

+1485
-217
lines changed

public/main/exercise/UploadAnswer.php

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
/* For licensing terms, see /license.txt */
33

44
use Chamilo\CoreBundle\Entity\AttemptFile;
5+
use Chamilo\CoreBundle\Entity\ResourceNode;
56
use Chamilo\CoreBundle\Entity\TrackEAttempt;
67
use Chamilo\CoreBundle\Framework\Container;
7-
use Symfony\Component\Uid\Uuid;
88

99
/**
1010
* Question with file upload, where the file is the answer.
@@ -63,9 +63,9 @@ public function return_header(Exercise $exercise, $counter = null, $score = [])
6363
}
6464

6565
/**
66-
* Attach uploaded Asset(s) to the question attempt as AttemptFile.
66+
* Attach uploaded ResourceNode(s) to the question attempt as AttemptFile.
6767
*/
68-
public static function saveAssetInQuestionAttempt(int $attemptId, array $postedAssetIds = []): void
68+
public static function saveAssetInQuestionAttempt(int $attemptId, array $postedNodeIds = []): void
6969
{
7070
$em = Container::getEntityManager();
7171

@@ -78,30 +78,36 @@ public static function saveAssetInQuestionAttempt(int $attemptId, array $postedA
7878
$questionId = (int) $attempt->getQuestionId();
7979
$sessionKey = 'upload_answer_assets_'.$questionId;
8080

81-
$assetIds = array_values(array_filter(array_map('strval', $postedAssetIds)));
82-
if (empty($assetIds)) {
81+
$nodeIds = array_values(array_filter(array_map('intval', $postedNodeIds)));
82+
83+
if (empty($nodeIds)) {
8384
$sessionVal = ChamiloSession::read($sessionKey);
84-
$assetIds = is_array($sessionVal) ? $sessionVal : (empty($sessionVal) ? [] : [$sessionVal]);
85+
$nodeIds = is_array($sessionVal) ? $sessionVal : (empty($sessionVal) ? [] : [(int) $sessionVal]);
8586
}
86-
if (empty($assetIds)) {
87+
88+
if (empty($nodeIds)) {
8789
return;
8890
}
8991

9092
ChamiloSession::erase($sessionKey);
91-
$repo = Container::getAssetRepository();
9293

93-
foreach ($assetIds as $id) {
94-
try {
95-
$asset = $repo->find(Uuid::fromRfc4122($id));
96-
} catch (\Throwable $e) {
94+
$resourceNodeRepo = Container::getResourceNodeRepository();
95+
96+
foreach ($nodeIds as $id) {
97+
if (!$id) {
9798
continue;
9899
}
99-
if (!$asset) {
100+
101+
/** @var ResourceNode|null $node */
102+
$node = $resourceNodeRepo->find($id);
103+
if (null === $node) {
100104
continue;
101105
}
102106

103-
$attemptFile = (new AttemptFile())->setAsset($asset);
107+
$attemptFile = new AttemptFile();
108+
$attemptFile->setResourceNode($node);
104109
$attempt->addAttemptFile($attemptFile);
110+
105111
$em->persist($attemptFile);
106112
}
107113

public/main/exercise/exercise_show.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,8 @@ function getFCK(vals, marksid) {
657657
if (!empty($comnt)) {
658658
echo ExerciseLib::getFeedbackText($comnt);
659659
}
660-
echo ExerciseLib::getOralFeedbackAudio($id, $questionId);
660+
echo ExerciseLib::getOralFeedbackAudio($id, $questionId, false);
661+
661662
echo '</div>';
662663

663664
echo '<div id="'.$name.'" class="row hidden">';
@@ -707,7 +708,7 @@ function getFCK(vals, marksid) {
707708
if (!empty($comnt)) {
708709
echo '<b>'.get_lang('Feedback').'</b>';
709710
echo ExerciseLib::getFeedbackText($comnt);
710-
echo ExerciseLib::getOralFeedbackAudio($id, $questionId);
711+
echo ExerciseLib::getOralFeedbackAudio($id, $questionId, false);
711712
}
712713
}
713714

public/main/exercise/oral_expression.class.php

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
use Chamilo\CoreBundle\Entity\Asset;
66
use Chamilo\CoreBundle\Entity\AttemptFile;
7+
use Chamilo\CoreBundle\Entity\ResourceNode;
78
use Chamilo\CoreBundle\Entity\TrackEAttempt;
89
use Chamilo\CoreBundle\Framework\Container;
10+
use Chamilo\CoreBundle\Repository\ResourceNodeRepository;
911
use Symfony\Component\Uid\Uuid;
1012

1113
/**
@@ -17,6 +19,9 @@
1719
*/
1820
class OralExpression extends Question
1921
{
22+
public const RECORDING_TYPE_ATTEMPT = 1;
23+
public const RECORDING_TYPE_FEEDBACK = 2;
24+
2025
public $typePicture = 'audio_question.png';
2126
public $explanationLangVar = 'Oral expression';
2227
public $available_extensions = ['wav', 'ogg'];
@@ -80,7 +85,8 @@ public function returnRecorder(int $trackExerciseId): string
8085
false
8186
);
8287

83-
$recordAudioView->assign('type', Asset::EXERCISE_ATTEMPT);
88+
// Student recording
89+
$recordAudioView->assign('type', self::RECORDING_TYPE_ATTEMPT);
8490
$recordAudioView->assign('t_exercise_id', $trackExerciseId);
8591
$recordAudioView->assign('question_id', $this->id);
8692

@@ -89,30 +95,37 @@ public function returnRecorder(int $trackExerciseId): string
8995
return $recordAudioView->fetch($template);
9096
}
9197

92-
public static function saveAssetInQuestionAttempt($attemptId)
98+
public static function saveAssetInQuestionAttempt($attemptId): void
9399
{
94100
$em = Container::getEntityManager();
95101

102+
/** @var TrackEAttempt|null $attempt */
96103
$attempt = $em->find(TrackEAttempt::class, $attemptId);
97104

98-
$variable = 'oral_expression_asset_'.$attempt->getQuestionId();
99-
100-
$asset = null;
101-
$assetId = ChamiloSession::read($variable);
102-
if (!empty($assetId)) {
103-
$asset = Container::getAssetRepository()->find(Uuid::fromRfc4122($assetId));
105+
if (null === $attempt) {
106+
return;
104107
}
105108

106-
if (null === $asset) {
109+
$variable = 'oral_expression_asset_'.$attempt->getQuestionId();
110+
$resourceNodeId = ChamiloSession::read($variable);
111+
ChamiloSession::erase($variable);
112+
113+
if (empty($resourceNodeId)) {
107114
return;
108115
}
109116

110-
ChamiloSession::erase($variable);
117+
/** @var ResourceNodeRepository $resourceNodeRepo */
118+
$resourceNodeRepo = Container::getResourceNodeRepository();
119+
120+
/** @var ResourceNode|null $node */
121+
$node = $resourceNodeRepo->find($resourceNodeId);
111122

112-
$attemptFile = (new AttemptFile())
113-
->setAsset($asset)
114-
;
123+
if (null === $node) {
124+
return;
125+
}
115126

127+
$attemptFile = new AttemptFile();
128+
$attemptFile->setResourceNode($node);
116129
$attempt->addAttemptFile($attemptFile);
117130

118131
$em->persist($attemptFile);

public/main/inc/ajax/exercise.ajax.php

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
/* For licensing terms, see /license.txt */
44

5-
use Chamilo\CoreBundle\Entity\Asset;
5+
use Chamilo\CoreBundle\Entity\ResourceFile;
6+
use Chamilo\CoreBundle\Entity\ResourceNode;
7+
use Chamilo\CoreBundle\Entity\ResourceType;
68
use Chamilo\CoreBundle\Entity\TrackEExerciseConfirmation;
79
use Chamilo\CoreBundle\Entity\TrackEExercise;
810
use Chamilo\CoreBundle\Event\Events;
911
use Chamilo\CoreBundle\Framework\Container;
1012
use Chamilo\CoreBundle\Event\ExerciseQuestionAnsweredEvent;
1113
use ChamiloSession as Session;
14+
use Doctrine\Persistence\ObjectRepository;
15+
use Symfony\Component\HttpFoundation\File\UploadedFile;
1216

1317
require_once __DIR__.'/../global.inc.php';
1418
$current_course_tool = TOOL_QUIZ;
@@ -1073,6 +1077,7 @@ function (array $exercise) {
10731077
exit;
10741078
}
10751079

1080+
// Chunk upload "send" phase
10761081
if (isset($_REQUEST['chunkAction']) && 'send' === $_REQUEST['chunkAction']) {
10771082
if (!empty($_FILES)) {
10781083
$tempDirectory = api_get_path(SYS_ARCHIVE_PATH);
@@ -1085,7 +1090,11 @@ function (array $exercise) {
10851090
}
10861091
foreach ($fileList as $file) {
10871092
$tmpFile = disable_dangerous_file(api_replace_dangerous_char($file['name']));
1088-
file_put_contents($tempDirectory.$tmpFile, fopen($file['tmp_name'], 'r'), FILE_APPEND);
1093+
file_put_contents(
1094+
$tempDirectory.$tmpFile,
1095+
fopen($file['tmp_name'], 'r'),
1096+
FILE_APPEND
1097+
);
10891098
}
10901099
}
10911100
echo json_encode(['files' => $_FILES, 'errorStatus' => 0]);
@@ -1102,36 +1111,74 @@ function (array $exercise) {
11021111
}
11031112

11041113
$resultList = [];
1105-
$assetRepo = Container::getAssetRepository();
1114+
11061115
$em = Container::getEntityManager();
1116+
1117+
/** @var ObjectRepository<ResourceType> $resourceTypeRepo */
1118+
$resourceTypeRepo = $em->getRepository(ResourceType::class);
1119+
1120+
/** @var ResourceType|null $resourceType */
1121+
$resourceType = $resourceTypeRepo->findOneBy(['title' => 'attempt_file']);
1122+
if (null === $resourceType) {
1123+
echo json_encode(['files' => [], 'error' => 'Missing ResourceType \"attempt_file\"']);
1124+
exit;
1125+
}
1126+
1127+
$resourceNodeRepo = Container::getResourceNodeRepository();
11071128
$basePath = rtrim(api_get_path(WEB_PATH), '/');
11081129

11091130
foreach ($fileList as $file) {
1110-
$originalName = api_replace_dangerous_char(disable_dangerous_file($file['name'] ?? 'file.bin'));
1131+
$originalName = api_replace_dangerous_char(
1132+
disable_dangerous_file($file['name'] ?? 'file.bin')
1133+
);
11111134
$tmpPath = $file['tmp_name'];
1135+
11121136
if (isset($_REQUEST['chunkAction']) && 'done' === $_REQUEST['chunkAction']) {
11131137
$tmpPath = api_get_path(SYS_ARCHIVE_PATH).($file['name'] ?? $originalName);
11141138
}
11151139

1116-
$asset = (new Asset())
1117-
->setCategory(Asset::EXERCISE_ATTEMPT)
1118-
->setTitle($originalName);
1140+
$uploadedFile = new UploadedFile(
1141+
$tmpPath,
1142+
$originalName,
1143+
$file['type'] ?? 'application/octet-stream',
1144+
$file['error'] ?? UPLOAD_ERR_OK,
1145+
true
1146+
);
1147+
1148+
$node = new ResourceNode();
1149+
$node->setTitle($originalName);
1150+
$node->setResourceType($resourceType);
1151+
$em->persist($node);
1152+
1153+
$resourceFile = new ResourceFile();
1154+
$resourceFile->setResourceNode($node);
1155+
$resourceFile->setFile($uploadedFile);
1156+
$em->persist($resourceFile);
11191157

1120-
$assetRepo->createFromRequest($asset, ['tmp_name' => $tmpPath]);
1158+
$em->flush();
11211159

11221160
if (isset($_REQUEST['chunkAction']) && 'done' === $_REQUEST['chunkAction']) {
11231161
@unlink($tmpPath);
11241162
}
11251163

1126-
$key = 'upload_answer_assets_'.$questionId;
1164+
$key = 'upload_answer_assets_'.$questionId;
11271165
$current = (array) ChamiloSession::read($key);
1128-
$current[] = (string) $asset->getId();
1166+
$current[] = (int) $node->getId();
11291167
ChamiloSession::write($key, array_values(array_unique($current)));
11301168

1169+
$relativeUrl = '';
1170+
try {
1171+
$relativeUrl = $resourceNodeRepo->getResourceFileUrl($node);
1172+
} catch (\Throwable $e) {
1173+
$relativeUrl = '';
1174+
}
1175+
1176+
$url = $relativeUrl ? $basePath.$relativeUrl : '';
1177+
11311178
$resultList[] = [
11321179
'name' => api_htmlentities($originalName),
1133-
'asset_id' => (string) $asset->getId(),
1134-
'url' => $basePath.$assetRepo->getAssetUrl($asset),
1180+
'asset_id' => (string) $node->getId(),
1181+
'url' => $url,
11351182
'size' => isset($file['size']) ? format_file_size((int) $file['size']) : '',
11361183
'type' => api_htmlentities($file['type'] ?? ''),
11371184
'result' => Display::return_icon('accept.png', get_lang('Uploaded')),

0 commit comments

Comments
 (0)