Skip to content
Merged
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
46 changes: 35 additions & 11 deletions assets/vue/composables/fileUtils.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,52 @@
export function useFileUtils() {
const isFile = (fileData) => {
return fileData.resourceNode && fileData.resourceNode.firstResourceFile
return !!fileData?.resourceNode?.firstResourceFile
}

const safeMime = (fileData) => {
// normalize: strip params like "; charset=UTF-8"
const raw = fileData?.resourceNode?.firstResourceFile?.mimeType || ""
return String(raw).split(";")[0].trim()
}

const fileName = (fileData) => {
// prefer originalName; fallback to node title
return fileData?.resourceNode?.firstResourceFile?.originalName || fileData?.resourceNode?.title || ""
}

const ext = (fileData) => {
const name = fileName(fileData)
const m = /\.([A-Za-z0-9]+)$/.exec(name)
return m ? m[1].toLowerCase() : ""
}

const isImage = (fileData) => {
return isFile(fileData) && fileData.resourceNode.firstResourceFile.image
return isFile(fileData) && !!fileData.resourceNode.firstResourceFile.image
}

const isVideo = (fileData) => {
return isFile(fileData) && fileData.resourceNode.firstResourceFile.video
return isFile(fileData) && !!fileData.resourceNode.firstResourceFile.video
}

const isAudio = (fileData) => {
const mimeType = fileData.resourceNode.firstResourceFile.mimeType
return isFile(fileData) && mimeType.split("/")[0].toLowerCase() === "audio"
if (!isFile(fileData)) return false
const top = safeMime(fileData).split("/")[0]?.toLowerCase() || ""
return top === "audio" || !!fileData.resourceNode.firstResourceFile.audio
}

const isHtml = (fileData) => {
if (!isFile(fileData)) {
return false
}
const mimeType = fileData.resourceNode.firstResourceFile.mimeType || ""
const [type, sub] = mimeType.split("/")
return (type?.toLowerCase() === "text" && sub?.toLowerCase() === "html") || sub?.toLowerCase() === "html"
if (!isFile(fileData)) return false

const mime = safeMime(fileData).toLowerCase()
const e = ext(fileData)

// MIME-based detection
const byMime = mime.includes("text/html") || mime.includes("application/html") || mime.includes("application/xhtml")

// Extension-based fallback when MIME is missing/wrong
const byExt = e === "html" || e === "htm" || e === "xhtml"

return byMime || byExt
}

const isPreviewable = (fileData) => {
Expand Down
12 changes: 10 additions & 2 deletions src/CoreBundle/Controller/ResourceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -589,13 +589,21 @@ private function processFile(Request $request, ResourceNode $resourceNode, strin

$fileName = $resourceFile->getOriginalName();
$fileSize = $resourceFile->getSize();
$mimeType = $resourceFile->getMimeType();
$mimeType = $resourceFile->getMimeType() ?: '';
[$start, $end, $length] = $this->getRange($request, $fileSize);
$resourceNodeRepo = $this->getResourceNodeRepository();

// Convert the file name to ASCII using iconv
$fileName = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $fileName);

// MIME normalization for HTML
$looksLikeHtmlByExt = (bool) preg_match('/\.x?html?$/i', (string) $fileName);
if ($mimeType === '' || stripos($mimeType, 'html') === false) {
if ($looksLikeHtmlByExt) {
$mimeType = 'text/html; charset=UTF-8';
}
}

switch ($mode) {
case 'download':
$forceDownload = true;
Expand Down Expand Up @@ -652,7 +660,7 @@ private function processFile(Request $request, ResourceNode $resourceNode, strin
$fileName
);
$response->headers->set('Content-Disposition', $disposition);
$response->headers->set('Content-Type', 'text/html');
$response->headers->set('Content-Type', 'text/html; charset=UTF-8');

// @todo move into a function/class
if ('true' === $this->getSettingsManager()->getSetting('editor.translate_html')) {
Expand Down
44 changes: 22 additions & 22 deletions src/CourseBundle/Component/CourseCopy/CourseBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ public function build(
*
* @param array<int> $ids
*/
private function build_learnpath_category(
public function build_learnpath_category(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -505,7 +505,7 @@ private function build_learnpath_category(
*
* @param array<int> $idList
*/
private function build_learnpaths(
public function build_learnpaths(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -616,7 +616,7 @@ private function build_learnpaths(
/**
* Export Gradebook (categories + evaluations + links).
*/
private function build_gradebook(
public function build_gradebook(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity
Expand Down Expand Up @@ -729,7 +729,7 @@ private function serializeGradebookCategory(GradebookCategory $c): array
*
* @param array<int> $ids
*/
private function build_works(
public function build_works(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -801,7 +801,7 @@ private function build_works(
*
* @param array<int> $ids
*/
private function build_attendance(
public function build_attendance(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -867,7 +867,7 @@ private function build_attendance(
*
* @param array<int> $ids
*/
private function build_thematic(
public function build_thematic(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -959,7 +959,7 @@ private function build_thematic(
*
* @param array<int> $ids
*/
private function build_wiki(
public function build_wiki(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -1017,7 +1017,7 @@ private function build_wiki(
*
* @param array<int> $ids
*/
private function build_glossary(
public function build_glossary(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -1062,7 +1062,7 @@ private function build_glossary(
*
* @param array<int> $ids
*/
private function build_course_descriptions(
public function build_course_descriptions(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -1108,7 +1108,7 @@ private function build_course_descriptions(
*
* @param array<int> $ids
*/
private function build_events(
public function build_events(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -1213,7 +1213,7 @@ private function build_events(
*
* @param array<int> $ids
*/
private function build_announcements(
public function build_announcements(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -1351,7 +1351,7 @@ private function tryAddAsset(string $relPath, string $absPath, int $size = 0): v
*
* @return array<int>
*/
private function build_surveys(
public function build_surveys(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -1444,7 +1444,7 @@ private function build_surveys(
*
* @param array<int> $questionIds
*/
private function build_survey_questions(
public function build_survey_questions(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -1528,7 +1528,7 @@ private function build_survey_questions(
*
* @return array<int>
*/
private function build_quizzes(
public function build_quizzes(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -1641,7 +1641,7 @@ private function safeCount(mixed $v): int
*
* @param array<int> $questionIds
*/
private function build_quiz_questions(
public function build_quiz_questions(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -1764,7 +1764,7 @@ private function exportQuestionsWithAnswers(object $legacyCourse, array $questio
/**
* Export Link category as legacy item.
*/
private function build_link_category(CLinkCategory $category): void
public function build_link_category(CLinkCategory $category): void
{
$id = (int) $category->getIid();
if ($id <= 0) {
Expand All @@ -1786,7 +1786,7 @@ private function build_link_category(CLinkCategory $category): void
*
* @param array<int> $ids
*/
private function build_links(
public function build_links(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -1949,7 +1949,7 @@ private function makeIdFilter(array $idsFilter): Closure
* Export Tool intro only for the course_homepage tool.
* Prefers the session-specific intro when both (session and base) exist.
*/
private function build_tool_intro(
public function build_tool_intro(
object $legacyCourse,
?CourseEntity $courseEntity,
?SessionEntity $sessionEntity
Expand Down Expand Up @@ -2020,7 +2020,7 @@ private function build_tool_intro(
*
* @param array<int> $ids
*/
private function build_forum_category(
public function build_forum_category(
object $legacyCourse,
CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -2056,7 +2056,7 @@ private function build_forum_category(
*
* @param array<int> $ids
*/
private function build_forums(
public function build_forums(
object $legacyCourse,
CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -2104,7 +2104,7 @@ private function build_forums(
*
* @param array<int> $ids
*/
private function build_forum_topics(
public function build_forum_topics(
object $legacyCourse,
CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down Expand Up @@ -2147,7 +2147,7 @@ private function build_forum_topics(
*
* @param array<int> $ids
*/
private function build_forum_posts(
public function build_forum_posts(
object $legacyCourse,
CourseEntity $courseEntity,
?SessionEntity $sessionEntity,
Expand Down
Loading