diff --git a/README.md b/README.md index ffb35a3..6999e68 100644 --- a/README.md +++ b/README.md @@ -26,15 +26,22 @@ The external links module is a task and ModelAdmin to track and to report on bro 5. Run in your browser - `/dev/build` to rebuild the database. 6. Run the following task *http://path.to.silverstripe/dev/tasks/CheckExternalLinks* to check for broken external links +## Report ## + +A new report is added called 'External Broken links report' from here you can also start a new job which is run +via AJAX and in batches of 10 so it can be run via content editors who do not have access to jobs or tasks. + ## Dev task ## Run the following task *http://path.to.silverstripe/dev/tasks/CheckExternalLinks* to check your site for external broken links. + +## Queued job ## + If you have the queuedjobs module installed you can set the task to be run every so ofter Add the following yml config to config.yml in mysite/_config have the the task run once every day (86400 seconds) -`--- -Name: externallinkssettings ---- +``` CheckExternalLinks: - Delay: 86400` + Delay: 86400 +``` diff --git a/code/controllers/CMSExternalLinks.php b/code/controllers/CMSExternalLinks.php index e6769d1..5c23815 100644 --- a/code/controllers/CMSExternalLinks.php +++ b/code/controllers/CMSExternalLinks.php @@ -2,19 +2,69 @@ class CMSExternalLinks_Controller extends Controller { - private static $allowed_actions = array('createQueuedReport'); + private static $allowed_actions = array('getJobStatus', 'clear', 'start'); + /* + * Respond to Ajax requests for info on a running job + * also calls continueJob and clear depending on the status of the job + * + * @return string JSON string detailing status of the job + */ + public function getJobStatus() { + $trackID = Session::get('ExternalLinksTrackID'); + if (!$trackID) return; + $noPages = Versioned::get_by_stage('SiteTree', 'Live')->count(); + $result = BrokenExternalPageTrack::get() + ->filter('TrackID', $trackID) + ->exclude('PageID', 0); + $completedPages = count($result); - public function createQueuedReport() { - if (!Permission::check('ADMIN')) return; + echo json_encode(array( + 'TrackID' => $trackID, + 'Completed' => $completedPages, + 'Total' => $noPages + )); - // setup external links job - $externalLinks = new CheckExternalLinksJob(); - $job = singleton('QueuedJobService'); - $jobID = $job->queueJob($externalLinks); + if ($completedPages >= $noPages) { + $this->clear(); + } else { + $this->continueJob(); + } + } + + /* + * Clears the tracking id and any surplus entries for the BrokenExternalPageTrack model + */ + public function clear() { + // clear any old entries + $trackID = Session::get('ExternalLinksTrackID'); + $oldEntries = BrokenExternalPageTrack::get() + ->exclude('TrackID', $trackID); + foreach ($oldEntries as $entry) { + $entry->delete(); + } + Session::clear('ExternalLinksTrackID'); + } + + /* + * Starts a broken external link check + */ + public function start() { + $track = BrokenExternalPageTrack::create(); + $track->write(); + $track->TrackID = $track->ID; + $track->write(); + + Session::set('ExternalLinksTrackID', $track->ID); + + $this->continueJob(); + } - // redirect to the jobs page - $admin = QueuedJobsAdmin::create(); - $this->Redirect($admin->Link()); + /* + * Continues a broken external link check + */ + public function continueJob() { + $task = new CheckExternalLinks(); + $task->run(null); } } diff --git a/code/jobs/CheckExternalLinksJob.php b/code/jobs/CheckExternalLinksJob.php index ba569ca..af76fc2 100644 --- a/code/jobs/CheckExternalLinksJob.php +++ b/code/jobs/CheckExternalLinksJob.php @@ -56,7 +56,8 @@ public function process() { } $task = new CheckExternalLinks(); - $task->run($page); + $task->pageToProcess = $page; + $task->run(); // and now we store the new list of remaining children $this->pagesToProcess = $remainingPages; diff --git a/code/model/BrokenExternalLink.php b/code/model/BrokenExternalLink.php index 1de3554..89aeeb8 100644 --- a/code/model/BrokenExternalLink.php +++ b/code/model/BrokenExternalLink.php @@ -31,3 +31,13 @@ function canView($member = false) { return Permission::checkMember($member, $codes); } } + +class BrokenExternalPageTrack extends DataObject { + private static $db = array( + 'TrackID' => 'Int' + ); + + private static $has_one = array( + 'Page' => 'Page' + ); +} diff --git a/code/reports/BrokenExternalLinksReport.php b/code/reports/BrokenExternalLinksReport.php index 4bfe568..9e54a46 100644 --- a/code/reports/BrokenExternalLinksReport.php +++ b/code/reports/BrokenExternalLinksReport.php @@ -66,19 +66,20 @@ public function sourceRecords() { } public function getCMSFields() { + Requirements::javascript('externallinks/javascript/BrokenExternalLinksReport.js'); $fields = parent::getCMSFields(); if (class_exists('AbstractQueuedJob')) { - $button = ''; + $button = ''; $runReportButton = new LiteralField( 'runReport', sprintf( $button, - 'admin/externallinks/createQueuedReport', _t('ExternalBrokenLinksReport.RUNREPORT', 'Create new report') ) ); $fields->push($runReportButton); - $reportResultSpan = ''; + + $reportResultSpan = '

