From 7f4657def4678ae0aec92a62af478a7903823eb4 Mon Sep 17 00:00:00 2001 From: Ahmad Altaher Alfayad Date: Fri, 10 May 2024 12:59:34 -0400 Subject: [PATCH 1/4] add replacement functionality for pages and modules --- src/Lms/Canvas/CanvasApi.php | 99 +++++++++++++++++++++++++++++++++++- src/Lms/Canvas/CanvasLms.php | 45 +++++++++++++++- 2 files changed, 142 insertions(+), 2 deletions(-) diff --git a/src/Lms/Canvas/CanvasApi.php b/src/Lms/Canvas/CanvasApi.php index 7415b049..cb2487b9 100644 --- a/src/Lms/Canvas/CanvasApi.php +++ b/src/Lms/Canvas/CanvasApi.php @@ -106,7 +106,7 @@ public function apiPost($url, $options, $sendAuthorized = true) } // Posts a file to Canvas - public function apiFilePost(string $url, array $options, string $filepath, string $newFileName): LmsResponse + public function apiFilePost(string $url, array $options, string $filepath, string $newFileName, $moduleInstances = null, $courseId = null, $replacePages = null) : LmsResponse { $fileResponse = $this->apiGet($url); $file = $fileResponse->getContent(); @@ -135,6 +135,59 @@ public function apiFilePost(string $url, array $options, string $filepath, strin 'body' => $formData->bodyToIterable(), ], false); + $fileResponseContent = $fileResponse->getContent(); + + if($moduleInstances) { + foreach ($moduleInstances as $moduleInstance) { + $response = $this->apiPost("courses/{$courseId}/modules/{$moduleInstance}/items", [ + 'json' => [ + 'module_item' => [ + 'title' => $newFileName, + 'type' => 'File', + 'content_id' => $fileResponseContent['id'], + ], + ], + ]); + + } + } + + if($replacePages) { + foreach ($replacePages as $page) { + $dom = new \DOMDocument(); + $dom->loadHTML($page['body']); + $anchors = $dom->getElementsByTagName('a'); + foreach ($anchors as $anchor) { + preg_match('/files\/(\d+)/', $anchor->getAttribute('href'), $matches); + if (isset($matches[1]) && $matches[1] == $file['id']) { + $anchor->setAttribute('href', $fileResponseContent['url']); + $anchor->setAttribute('title', $newFileName); + $anchor->nodeValue = $newFileName; + } + $page['body'] = $dom->saveHTML(); + $response = $this->apiPut("courses/{$courseId}/pages/{$page['page_id']}", [ + 'json' => [ + 'wiki_page' => [ + 'title' => $page['title'], + 'body' => $page['body'], + 'editing_roles' => $page['editing_roles'], + 'published' => $page['published'], + 'front_page' => $page['front_page'], + 'hide_from_students' => $page['hide_from_students'], + 'notify_of_update' => $page['notify_of_update'], + 'attachments' => [ + [ + 'url' => $fileResponseContent['url'], + 'filename' => $newFileName, + ], + ], + ], + ], + ]); + } + } + } + return $fileResponse; } @@ -189,4 +242,48 @@ public function apiDelete($url) { } + public function listModules($courseId) + { + $url = "courses/{$courseId}/modules"; + $response = $this->apiGet($url); + return $response->getContent(); + } + + public function listModuleItems($courseId, $moduleId) + { + $url = "courses/{$courseId}/modules/{$moduleId}/items"; + $response = $this->apiGet($url); + return $response->getContent(); + } + + public function deleteModuleItem($courseId, $moduleId, $itemId) + { + $url = "courses/{$courseId}/modules/{$moduleId}/items/{$itemId}"; + $response = $this->apiDelete($url); + return $response->getContent(); + } + + public function listPages($courseId) + { + $url = "courses/{$courseId}/pages"; + $response = $this->apiGet($url . '?include[]=body'); + + $responseWithPageBody = []; + + foreach ($response->getContent() as $content) { + $page = $this->showPage($courseId, $content['page_id']); + $content['body'] = $page['body']; + $responseWithPageBody[] = $content; + } + + return $responseWithPageBody; + } + + public function showPage($courseId, $pageId) + { + $url = "courses/{$courseId}/pages/{$pageId}"; + $response = $this->apiGet($url . '?include[]=body'); + return $response->getContent(); + } + } diff --git a/src/Lms/Canvas/CanvasLms.php b/src/Lms/Canvas/CanvasLms.php index 341d41df..18332643 100644 --- a/src/Lms/Canvas/CanvasLms.php +++ b/src/Lms/Canvas/CanvasLms.php @@ -376,13 +376,44 @@ public function postFileItem(FileItem $file, string $newFileName) $apiDomain = $this->getApiDomain($user); $apiToken = $this->getApiToken($user); $canvasApi = new CanvasApi($apiDomain, $apiToken); + $modules = $canvasApi->listModules($file->getCourse()->getLmsCourseId()); + $pages = $canvasApi->listPages($file->getCourse()->getLmsCourseId()); + $refillModules = []; + $changePages = []; + + // Delete any existing module items with the same file name + foreach ($modules as $module) { + $moduleItems = $canvasApi->listModuleItems($file->getCourse()->getLmsCourseId(), $module['id']); + $instances = $this->findFileInModuleItems($moduleItems, $file->getLmsFileId()); + if (!empty($instances)) { + foreach ($instances as $instance) { + $canvasApi->deleteModuleItem($file->getCourse()->getLmsCourseId(), $module['id'], $instance['id']); + } + $refillModules[] = $module['id']; + } + } + + // Find all pages that contain this file in their HTML + foreach ($pages as $page) { + $dom = new \DOMDocument(); + $dom->loadHTML($page['body']); + $anchors = $dom->getElementsByTagName('a'); + foreach ($anchors as $anchor) { + preg_match('/files\/(\d+)/', $anchor->getAttribute('href'), $matches); + if(isset($matches[1]) && $matches[1] == $file->getLmsFileId()) { + $changePages[] = $page; + break; + } + } + } + $url = "courses/{$file->getCourse()->getLmsCourseId()}/files/{$file->getLmsFileId()}"; $filepath = $this->util->getTempPath() . '/file.' . $file->getId(); $options = [ 'postUrl' => "courses/{$file->getCourse()->getLmsCourseId()}/files" ]; - $fileResponse = $canvasApi->apiFilePost($url, $options, $filepath, $newFileName); + $fileResponse = $canvasApi->apiFilePost($url, $options, $filepath, $newFileName, $refillModules, $file->getCourse()->getLmsCourseId(), $changePages); $fileObj = $fileResponse->getContent(); if (isset($fileObj['id'])) { @@ -393,6 +424,18 @@ public function postFileItem(FileItem $file, string $newFileName) return $fileResponse; } + public function findFileInModuleItems($moduleItems, string $fileId) + { + $instances = []; + foreach ($moduleItems as $item) { + if ($item['content_id'] == $fileId) { + $instances[] = $item; + } + } + + return $instances; + } + public function getCourseUrl(Course $course, User $user) { $domain = $this->getApiDomain($user); From 35c319ec02e1eb542abaa81384c74f4768a54d36 Mon Sep 17 00:00:00 2001 From: Ahmad Altaher Alfayad Date: Mon, 13 May 2024 17:46:46 -0400 Subject: [PATCH 2/4] add replacement functionality for assignment descriptions --- src/Lms/Canvas/CanvasApi.php | 33 ++++++++++++++++++++++++++++++++- src/Lms/Canvas/CanvasLms.php | 29 +++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/Lms/Canvas/CanvasApi.php b/src/Lms/Canvas/CanvasApi.php index cb2487b9..828c83c6 100644 --- a/src/Lms/Canvas/CanvasApi.php +++ b/src/Lms/Canvas/CanvasApi.php @@ -106,7 +106,7 @@ public function apiPost($url, $options, $sendAuthorized = true) } // Posts a file to Canvas - public function apiFilePost(string $url, array $options, string $filepath, string $newFileName, $moduleInstances = null, $courseId = null, $replacePages = null) : LmsResponse + public function apiFilePost(string $url, array $options, string $filepath, string $newFileName, $moduleInstances = null, $courseId = null, $replacePages = null, $replaceAssignments = null) : LmsResponse { $fileResponse = $this->apiGet($url); $file = $fileResponse->getContent(); @@ -188,6 +188,30 @@ public function apiFilePost(string $url, array $options, string $filepath, strin } } + if ($replaceAssignments) { + foreach ($replaceAssignments as $assignment) { + $dom = new \DOMDocument(); + $dom->loadHTML($assignment['description']); + $anchors = $dom->getElementsByTagName('a'); + foreach ($anchors as $anchor) { + preg_match('/files\/(\d+)/', $anchor->getAttribute('href'), $matches); + if (isset($matches[1]) && $matches[1] == $file['id']) { + $anchor->setAttribute('href', $fileResponseContent['url']); + $anchor->setAttribute('title', $newFileName); + $anchor->nodeValue = $newFileName; + } + $assignment['description'] = $dom->saveHTML(); + $response = $this->apiPut("courses/{$courseId}/assignments/{$assignment['id']}", [ + 'json' => [ + 'assignment' => [ + 'description' => $assignment['description'], + ], + ], + ]); + } + } + } + return $fileResponse; } @@ -286,4 +310,11 @@ public function showPage($courseId, $pageId) return $response->getContent(); } + public function listAssignments($courseId) + { + $url = "courses/{$courseId}/assignments"; + $response = $this->apiGet($url); + return $response->getContent(); + } + } diff --git a/src/Lms/Canvas/CanvasLms.php b/src/Lms/Canvas/CanvasLms.php index 18332643..ee5a3f0a 100644 --- a/src/Lms/Canvas/CanvasLms.php +++ b/src/Lms/Canvas/CanvasLms.php @@ -378,8 +378,10 @@ public function postFileItem(FileItem $file, string $newFileName) $canvasApi = new CanvasApi($apiDomain, $apiToken); $modules = $canvasApi->listModules($file->getCourse()->getLmsCourseId()); $pages = $canvasApi->listPages($file->getCourse()->getLmsCourseId()); + $assignments = $canvasApi->listAssignments($file->getCourse()->getLmsCourseId()); $refillModules = []; $changePages = []; + $changeAssignments = []; // Delete any existing module items with the same file name foreach ($modules as $module) { @@ -393,7 +395,7 @@ public function postFileItem(FileItem $file, string $newFileName) } } - // Find all pages that contain this file in their HTML + // Find all wiki pages that contain this file in their HTML foreach ($pages as $page) { $dom = new \DOMDocument(); $dom->loadHTML($page['body']); @@ -407,13 +409,20 @@ public function postFileItem(FileItem $file, string $newFileName) } } + // Find all assignments that contain this file in their description HTML + foreach ($assignments as $assignment) { + if ($this->fileIsInLink($file->getLmsFileId(), $assignment['description'])) { + $changeAssignments[] = $assignment; + } + } + $url = "courses/{$file->getCourse()->getLmsCourseId()}/files/{$file->getLmsFileId()}"; $filepath = $this->util->getTempPath() . '/file.' . $file->getId(); $options = [ 'postUrl' => "courses/{$file->getCourse()->getLmsCourseId()}/files" ]; - $fileResponse = $canvasApi->apiFilePost($url, $options, $filepath, $newFileName, $refillModules, $file->getCourse()->getLmsCourseId(), $changePages); + $fileResponse = $canvasApi->apiFilePost($url, $options, $filepath, $newFileName, $refillModules, $file->getCourse()->getLmsCourseId(), $changePages, $changeAssignments); $fileObj = $fileResponse->getContent(); if (isset($fileObj['id'])) { @@ -535,6 +544,22 @@ public function getContentTypes() * PROTECTED FUNCTIONS **********************/ + protected function fileIsInLink($fileId, $html) + { + $dom = new \DOMDocument(); + $dom->loadHTML($html); + $anchors = $dom->getElementsByTagName('a'); + + foreach ($anchors as $anchor) { + preg_match('/files\/(\d+)/', $anchor->getAttribute('href'), $matches); + if(isset($matches[1]) && $matches[1] == $fileId) { + return true; + } + } + + return false; + } + protected function getAccountInfo(User $user, $accountId) { $url = "accounts/${accountId}"; From 95037a4dadaee5e2a31c02f7cd97506ecc1e7a20 Mon Sep 17 00:00:00 2001 From: Ahmad Altaher Alfayad Date: Thu, 16 May 2024 11:54:27 -0400 Subject: [PATCH 3/4] add all replacement functionality, relay more information to user in replacement modal --- assets/js/Components/FilesModal.js | 6 + src/Lms/Canvas/CanvasApi.php | 267 +++++++++++++++++++++-------- src/Lms/Canvas/CanvasLms.php | 40 +++-- translations/en.json | 3 +- 4 files changed, 224 insertions(+), 92 deletions(-) diff --git a/assets/js/Components/FilesModal.js b/assets/js/Components/FilesModal.js index f34e5888..79c2f6cc 100644 --- a/assets/js/Components/FilesModal.js +++ b/assets/js/Components/FilesModal.js @@ -270,6 +270,12 @@ class FilesModal extends React.Component { return } + const userConfirmed = window.confirm(this.props.t('msg.confirmation')); + + if (!userConfirmed) { + return; + } + let api = new Api(this.props.settings) api.postFile(activeFile, this.state.replaceFileObj) .then((responsStr) => responsStr.json()) diff --git a/src/Lms/Canvas/CanvasApi.php b/src/Lms/Canvas/CanvasApi.php index 828c83c6..c901a7ce 100644 --- a/src/Lms/Canvas/CanvasApi.php +++ b/src/Lms/Canvas/CanvasApi.php @@ -106,7 +106,7 @@ public function apiPost($url, $options, $sendAuthorized = true) } // Posts a file to Canvas - public function apiFilePost(string $url, array $options, string $filepath, string $newFileName, $moduleInstances = null, $courseId = null, $replacePages = null, $replaceAssignments = null) : LmsResponse + public function apiFilePost(string $url, array $options, string $filepath, string $newFileName, $changeReferences = null) : LmsResponse { $fileResponse = $this->apiGet($url); $file = $fileResponse->getContent(); @@ -122,8 +122,6 @@ public function apiFilePost(string $url, array $options, string $filepath, strin $endpointResponse = $this->apiPost($options['postUrl'], ['query' => $endpointOptions], true); $endpointContent = $endpointResponse->getContent(); - $this->apiDelete($url); - // TODO: handle failed call $formFields = $endpointContent['upload_params']; @@ -137,79 +135,13 @@ public function apiFilePost(string $url, array $options, string $filepath, strin $fileResponseContent = $fileResponse->getContent(); - if($moduleInstances) { - foreach ($moduleInstances as $moduleInstance) { - $response = $this->apiPost("courses/{$courseId}/modules/{$moduleInstance}/items", [ - 'json' => [ - 'module_item' => [ - 'title' => $newFileName, - 'type' => 'File', - 'content_id' => $fileResponseContent['id'], - ], - ], - ]); - - } - } - - if($replacePages) { - foreach ($replacePages as $page) { - $dom = new \DOMDocument(); - $dom->loadHTML($page['body']); - $anchors = $dom->getElementsByTagName('a'); - foreach ($anchors as $anchor) { - preg_match('/files\/(\d+)/', $anchor->getAttribute('href'), $matches); - if (isset($matches[1]) && $matches[1] == $file['id']) { - $anchor->setAttribute('href', $fileResponseContent['url']); - $anchor->setAttribute('title', $newFileName); - $anchor->nodeValue = $newFileName; - } - $page['body'] = $dom->saveHTML(); - $response = $this->apiPut("courses/{$courseId}/pages/{$page['page_id']}", [ - 'json' => [ - 'wiki_page' => [ - 'title' => $page['title'], - 'body' => $page['body'], - 'editing_roles' => $page['editing_roles'], - 'published' => $page['published'], - 'front_page' => $page['front_page'], - 'hide_from_students' => $page['hide_from_students'], - 'notify_of_update' => $page['notify_of_update'], - 'attachments' => [ - [ - 'url' => $fileResponseContent['url'], - 'filename' => $newFileName, - ], - ], - ], - ], - ]); - } - } - } - - if ($replaceAssignments) { - foreach ($replaceAssignments as $assignment) { - $dom = new \DOMDocument(); - $dom->loadHTML($assignment['description']); - $anchors = $dom->getElementsByTagName('a'); - foreach ($anchors as $anchor) { - preg_match('/files\/(\d+)/', $anchor->getAttribute('href'), $matches); - if (isset($matches[1]) && $matches[1] == $file['id']) { - $anchor->setAttribute('href', $fileResponseContent['url']); - $anchor->setAttribute('title', $newFileName); - $anchor->nodeValue = $newFileName; - } - $assignment['description'] = $dom->saveHTML(); - $response = $this->apiPut("courses/{$courseId}/assignments/{$assignment['id']}", [ - 'json' => [ - 'assignment' => [ - 'description' => $assignment['description'], - ], - ], - ]); - } - } + if($changeReferences) { + $this->changeLinksInSyllabus($changeReferences['course_id'], $file['id'], $fileResponseContent['url'], $newFileName); + $this->changeModuleItemInstances($changeReferences['course_id'], $changeReferences['modules'], $newFileName, $fileResponseContent['id']); + $this->changeLinksInPages($changeReferences['course_id'], $file['id'], $changeReferences['pages'], $fileResponseContent['url'], $newFileName); + $this->changeLinksInAssignments($changeReferences['course_id'], $file['id'], $changeReferences['assignments'], $fileResponseContent['url'], $newFileName); + $this->changeLinksInQuizzes($changeReferences['course_id'], $file['id'], $changeReferences['quizzes'], $fileResponseContent['url'], $newFileName); + $this->changeLinksInQuizQuestions($changeReferences['course_id'], $file['id'], $changeReferences['quizQuestions'], $fileResponseContent['url'], $newFileName); } return $fileResponse; @@ -266,6 +198,18 @@ public function apiDelete($url) { } + public function getCourse($courseId, $includeSyllabus = false) + { + if ($includeSyllabus) { + $url = "courses/{$courseId}?include[]=syllabus_body"; + } + else { + $url = "courses/{$courseId}"; + } + $response = $this->apiGet($url); + return $response->getContent(); + } + public function listModules($courseId) { $url = "courses/{$courseId}/modules"; @@ -317,4 +261,175 @@ public function listAssignments($courseId) return $response->getContent(); } + public function listQuizzes($courseId) + { + $url = "courses/{$courseId}/quizzes"; + $response = $this->apiGet($url); + return $response->getContent(); + } + + public function listQuizQuestions($courseId, $quizId) + { + $url = "courses/{$courseId}/quizzes/{$quizId}/questions"; + $response = $this->apiGet($url); + return $response->getContent(); + } + + public function updateCourse($courseId, $options) + { + $url = "courses/{$courseId}"; + $response = $this->apiPut($url, $options); + return $response->getContent(); + } + + public function uploadModuleItem($courseId, $moduleId, $options) + { + $url = "courses/{$courseId}/modules/{$moduleId}/items"; + $response = $this->apiPost($url, $options); + return $response->getContent(); + } + + public function updatePage($courseId, $pageId, $options) + { + $url = "courses/{$courseId}/pages/{$pageId}"; + $response = $this->apiPut($url, $options); + return $response->getContent(); + } + + public function updateAssignment($courseId, $assignmentId, $options) + { + $url = "courses/{$courseId}/assignments/{$assignmentId}"; + $response = $this->apiPut($url, $options); + return $response->getContent(); + } + + public function updateQuiz($courseId, $quizId, $options) + { + $url = "courses/{$courseId}/quizzes/{$quizId}"; + $response = $this->apiPut($url, $options); + return $response->getContent(); + } + + public function updateQuizQuestion($courseId, $quizId, $questionId, $options) + { + $url = "courses/{$courseId}/quizzes/{$quizId}/questions/{$questionId}"; + $response = $this->apiPut($url, $options); + return $response->getContent(); + } + + /********************** + * PROTECTED FUNCTIONS + **********************/ + + + protected function changeLinksInSyllabus($courseId, $oldFileId, $newUrl, $newFileName) + { + $course = $this->getCourse($courseId, true); + $dom = new \DOMDocument(); + + $dom->loadHTML($course['syllabus_body']); + $anchors = $dom->getElementsByTagName('a'); + $newSyllabus = $this->changeAnchorTags($dom, $oldFileId, $newUrl, $newFileName); + if ($newSyllabus != $course['syllabus_body']) { + $this->updateCourse($courseId, ['json' => ['course' => ['syllabus_body' => $newSyllabus]]]); + } + } + + protected function changeModuleItemInstances($courseId, $moduleInstances, $newFileName, $newFileId) { + foreach ($moduleInstances as $moduleInstance) { + $this->uploadModuleItem($courseId, $moduleInstance, [ + 'json' => [ + 'module_item' => [ + 'title' => $newFileName, + 'type' => 'File', + 'content_id' => $newFileId, + ], + ], + ]); + } + } + + protected function changeLinksInPages($courseId, $oldFileId, $pages, $newUrl, $newFileName) { + foreach ($pages as $page) { + $dom = new \DOMDocument(); + $dom->loadHTML($page['body']); + $newPage = $this->changeAnchorTags($dom, $oldFileId, $newUrl, $newFileName); + if ($newPage != $page['body']) { + $this->updatePage($courseId, $page['page_id'], [ + 'json' => [ + 'wiki_page' => [ + 'body' => $newPage, + ], + ], + ]); + } + } + } + + protected function changeLinksInAssignments($courseId, $oldFileId, $assignments, $newUrl, $newFileName) { + foreach ($assignments as $assignment) { + $dom = new \DOMDocument(); + $dom->loadHTML($assignment['description']); + $newAssignment = $this->changeAnchorTags($dom, $oldFileId, $newUrl, $newFileName); + if ($newAssignment != $assignment['description']) { + $this->updateAssignment($courseId, $assignment['id'], [ + 'json' => [ + 'assignment' => [ + 'description' => $newAssignment, + ], + ], + ]); + } + } + } + + protected function changeLinksInQuizzes($courseId, $oldFileId, $quizzes, $newUrl, $newFileName) { + foreach ($quizzes as $quiz) { + $dom = new \DOMDocument(); + $dom->loadHTML($quiz['description']); + $newQuiz = $this->changeAnchorTags($dom, $oldFileId, $newUrl, $newFileName); + if ($newQuiz != $quiz['description']) { + $this->updateQuiz($courseId, $quiz['id'], [ + 'json' => [ + 'quiz' => [ + 'description' => $newQuiz, + 'notify_of_update' => $quiz['notify_of_update'], + ], + ], + ]); + } + } + } + + public function changeLinksInQuizQuestions($courseId, $oldFileId, $replaceQuizQuestions, $newUrl, $newFileName) { + foreach ($replaceQuizQuestions as $quizQuestion) { + $dom = new \DOMDocument(); + $dom->loadHTML($quizQuestion['question_text']); + $newQuestion = $this->changeAnchorTags($dom, $oldFileId, $newUrl, $newFileName); + if ($newQuestion != $quizQuestion['question_text']) { + $this->updateQuizQuestion($courseId, $quizQuestion['quiz_id'], $quizQuestion['id'], [ + 'json' => [ + 'question' => [ + 'question_text' => $newQuestion, + ], + ], + ]); + } + } + } + + protected function changeAnchorTags($dom, $fileId, $newUrl, $newFileName) { + $anchors = $dom->getElementsByTagName('a'); + foreach ($anchors as $anchor) { + preg_match('/files\/(\d+)/', $anchor->getAttribute('href'), $matches); + if (isset($matches[1]) && $matches[1] == $fileId) { + $anchor->setAttribute('href', $newUrl); + $anchor->setAttribute('title', $newFileName); + $anchor->nodeValue = $newFileName; + } + } + + return $dom->saveHTML(); + } + } diff --git a/src/Lms/Canvas/CanvasLms.php b/src/Lms/Canvas/CanvasLms.php index ee5a3f0a..52c2a297 100644 --- a/src/Lms/Canvas/CanvasLms.php +++ b/src/Lms/Canvas/CanvasLms.php @@ -379,9 +379,8 @@ public function postFileItem(FileItem $file, string $newFileName) $modules = $canvasApi->listModules($file->getCourse()->getLmsCourseId()); $pages = $canvasApi->listPages($file->getCourse()->getLmsCourseId()); $assignments = $canvasApi->listAssignments($file->getCourse()->getLmsCourseId()); - $refillModules = []; - $changePages = []; - $changeAssignments = []; + $quizzes = $canvasApi->listQuizzes($file->getCourse()->getLmsCourseId()); + $changeReferences = ['course_id' => $file->getCourse()->getLmsCourseId(),'modules' => [], 'pages' => [], 'assignments' => [], 'quizzes' => [], 'quizQuestions' => []]; // Delete any existing module items with the same file name foreach ($modules as $module) { @@ -391,28 +390,39 @@ public function postFileItem(FileItem $file, string $newFileName) foreach ($instances as $instance) { $canvasApi->deleteModuleItem($file->getCourse()->getLmsCourseId(), $module['id'], $instance['id']); } - $refillModules[] = $module['id']; + $changeReferences['modules'][] = $module['id']; } } // Find all wiki pages that contain this file in their HTML foreach ($pages as $page) { - $dom = new \DOMDocument(); - $dom->loadHTML($page['body']); - $anchors = $dom->getElementsByTagName('a'); - foreach ($anchors as $anchor) { - preg_match('/files\/(\d+)/', $anchor->getAttribute('href'), $matches); - if(isset($matches[1]) && $matches[1] == $file->getLmsFileId()) { - $changePages[] = $page; - break; - } + if ($this->fileIsInLink($file->getLmsFileId(), $page['body'])) { + $changeReferences['pages'][] = $page; } } // Find all assignments that contain this file in their description HTML foreach ($assignments as $assignment) { if ($this->fileIsInLink($file->getLmsFileId(), $assignment['description'])) { - $changeAssignments[] = $assignment; + $changeReferences['assignments'][] = $assignment; + } + } + + // Find all quizzes that contain this file in their description HTML + foreach ($quizzes as $quiz) { + if ($this->fileIsInLink($file->getLmsFileId(), $quiz['description'])) { + $changeReferences['quizzes'][] = $quiz; + } + + // Check quiz questions for references to the file + $questions[] = $canvasApi->listQuizQuestions($file->getCourse()->getLmsCourseId(), $quiz['id']); + + $questions = $questions[0]; + + foreach ($questions as $question) { + if ($this->fileIsInLink($file->getLmsFileId(), $question['question_text'])) { + $changeReferences['quizQuestions'][] = $question; + } } } @@ -422,7 +432,7 @@ public function postFileItem(FileItem $file, string $newFileName) 'postUrl' => "courses/{$file->getCourse()->getLmsCourseId()}/files" ]; - $fileResponse = $canvasApi->apiFilePost($url, $options, $filepath, $newFileName, $refillModules, $file->getCourse()->getLmsCourseId(), $changePages, $changeAssignments); + $fileResponse = $canvasApi->apiFilePost($url, $options, $filepath, $newFileName, $changeReferences); $fileObj = $fileResponse->getContent(); if (isset($fileObj['id'])) { diff --git a/translations/en.json b/translations/en.json index 498fbecc..a09bc7ec 100644 --- a/translations/en.json +++ b/translations/en.json @@ -127,6 +127,7 @@ "menu.full_rescan": "Force Full Rescan", "msg.no_permissions": "You do not have permission to access the specified course.", + "msg.confirmation": "Are you sure you want to replace this file? This action cannot be undone.", "msg.course_scanning": "Course scanning...", "msg.no_new_content": "Course scan complete. No new content found.", "msg.new_content": "Course scan complete. New content has been added.", @@ -175,7 +176,7 @@ "label.next_file": "Next File", "label.upload": "Upload", "label.replace": "Replace File", - "label.replace.desc": "Replace the current version of this file here.", + "label.replace.desc": "Replace the current version of this file here. This modal will replace all instances of the file in assignments, pages, modules, syllabus, quizzes and quiz questions. This action cannot be undone.", "label.loading": "Loading", "label.loading_reports": "Loading report history", "label.loading_users": "Loading users", From 6b2049eb2b60474070d6ea7e5da1412a5f66b823 Mon Sep 17 00:00:00 2001 From: Ahmad Altaher Alfayad Date: Thu, 6 Jun 2024 14:01:14 -0400 Subject: [PATCH 4/4] update apiDelete to delete everything, not just files --- src/Lms/Canvas/CanvasApi.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Lms/Canvas/CanvasApi.php b/src/Lms/Canvas/CanvasApi.php index c901a7ce..3115407d 100644 --- a/src/Lms/Canvas/CanvasApi.php +++ b/src/Lms/Canvas/CanvasApi.php @@ -173,12 +173,8 @@ public function apiPut($url, $options) public function apiDelete($url) { $lmsResponse = new LmsResponse(); - if (strpos($url, 'https://') === false) { - $pattern = '/\/files\/\d+/'; - - preg_match($pattern, $url, $matches); - - $url = "https://" . $this->baseUrl . "/api/v1/" . $matches[0]; + if (strpos($url, 'https://') === false) { + $url = "https://{$this->baseUrl}/api/v1/{$url}"; } $response = $this->httpClient->request('DELETE', $url);