Skip to content

Commit

Permalink
Merge branch '1'
Browse files Browse the repository at this point in the history
  • Loading branch information
ScopeyNZ committed Jun 6, 2018
2 parents 4c164f7 + d0b5906 commit b65673d
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 30 deletions.
83 changes: 64 additions & 19 deletions src/Forms/GridFieldRefreshButton.php
Expand Up @@ -2,21 +2,19 @@

namespace BringYourOwnIdeas\Maintenance\Forms;

use BringYourOwnIdeas\Maintenance\Reports\SiteSummary;
use SilverStripe\ORM\DataList;
use SilverStripe\View\Requirements;
use SilverStripe\Forms\GridField\GridField_FormAction;
use SilverStripe\View\ArrayData;
use SilverStripe\Forms\GridField\GridField;
use BringYourOwnIdeas\Maintenance\Jobs\CheckForUpdatesJob;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injector;
use Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor;
use Symbiote\QueuedJobs\Services\QueuedJobService;
use Symbiote\QueuedJobs\Services\QueuedJob;
use BringYourOwnIdeas\Maintenance\Jobs\CheckForUpdatesJob;
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridField_ActionProvider;
use SilverStripe\Forms\GridField\GridField_FormAction;
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
use SilverStripe\Forms\GridField\GridField_URLHandler;
use SilverStripe\View\ArrayData;
use SilverStripe\View\Requirements;
use Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor;
use Symbiote\QueuedJobs\Services\QueuedJob;
use Symbiote\QueuedJobs\Services\QueuedJobService;

/**
* Adds a "Refresh" button to the bottom or top of a GridField.
Expand All @@ -26,6 +24,10 @@
*/
class GridFieldRefreshButton implements GridField_HTMLProvider, GridField_ActionProvider, GridField_URLHandler
{
private static $dependencies = [
'QueuedJobService' => '%$' . QueuedJobService::class,
];

/**
* @var array
* @config
Expand All @@ -38,6 +40,11 @@ class GridFieldRefreshButton implements GridField_HTMLProvider, GridField_Action
*/
protected $targetFragment;

/**
* @var QueuedJobService
*/
protected $queuedJobService;

/**
* @param string $targetFragment The HTML fragment to write the button into
*/
Expand Down Expand Up @@ -144,10 +151,10 @@ public function handleCheck()
*/
public function hasPendingJob()
{
/** @var QueuedJobDescriptor $job */
$job = Injector::inst()
->get(QueuedJobService::class)
->getJobList(QueuedJob::QUEUED)
// We care about any queued job in the immediate queue, or any queue if the job is already running
/** @var QueuedJobDescriptor $immediateJob */
$immediateJob = $this->getQueuedJobService()
->getJobList(QueuedJob::IMMEDIATE)
->filter([
'Implementation' => CheckForUpdatesJob::class
])
Expand All @@ -159,17 +166,55 @@ public function hasPendingJob()
]
]);

return $job->exists();
/** @var QueuedJobDescriptor $runningJob */
$runningJob = QueuedJobDescriptor::get()
->filter([
'Implementation' => CheckForUpdatesJob::class,
'JobStatus' => QueuedJob::STATUS_RUN,
]);

return $immediateJob->exists() || $runningJob->exists();
}

/**
* Handle the refresh, for both the action button and the URL
*/
public function handleRefresh()
{
if (!$this->hasPendingJob()) {
$injector = Injector::inst();
$injector->get(QueuedJobService::class)->queueJob($injector->create(CheckForUpdatesJob::class));
if ($this->hasPendingJob()) {
return;
}

// Queue the job in the immediate queue
$job = Injector::inst()->create(CheckForUpdatesJob::class);
$jobDescriptorId = $this->getQueuedJobService()->queueJob($job, null, null, QueuedJob::IMMEDIATE);

// Check the job descriptor on the queue
$jobDescriptor = QueuedJobDescriptor::get()->filter('ID', $jobDescriptorId)->first();

// If the job is not immediate, change it to immediate and reschedule it to occur immediately
if ($jobDescriptor->JobType !== QueuedJob::IMMEDIATE) {
$jobDescriptor->JobType = QueuedJob::IMMEDIATE;
$jobDescriptor->StartAfter = null;
$jobDescriptor->write();
}
}

/**
* @return QueuedJobService
*/
public function getQueuedJobService()
{
return $this->queuedJobService;
}

/**
* @param QueuedJobService $queuedJobService
* @return $this
*/
public function setQueuedJobService(QueuedJobService $queuedJobService)
{
$this->queuedJobService = $queuedJobService;
return $this;
}
}
45 changes: 45 additions & 0 deletions src/Jobs/CheckForUpdatesJob.php
Expand Up @@ -3,16 +3,36 @@
namespace BringYourOwnIdeas\Maintenance\Jobs;

use BringYourOwnIdeas\Maintenance\Tasks\UpdatePackageInfoTask;
use DateTime;
use SilverStripe\Core\Config\Config;
use SilverStripe\ORM\FieldType\DBDatetime;
use Symbiote\QueuedJobs\Services\QueuedJob;
use SilverStripe\Core\Injector\Injector;
use Symbiote\QueuedJobs\Services\AbstractQueuedJob;
use Symbiote\QueuedJobs\Services\QueuedJobService;

