diff --git a/assets/js/Components/App.js b/assets/js/Components/App.js index 6985d55b..9b4bab36 100644 --- a/assets/js/Components/App.js +++ b/assets/js/Components/App.js @@ -39,6 +39,7 @@ class App extends React.Component { this.handleIssueSave = this.handleIssueSave.bind(this) this.handleFileSave = this.handleFileSave.bind(this) this.handleCourseRescan = this.handleCourseRescan.bind(this) + this.handleFullCourseRescan = this.handleFullCourseRescan.bind(this) this.handleNewReport = this.handleNewReport.bind(this) this.resizeFrame = this.resizeFrame.bind(this) } @@ -53,6 +54,7 @@ class App extends React.Component { navigation={this.state.navigation} handleNavigation={this.handleNavigation} handleCourseRescan={this.handleCourseRescan} + handleFullCourseRescan={this.handleFullCourseRescan} handleModal={this.handleModal} /> {(('welcome' !== this.state.navigation) && ('summary' !== this.state.navigation)) && @@ -148,6 +150,11 @@ class App extends React.Component { return api.scanCourse(this.settings.course.id) } + fullRescan() { + let api = new Api(this.settings) + return api.fullRescan(this.settings.course.id) + } + disableReview = () => { return this.state.syncComplete && !this.state.disableReview } @@ -162,6 +169,16 @@ class App extends React.Component { this.forceUpdate() } + handleFullCourseRescan() { + if (this.state.hasNewReport) { + this.setState({ hasNewReport: false, syncComplete: false }) + this.fullRescan() + .then((response) => response.json()) + .then(this.handleNewReport) + } + this.forceUpdate() + } + handleNewReport(data) { let report = this.state.report let hasNewReport = this.state.hasNewReport diff --git a/assets/js/Components/Header.js b/assets/js/Components/Header.js index 5e860b80..ff5f492c 100644 --- a/assets/js/Components/Header.js +++ b/assets/js/Components/Header.js @@ -44,6 +44,7 @@ class Header extends React.Component { {/* this.handleMoreNav('settings')}>{this.props.t('menu.settings')} */} {this.props.t('menu.scan_course')} + {this.props.t('menu.full_rescan')} {this.props.t('menu.download_pdf')} diff --git a/assets/js/Services/Api.js b/assets/js/Services/Api.js index 3ace069d..330989c9 100644 --- a/assets/js/Services/Api.js +++ b/assets/js/Services/Api.js @@ -13,6 +13,7 @@ export default class Api { adminCourses: '/api/admin/courses/account/{account}/term/{term}', scanContent: '/api/sync/content/{contentItem}', scanCourse: '/api/sync/{course}', + fullRescan: '/api/sync/rescan/{course}', scanIssue: '/api/issues/{issue}/scan', adminReport: '/api/admin/courses/{course}/reports/latest', adminReportHistory: '/api/admin/reports/account/{account}/term/{term}', @@ -233,6 +234,21 @@ export default class Api { }) } + fullRescan(courseId) + { + const authToken = this.getAuthToken() + let url = `${this.apiUrl}${this.endpoints.fullRescan}` + url = url.replace('{course}', courseId) + + return fetch(url, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'X-AUTH-TOKEN': authToken, + }, + }) + } + scanContent(contentId) { const authToken = this.getAuthToken() diff --git a/src/Controller/SyncController.php b/src/Controller/SyncController.php index d9157326..307201d7 100644 --- a/src/Controller/SyncController.php +++ b/src/Controller/SyncController.php @@ -71,6 +71,59 @@ public function requestSync(Course $course, LmsFetchService $lmsFetch) return new JsonResponse($response); } + #[Route('/api/sync/rescan/{course}', name: 'full_rescan')] + public function fullCourseRescan(Course $course, LmsFetchService $lmsFetch) { + $response = new ApiResponse(); + $user = $this->getUser(); + $reportArr = false; + + try { + if (!$this->userHasCourseAccess($course)) { + throw new \Exception('msg.no_permissions'); + } + if ($course->isDirty()) { + throw new \Exception('msg.course_scanning'); + } + if (!$course->isActive()) { + $response->setData(0); + throw new \Exception('msg.sync.course_inactive'); + } + + $prevReport = $course->getPreviousReport(); + + $course->removeAllReports(); + + $lmsFetch->refreshLmsContent($course, $user); + + $report = $course->getLatestReport(); + + if (!$report) { + throw new \Exception('msg.no_report_created'); + } + + $reportArr = $report->toArray(); + $reportArr['files'] = $course->getFileItems(); + $reportArr['issues'] = $course->getAllIssues(); + $reportArr['contentItems'] = $course->getContentItems(); + + $response->setData($reportArr); + + if ($prevReport && ($prevReport->getIssueCount() == $report->getIssueCount())) { + $response->addMessage('msg.no_new_content', 'success', 5000); + } else { + $response->addMessage('msg.new_content', 'success', 5000); + } + } catch (\Exception $e) { + if ('msg.course_scanning' === $e->getMessage()) { + $response->addMessage($e->getMessage(), 'info', 0, false); + } else { + $response->addMessage($e->getMessage(), 'error', 0); + } + } + + return new JsonResponse($response); + } + #[Route('/api/sync/content/{contentItem}', name: 'content_sync', methods: ['GET'])] public function requestContentSync(ContentItem $contentItem, LmsFetchService $lmsFetch, PhpAllyService $phpAlly) { diff --git a/src/Entity/Course.php b/src/Entity/Course.php index 2e40a3a6..86d14c22 100644 --- a/src/Entity/Course.php +++ b/src/Entity/Course.php @@ -259,6 +259,12 @@ public function removeReport(Report $report): self return $this; } + public function removeAllReports(): self + { + $this->reports->clear(); + return $this; + } + public function getPreviousReport(): ?Report { $reports = $this->reports->toArray(); diff --git a/translations/en.json b/translations/en.json index fbc21735..816e1b07 100644 --- a/translations/en.json +++ b/translations/en.json @@ -124,6 +124,7 @@ "menu.admin": "Admin", "menu.download_pdf": "Download PDF", "menu.scan_course": "Rescan Course", + "menu.full_rescan": "Force Full Rescan", "msg.no_permissions": "You do not have permission to access the specified course.", "msg.course_scanning": "Course scanning...", diff --git a/translations/es.json b/translations/es.json index 38f4863c..001df103 100644 --- a/translations/es.json +++ b/translations/es.json @@ -124,6 +124,7 @@ "menu.admin": "Admin", "menu.download_pdf": "Descargar PDF", "menu.scan_course": "Volver a escanear Curso", + "menu.full_rescan": "Reiniciar escaneo completo", "msg.no_permissions": "No tienes permiso para acceder al curso especificado.", "msg.course_scanning": "Escaneando el curso...",