Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions public/main/exercise/UploadAnswer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
/* For licensing terms, see /license.txt */

use Chamilo\CoreBundle\Entity\AttemptFile;
use Chamilo\CoreBundle\Entity\ResourceNode;
use Chamilo\CoreBundle\Entity\TrackEAttempt;
use Chamilo\CoreBundle\Framework\Container;
use Symfony\Component\Uid\Uuid;

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

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

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

$assetIds = array_values(array_filter(array_map('strval', $postedAssetIds)));
if (empty($assetIds)) {
$nodeIds = array_values(array_filter(array_map('intval', $postedNodeIds)));

if (empty($nodeIds)) {
$sessionVal = ChamiloSession::read($sessionKey);
$assetIds = is_array($sessionVal) ? $sessionVal : (empty($sessionVal) ? [] : [$sessionVal]);
$nodeIds = is_array($sessionVal) ? $sessionVal : (empty($sessionVal) ? [] : [(int) $sessionVal]);
}
if (empty($assetIds)) {

if (empty($nodeIds)) {
return;
}

ChamiloSession::erase($sessionKey);
$repo = Container::getAssetRepository();

foreach ($assetIds as $id) {
try {
$asset = $repo->find(Uuid::fromRfc4122($id));
} catch (\Throwable $e) {
$resourceNodeRepo = Container::getResourceNodeRepository();

foreach ($nodeIds as $id) {
if (!$id) {
continue;
}
if (!$asset) {

/** @var ResourceNode|null $node */
$node = $resourceNodeRepo->find($id);
if (null === $node) {
continue;
}

$attemptFile = (new AttemptFile())->setAsset($asset);
$attemptFile = new AttemptFile();
$attemptFile->setResourceNode($node);
$attempt->addAttemptFile($attemptFile);

$em->persist($attemptFile);
}

Expand Down
5 changes: 3 additions & 2 deletions public/main/exercise/exercise_show.php
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,8 @@ function getFCK(vals, marksid) {
if (!empty($comnt)) {
echo ExerciseLib::getFeedbackText($comnt);
}
echo ExerciseLib::getOralFeedbackAudio($id, $questionId);
echo ExerciseLib::getOralFeedbackAudio($id, $questionId, false);

echo '</div>';

echo '<div id="'.$name.'" class="row hidden">';
Expand Down Expand Up @@ -707,7 +708,7 @@ function getFCK(vals, marksid) {
if (!empty($comnt)) {
echo '<b>'.get_lang('Feedback').'</b>';
echo ExerciseLib::getFeedbackText($comnt);
echo ExerciseLib::getOralFeedbackAudio($id, $questionId);
echo ExerciseLib::getOralFeedbackAudio($id, $questionId, false);
}
}

Expand Down
39 changes: 26 additions & 13 deletions public/main/exercise/oral_expression.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use Chamilo\CoreBundle\Entity\Asset;
use Chamilo\CoreBundle\Entity\AttemptFile;
use Chamilo\CoreBundle\Entity\ResourceNode;
use Chamilo\CoreBundle\Entity\TrackEAttempt;
use Chamilo\CoreBundle\Framework\Container;
use Chamilo\CoreBundle\Repository\ResourceNodeRepository;
use Symfony\Component\Uid\Uuid;

/**
Expand All @@ -17,6 +19,9 @@
*/
class OralExpression extends Question
{
public const RECORDING_TYPE_ATTEMPT = 1;
public const RECORDING_TYPE_FEEDBACK = 2;

public $typePicture = 'audio_question.png';
public $explanationLangVar = 'Oral expression';
public $available_extensions = ['wav', 'ogg'];
Expand Down Expand Up @@ -80,7 +85,8 @@ public function returnRecorder(int $trackExerciseId): string
false
);

$recordAudioView->assign('type', Asset::EXERCISE_ATTEMPT);
// Student recording
$recordAudioView->assign('type', self::RECORDING_TYPE_ATTEMPT);
$recordAudioView->assign('t_exercise_id', $trackExerciseId);
$recordAudioView->assign('question_id', $this->id);

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

public static function saveAssetInQuestionAttempt($attemptId)
public static function saveAssetInQuestionAttempt($attemptId): void
{
$em = Container::getEntityManager();

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

$variable = 'oral_expression_asset_'.$attempt->getQuestionId();

$asset = null;
$assetId = ChamiloSession::read($variable);
if (!empty($assetId)) {
$asset = Container::getAssetRepository()->find(Uuid::fromRfc4122($assetId));
if (null === $attempt) {
return;
}

if (null === $asset) {
$variable = 'oral_expression_asset_'.$attempt->getQuestionId();
$resourceNodeId = ChamiloSession::read($variable);
ChamiloSession::erase($variable);

if (empty($resourceNodeId)) {
return;
}

ChamiloSession::erase($variable);
/** @var ResourceNodeRepository $resourceNodeRepo */
$resourceNodeRepo = Container::getResourceNodeRepository();

/** @var ResourceNode|null $node */
$node = $resourceNodeRepo->find($resourceNodeId);

$attemptFile = (new AttemptFile())
->setAsset($asset)
;
if (null === $node) {
return;
}

$attemptFile = new AttemptFile();
$attemptFile->setResourceNode($node);
$attempt->addAttemptFile($attemptFile);

$em->persist($attemptFile);
Expand Down
71 changes: 59 additions & 12 deletions public/main/inc/ajax/exercise.ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

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

use Chamilo\CoreBundle\Entity\Asset;
use Chamilo\CoreBundle\Entity\ResourceFile;
use Chamilo\CoreBundle\Entity\ResourceNode;
use Chamilo\CoreBundle\Entity\ResourceType;
use Chamilo\CoreBundle\Entity\TrackEExerciseConfirmation;
use Chamilo\CoreBundle\Entity\TrackEExercise;
use Chamilo\CoreBundle\Event\Events;
use Chamilo\CoreBundle\Framework\Container;
use Chamilo\CoreBundle\Event\ExerciseQuestionAnsweredEvent;
use ChamiloSession as Session;
use Doctrine\Persistence\ObjectRepository;
use Symfony\Component\HttpFoundation\File\UploadedFile;

require_once __DIR__.'/../global.inc.php';
$current_course_tool = TOOL_QUIZ;
Expand Down Expand Up @@ -1073,6 +1077,7 @@ function (array $exercise) {
exit;
}

// Chunk upload "send" phase
if (isset($_REQUEST['chunkAction']) && 'send' === $_REQUEST['chunkAction']) {
if (!empty($_FILES)) {
$tempDirectory = api_get_path(SYS_ARCHIVE_PATH);
Expand All @@ -1085,7 +1090,11 @@ function (array $exercise) {
}
foreach ($fileList as $file) {
$tmpFile = disable_dangerous_file(api_replace_dangerous_char($file['name']));
file_put_contents($tempDirectory.$tmpFile, fopen($file['tmp_name'], 'r'), FILE_APPEND);
file_put_contents(
$tempDirectory.$tmpFile,
fopen($file['tmp_name'], 'r'),
FILE_APPEND
);
}
}
echo json_encode(['files' => $_FILES, 'errorStatus' => 0]);
Expand All @@ -1102,36 +1111,74 @@ function (array $exercise) {
}

$resultList = [];
$assetRepo = Container::getAssetRepository();

$em = Container::getEntityManager();

/** @var ObjectRepository<ResourceType> $resourceTypeRepo */
$resourceTypeRepo = $em->getRepository(ResourceType::class);

/** @var ResourceType|null $resourceType */
$resourceType = $resourceTypeRepo->findOneBy(['title' => 'attempt_file']);
if (null === $resourceType) {
echo json_encode(['files' => [], 'error' => 'Missing ResourceType \"attempt_file\"']);
exit;
}

$resourceNodeRepo = Container::getResourceNodeRepository();
$basePath = rtrim(api_get_path(WEB_PATH), '/');

foreach ($fileList as $file) {
$originalName = api_replace_dangerous_char(disable_dangerous_file($file['name'] ?? 'file.bin'));
$originalName = api_replace_dangerous_char(
disable_dangerous_file($file['name'] ?? 'file.bin')
);
$tmpPath = $file['tmp_name'];

if (isset($_REQUEST['chunkAction']) && 'done' === $_REQUEST['chunkAction']) {
$tmpPath = api_get_path(SYS_ARCHIVE_PATH).($file['name'] ?? $originalName);
}

$asset = (new Asset())
->setCategory(Asset::EXERCISE_ATTEMPT)
->setTitle($originalName);
$uploadedFile = new UploadedFile(
$tmpPath,
$originalName,
$file['type'] ?? 'application/octet-stream',
$file['error'] ?? UPLOAD_ERR_OK,
true
);

$node = new ResourceNode();
$node->setTitle($originalName);
$node->setResourceType($resourceType);
$em->persist($node);

$resourceFile = new ResourceFile();
$resourceFile->setResourceNode($node);
$resourceFile->setFile($uploadedFile);
$em->persist($resourceFile);

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

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

$key = 'upload_answer_assets_'.$questionId;
$key = 'upload_answer_assets_'.$questionId;
$current = (array) ChamiloSession::read($key);
$current[] = (string) $asset->getId();
$current[] = (int) $node->getId();
ChamiloSession::write($key, array_values(array_unique($current)));

$relativeUrl = '';
try {
$relativeUrl = $resourceNodeRepo->getResourceFileUrl($node);
} catch (\Throwable $e) {
$relativeUrl = '';
}

$url = $relativeUrl ? $basePath.$relativeUrl : '';

$resultList[] = [
'name' => api_htmlentities($originalName),
'asset_id' => (string) $asset->getId(),
'url' => $basePath.$assetRepo->getAssetUrl($asset),
'asset_id' => (string) $node->getId(),
'url' => $url,
'size' => isset($file['size']) ? format_file_size((int) $file['size']) : '',
'type' => api_htmlentities($file['type'] ?? ''),
'result' => Display::return_icon('accept.png', get_lang('Uploaded')),
Expand Down
Loading
Loading