Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding in tests and report creation button #1

Open
wants to merge 12 commits into
base: plat-59
Choose a base branch
from
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
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,32 @@ 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 code to the mysite config to run the job every 24 hours (86400 seconds)
Add the following yml config to config.yml in mysite/_config have the the task run once every day (86400 seconds)

CheckExternalLinks:
Delay: 86400

`Config::inst()->update('CheckExternalLinks', 'QueuedJob', 86400);`
## Whitelisting codes ##

If you want to ignore or whitelist certain http codes this can be setup via IgnoreCodes in the config.yml
file in mysite/_config

CheckExternalLinks:
Delay: 60
IgnoreCodes:
- 401
- 403
- 501
7 changes: 7 additions & 0 deletions _config/routes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
Name: externallink
After: framework/routes
---
Director:
rules:
'admin/externallinks//$Action': 'CMSExternalLinks_Controller'
60 changes: 60 additions & 0 deletions code/controllers/CMSExternalLinks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

class CMSExternalLinks_Controller extends Controller {

private static $allowed_actions = array('getJobStatus', 'start');

/*
* Respond to Ajax requests for info on a running job
*
* @return string JSON string detailing status of the job
*/
public function getJobStatus() {
$track = CheckExternalLinks::getLatestTrack();
if (!$track || !$track->exists()) return null;
echo json_encode(array(
'TrackID' => $track->ID,
'Status' => $track->Status,
'Completed' => $track->CompletedPages,
'Total' => $track->TotalPages
));
}


/*
* Starts a broken external link check
*/
public function start() {
$status = checkExternalLinks::getLatestTrackStatus();
// return if the a job is already running
if ($status == 'Running') {
return;
}
if (class_exists('QueuedJobService')) {
$pages = Versioned::get_by_stage('SiteTree', 'Stage');
$noPages = count($pages);

$track = BrokenExternalPageTrackStatus::create();
$track->TotalPages = $noPages;
$track->Status = 'Running';
$track->write();

foreach ($pages as $page) {
$trackPage = BrokenExternalPageTrack::create();
$trackPage->PageID = $page->ID;
$trackPage->TrackID = $track->ID;
$trackPage->write();
}

$checkLinks = new CheckExternalLinksJob();
singleton('QueuedJobService')
->queueJob($checkLinks, date('Y-m-d H:i:s', time() + 1));
} else {
//TODO this hangs as it waits for the connection to be released
// should return back and continue processing
// http://us3.php.net/manual/en/features.connection-handling.php
$task = new CheckExternalLinks();
$task->run();
}
}
}
51 changes: 8 additions & 43 deletions code/jobs/CheckExternalLinksJob.php
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
<?php

if(!class_exists('AbstractQueuedJob')) return;