'; $reportResult = new LiteralField('ResultTitle', $reportResultSpan); $fields->push($reportResult); } diff --git a/code/tasks/CheckExternalLinks.php b/code/tasks/CheckExternalLinks.php index a6ef0b0..b0e2d40 100644 --- a/code/tasks/CheckExternalLinks.php +++ b/code/tasks/CheckExternalLinks.php @@ -1,6 +1,7 @@ completedPages; - } - - public function getTotalPages() { - return $this->totalPages; - } - function run($request) { - if (isset($request->ID)) { - $pages = $request; + $trackID = Session::get('ExternalLinksTrackID'); + if (isset($this->pageToProcess)) { + $pages = $this->pageToProcess; } else { - $pages = Versioned::get_by_stage('SiteTree', 'Live'); + if ($trackID) { + $result = BrokenExternalPageTrack::get() + ->filter('TrackID', $trackID); + $pages = Versioned::get_by_stage('SiteTree', 'Live') + ->exclude('ID', $result->column('PageID')) + ->limit(10); + } else { + $pages = Versioned::get_by_stage('SiteTree', 'Live'); + } } foreach ($pages as $page) { ++$this->totalPages; @@ -93,6 +95,12 @@ function run($request) { } } ++$this->completedPages; + if ($trackID) { + $trackPage = new BrokenExternalPageTrack(); + $trackPage->PageID = $page->ID; + $trackPage->TrackID = $trackID; + $trackPage->write(); + } } // run this again if queued jobs exists and is a valid int diff --git a/javascript/BrokenExternalLinksReport.js b/javascript/BrokenExternalLinksReport.js new file mode 100644 index 0000000..9cf4a32 --- /dev/null +++ b/javascript/BrokenExternalLinksReport.js @@ -0,0 +1,45 @@ +(function($) { + $('#externalLinksReport').entwine({ + onclick: function() { + $(this).start(); + $(this).poll(); + }, + start: function() { + // initiate a new job + $('#ReportHolder').empty(); + $('#ReportHolder').text('Running report 0%'); + $('#ReportHolder').append(''); + $.ajax({url: "admin/externallinks/start", async: true, timeout: 1000 }); + }, + poll: function() { + // poll the current job and update the front end status + $.ajax({ + url: "admin/externallinks/getJobStatus", + async: true, + success: function(data) { + var obj = $.parseJSON(data); + if (!obj) return; + var completed = obj.Completed ? obj.Completed : 0; + var total = obj.Total ? obj.Total : 0; + if (total > 0 && completed == total) { + $('#ReportHolder').text('Report Finished ' + completed + '/' + total); + } else { + setTimeout(function() { $('#externalLinksReport').poll(); }, 1); + } + if (total && completed) { + if (completed < total) { + var percent = (completed / total) * 100; + $('#ReportHolder').text('Running report ' + completed + '/' + + total + ' (' + percent.toFixed(2) + '%)'); + $('#ReportHolder'). + append(''); + } + } + }, + error: function(e) { + console.log(e); + } + }); + } + }); +}(jQuery));