/**
* Refresh report job. Runs as a queued job.
*
*/
class CheckForUpdatesJob extends AbstractQueuedJob implements QueuedJob
{
/**
* Whether or not to reschedule a new job when one completes
*
* @config
* @var bool
*/
private static $reschedule = true;

/**
* The PHP time difference to reschedule a job for after one completes
*
* @config
* @var string
*/
private static $reschedule_delay = '+1 day';

/**
* Define the title
*
Expand Down Expand Up @@ -44,4 +64,29 @@ public function process()
// mark job as completed
$this->isComplete = true;
}

/**
* @inheritdoc
*/
public function afterComplete()
{
// Gather config options
$reschedule = Config::inst()->get(__CLASS__, 'reschedule');
$rescheduleDelay = Config::inst()->get(__CLASS__, 'reschedule_delay');

if ($reschedule === false) {
return;
}

// Queue a new job to run in the future
$injector = Injector::inst();
$queuedJobService = $injector->get(QueuedJobService::class);

$startAfter = new DateTime(DBDatetime::now()->getValue());
$startAfter->modify($rescheduleDelay);
$queuedJobService->queueJob(
$injector->create(CheckForUpdatesJob::class),
$startAfter->format(DateTime::ISO8601)
);
}
}
6 changes: 5 additions & 1 deletion src/Reports/SiteSummary.php
Expand Up @@ -84,9 +84,13 @@ public function getReportField()

$grid->addExtraClass('site-summary');

$summaryFields = Package::create()->summaryFields();
/** @var GridFieldExportButton $exportButton */
$exportButton = $config->getComponentByType(GridFieldExportButton::class);
$exportButton->setExportColumns(Package::create()->summaryFields());
$exportButton->setExportColumns($summaryFields);
/** @var GridFieldPrintButton $printButton */
$printButton = $config->getComponentByType(GridFieldPrintButton::class);
$printButton->setPrintColumns($summaryFields);

$versionHtml = ArrayData::create([
'Title' => _t(__CLASS__ . '.VERSION', 'Version'),
Expand Down
41 changes: 31 additions & 10 deletions tests/Forms/GridFieldRefreshButtonTest.php
Expand Up @@ -4,9 +4,10 @@

use BringYourOwnIdeas\Maintenance\Forms\GridFieldRefreshButton;
use SilverStripe\Core\Config\Config;
use Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\GridField\GridField;
use Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor;
use Symbiote\QueuedJobs\Services\QueuedJobService;

class GridFieldRefreshButtonTest extends SapphireTest
Expand All @@ -20,25 +21,33 @@ protected function setUp()
Config::modify()->set(QueuedJobService::class, 'use_shutdown_function', false);
}

public function testHasRunningJob()
public function testHasRunningJobReturnsTrueWhenJobIsRunning()
{
$button = new GridFieldRefreshButton('test');
$button = $this->getButton();
$this->assertTrue($button->hasPendingJob());
}

public function testHasRunningJobReturnsTrueForPendingJobsOnImmediateQueue()
{
$runningJob = $this->objFromFixture(QueuedJobDescriptor::class, 'runningjob');
$runningJob->JobStatus = 'Complete';
$runningJob->write();
$this->assertTrue($this->getButton()->hasPendingJob());
}

public function testDoesNotHaveCancelledCompletedOrBrokenJob()
{
$this->completeRunningJob();

$button = new GridFieldRefreshButton('test');
$button = $this->getButton();
$this->assertFalse($button->hasPendingJob());
}

public function testHandleRefreshDoesNotCreateJobWhenJobIsRunning()
{
$count = QueuedJobDescriptor::get()->count();

$button = new GridFieldRefreshButton('test');
$button = $this->getButton();
$button->handleRefresh();

$this->assertSame($count, QueuedJobDescriptor::get()->count());
Expand All @@ -50,21 +59,21 @@ public function testHandleRefreshCreatesJobWhenNoJobIsRunning()

$count = QueuedJobDescriptor::get()->count();

$button = new GridFieldRefreshButton('test');
$button = $this->getButton();
$button->handleRefresh();

$this->assertSame($count + 1, QueuedJobDescriptor::get()->count());
}

public function testHandleCheckReturnsValidJson()
{
$button = new GridFieldRefreshButton('test');
$button = $this->getButton();
$this->assertSame('true', $button->handleCheck());
}

public function testButtonIsDisabledWhenJobIsRunning()
{
$button = new GridFieldRefreshButton('test');
$button = $this->getButton();

$gridFieldMock = $this->getGridFieldMock();

Expand All @@ -77,7 +86,7 @@ public function testButtonIsEnabledWhenNoJobIsRunning()
{
$this->completeRunningJob();

$button = new GridFieldRefreshButton('test');
$button = $this->getButton();

$gridFieldMock = $this->getGridFieldMock();

Expand All @@ -94,6 +103,10 @@ protected function completeRunningJob()
$runningJob = $this->objFromFixture(QueuedJobDescriptor::class, 'runningjob');
$runningJob->JobStatus = 'Complete';
$runningJob->write();

$runningJob = $this->objFromFixture(QueuedJobDescriptor::class, 'immediatependingjob');
$runningJob->JobStatus = 'Complete';
$runningJob->write();
}

/**
Expand All @@ -115,4 +128,12 @@ protected function getGridFieldMock()

return $gridFieldMock;
}

/**
* @return GridFieldRefreshButton
*/
protected function getButton()
{
return Injector::inst()->create(GridFieldRefreshButton::class, 'test');
}
}
4 changes: 4 additions & 0 deletions tests/Forms/GridFieldRefreshButtonTest.yml
Expand Up @@ -3,6 +3,10 @@ Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor:
JobStatus: 'Running'
Implementation: 'BringYourOwnIdeas\Maintenance\Jobs\CheckForUpdatesJob'
JobType: 2
immediatependingjob:
JobStatus: 'Pending'
Implementation: 'BringYourOwnIdeas\Maintenance\Jobs\CheckForUpdatesJob'
JobType: 1
brokenjob:
JobStatus: 'Broken'
Implementation: 'BringYourOwnIdeas\Maintenance\Jobs\CheckForUpdatesJob'
Expand Down

0 comments on commit b65673d

Please sign in to comment.