/**
* A Job for running a external link check for published pages
*
*/
class CheckExternalLinksJob extends AbstractQueuedJob implements QueuedJob {

public function __construct() {
$this->pagesToProcess = Versioned::get_by_stage('SiteTree', 'Live')->column();
$this->currentStep = 0;
$this->totalSteps = count($this->pagesToProcess);
}

public function getTitle() {
return 'Checking external links';
return _t('CheckExternalLiksJob.TITLE', 'Checking for external broken links');
}

public function getJobType() {
Expand All @@ -24,46 +20,15 @@ public function getSignature() {
return md5(get_class($this));
}

public function setup() {
parent::setup();
$restart = $this->currentStep == 0;
if ($restart) {
$this->pagesToProcess = Versioned::get_by_stage('SiteTree', 'Live')->column();
}

}

/**
* Check a individual page
* Check an individual page
*/
public function process() {
$remainingPages = $this->pagesToProcess;
if (!count($remainingPages)) {
$this->isComplete = true;
return;
}

// lets process our first item - note that we take it off the list of things left to do
$ID = array_shift($remainingPages);

// get the page
$page = Versioned::get_by_stage('SiteTree', 'Live', 'ID = '.$ID);

if (!$page || !$page->Count()) {
$this->addMessage("Page ID #$ID could not be found, skipping");
}

$task = new CheckExternalLinks();
$task->run($page);

// and now we store the new list of remaining children
$this->pagesToProcess = $remainingPages;
$this->currentStep++;

if (!count($remainingPages)) {
$this->isComplete = true;
return;
}
$track = $task->runLinksCheck(1);
$this->currentStep = $track->CompletedPages;
$this->totalSteps = $track->TotalPages;
$this->isComplete = $track->Status === 'Completed';
}

}
53 changes: 53 additions & 0 deletions code/model/BrokenExternalLink.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

class BrokenExternalLink extends DataObject {

private static $db = array(
'Link' => 'Varchar(2083)', // 2083 is the maximum length of a URL in Internet Explorer.
'HTTPCode' =>'Int'
);

private static $has_one = array(
'Page' => 'Page'
);

public static $summary_fields = array(
'Page.Title' => 'Page',
'HTTPCode' => 'HTTP Code',
'Created' => 'Created'
);

public static $searchable_fields = array(
'HTTPCode' => array('title' => 'HTTP Code')
);

function canEdit($member = false) {
return false;
}

function canView($member = false) {
$member = $member ? $member : Member::currentUser();
$codes = array('content-authors', 'administrators');
return Permission::checkMember($member, $codes);
}
}

class BrokenExternalPageTrackStatus extends DataObject {
private static $db = array(
'Status' => 'Enum("Completed, Running", "Running")',
'TotalPages' => 'Int',
'CompletedPages' => 'Int',
'JobInfo' => 'Varchar(255)'
);
}

class BrokenExternalPageTrack extends DataObject {
private static $db = array(
'TrackID' => 'Int',
'Processed' => 'Boolean'
);

private static $has_one = array(
'Page' => 'Page'
);
}
28 changes: 0 additions & 28 deletions code/model/BrokenExternalLinks.php

This file was deleted.

89 changes: 89 additions & 0 deletions code/reports/BrokenExternalLinksReport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

/**
* Content side-report listing pages with external broken links
* @package externallinks
* @subpackage content
*/

class BrokenExternalLinksReport extends SS_Report {

/**
* Columns in the report
*
* @var array
* @config
*/
private static $columns = array(
'Created' => 'Checked',
'Link' => 'External Link',
'HTTPCode' => 'HTTP Error Code',
'PageLink' => array(
'title' => 'Page link is on',
'link' => true
),
);

public function init() {
parent::init();
}

/**
* Returns the report title
*
* @return string
*/
public function title() {
return _t('ExternalBrokenLinksReport.EXTERNALBROKENLINKS',"External broken links report");
}

/**
* Returns the column names of the report
*
* @return array
*/
public function columns() {
return self::$columns;
}

/**
* Alias of columns(), to support the export to csv action
* in {@link GridFieldExportButton} generateExportFileData method.
* @return array
*/
public function getColumns() {
return $this->columns();
}

public function sourceRecords() {
$returnSet = new ArrayList();
$links = BrokenExternalLink::get();
foreach ($links as $link) {
$link->PageLink = $link->Page()->Title;
$link->ID = $link->Page()->ID;
$returnSet->push($link);
}
return $returnSet;
}

public function getCMSFields() {
Requirements::javascript('externallinks/javascript/BrokenExternalLinksReport.js');
$fields = parent::getCMSFields();

$reportResultSpan = '</ br></ br><h3 id="ReportHolder"></h3>';
$reportResult = new LiteralField('ResultTitle', $reportResultSpan);
$fields->push($reportResult);

$button = '<button id="externalLinksReport" type="button">%s</button>';
$runReportButton = new LiteralField(
'runReport',
sprintf(
$button,
_t('ExternalBrokenLinksReport.RUNREPORT', 'Create new report')
)
);
$fields->push($runReportButton);

return $fields;
}
}
Loading