Skip to content
Snippets Groups Projects
Commit f36dbcb9 authored by megachriz's avatar megachriz Committed by Megachriz
Browse files

Issue #2868134 by MegaChriz: Show next time that the source will be imported.

parent 3f06cb6d
No related branches found
No related tags found
No related merge requests found
......@@ -301,6 +301,7 @@ function feeds_source_status($source) {
}
$v['imported'] = $source->imported;
$v['count'] = $source->itemCount();
$v['next'] = $source->getNextImportTimeDetails();
if (!empty($v)) {
return theme('feeds_source_status', $v);
}
......@@ -331,6 +332,32 @@ function theme_feeds_source_status($v) {
$items[] = t('No imported items.');
}
}
if ($v['next']) {
// Check if medium date format contains hours/minutes.
$date_format = variable_get('date_format_medium');
$use_custom_date_format = $date_format && !strpos($date_format, 'H:i');
if (!empty($v['next']['message'])) {
$items[] = t('Next import: @message.', array(
'@message' => $v['next']['message'],
));
}
elseif ($v['next']['time'] > REQUEST_TIME) {
$items[] = t('Next import: @date (via @method)', array(
'@date' => $use_custom_date_format ? format_date($v['next']['time'], 'custom', 'Y/m/d H:i:s') : format_date($v['next']['time']),
'@method' => $v['next']['method'],
));
}
else {
$items[] = t('Next import: on next cron run (via @method).', array(
'@method' => $v['next']['method'],
));
}
}
else {
$items[] = t('Next import: not scheduled.');
}
$output .= theme('item_list', array('items' => $items));
$output .= '</div>';
return $output;
......
......@@ -665,6 +665,131 @@ class FeedsSource extends FeedsConfigurable {
return $this->importer->processor->itemCount($this);
}
/**
* Returns the next time that the feed will be imported.
*
* @return int|null
* The next time the feed will be imported as a UNIX timestamp.
* NULL if not known.
*/
public function getNextImportTime() {
$details = $this->getNextImportTimeDetails();
if (isset($details['time'])) {
return $details['time'];
}
}
/**
* Returns the next time that the feed will be imported.
*
* @return array|null
* Information about when the next time the feed will be imported:
* - time: the next time the feed will be imported as a UNIX timestamp.
* - method: via which scheduler the job will ran.
* - message: If set, time and method should be ignored.
* Null if no information is available.
*/
public function getNextImportTimeDetails() {
// Check queue.
$serialized_job_type = db_like(strtr('s:4:"type";s:!length:"!type";', array(
'!length' => strlen($this->id),
'!type' => $this->id,
)));
$serialized_job_id_as_string = db_like(strtr('s:2:"id";s:!length:"!id";', array(
'!length' => strlen($this->feed_nid),
'!id' => $this->feed_nid,
)));
$serialized_job_id_as_integer = db_like(strtr('s:2:"id";i:!id;', array(
'!id' => $this->feed_nid,
)));
$queue_created = db_select('queue')
->fields('queue', array('created'))
->condition('name', 'feeds_source_import')
->condition('data', '%' . $serialized_job_type . '%', 'LIKE')
->condition(db_or()
->condition('data', '%' . $serialized_job_id_as_string . '%', 'LIKE')
->condition('data', '%' . $serialized_job_id_as_integer . '%', 'LIKE')
)
->condition('expire', 0)
->execute()
->fetchField();
if ($queue_created) {
return array(
'time' => $queue_created,
'method' => t('Queue'),
);
}
// Special case for PostgreSQL: if using that database type, we cannot
// search in the data column of the queue table, because the Drupal database
// layer adds '::text' to bytea columns, which results into the data column
// becoming unreadable in conditions. So instead, we check for the first 10
// records in the queue to see if the given importer ID + feed NID is
// amongst them.
if (Database::getConnection()->databaseType() == 'pgsql') {
$items = db_query("SELECT data, created FROM {queue} WHERE name = :name AND expire = 0 LIMIT 10", array(
':name' => 'feeds_source_import',
));
foreach ($items as $item) {
if (is_string($item->data)) {
$item->data = unserialize($item->data);
}
if ($item->data['type'] == $this->id && $item->data['id'] == $this->feed_nid) {
return array(
'time' => $item->created,
'method' => t('Queue'),
);
}
}
// If not found by now, count how many items there are in the
// feeds_source_import queue. We use this number later to indicate that
// the job *could* be in the queue.
$number_of_queue_items = db_query('SELECT COUNT(name) FROM {queue} WHERE name = :name AND expire = 0', array(
':name' => 'feeds_source_import',
))->fetchField();
}
// Check if the importer is in the process of being rescheduled.
$importers = feeds_reschedule();
if (isset($importers[$this->id])) {
return array(
'time' => NULL,
'method' => NULL,
'message' => t('to be rescheduled'),
);
}
// Check job scheduler.
$job = db_select('job_schedule')
->fields('job_schedule', array('next', 'scheduled'))
->condition('name', 'feeds_source_import')
->condition('type', $this->id)
->condition('id', $this->feed_nid)
->execute()
->fetch();
if (isset($job->next)) {
$details = array(
'time' => $job->next,
'method' => t('Job scheduler'),
);
if (!empty($job->scheduled)) {
if (isset($number_of_queue_items) && $number_of_queue_items > 10) {
// When using PostgreSQL we were not able to efficiently search the
// queue table, so it could still be in that table.
$details['message'] = t('unknown, could still be in the queue');
}
else {
$details['message'] = t('possibly stuck');
}
}
return $details;
}
}
/**
* Unlocks a feed.
*/
......
......@@ -210,6 +210,107 @@ class FeedsSchedulerTestCase extends FeedsWebTestCase {
)));
}
/**
* Tests if the expected next import time is shown for scheduled imports.
*/
public function testNextImportTime() {
$this->initSyndication();
$this->drupalLogin($this->admin_user);
// Set schedule to be 25 minutes in the future.
$next = REQUEST_TIME + 1500;
db_query("UPDATE {job_schedule} SET next = :time", array(
':time' => $next,
));
$this->drupalGet('node/1/import');
$this->assertText(format_date($next));
// Set schedule to import on next cron run.
db_query("UPDATE {job_schedule} SET next = :time", array(
':time' => REQUEST_TIME,
));
$this->drupalGet('node/1/import');
$this->assertText('Next import: on next cron run');
// Now remove all jobs.
db_truncate('job_schedule')->execute();
// Assert that the import is not scheduled now.
$this->drupalGet('node/1/import');
$this->assertText('Next import: not scheduled');
}
/**
* Tests if the expected next import time is shown when the import is queued
* via background job.
*/
public function testNextImportTimeWhenQueuedViaBackgroundJob() {
// Create an importer that uses a background job to import.
$this->createImporterConfiguration('Node import', 'node');
$edit = array(
'content_type' => '',
'import_on_create' => TRUE,
'process_in_background' => TRUE,
);
$this->drupalPost('admin/structure/feeds/node/settings', $edit, 'Save');
$this->setPlugin('node', 'FeedsFileFetcher');
$this->setPlugin('node', 'FeedsCSVParser');
$mappings = array(
0 => array(
'source' => 'title',
'target' => 'title',
),
);
$this->addMappings('node', $mappings);
// Specify a file with many nodes.
$this->importFile('node', $this->absolutePath() . '/tests/feeds/many_nodes.csv');
// Verify that a queue item is created.
$count = db_query("SELECT COUNT(*) FROM {queue} WHERE name = 'feeds_source_import'")->fetchField();
$this->assertEqual(1, $count, format_string('One import item is queued (actual: @count).', array(
'@count' => $count,
)));
// The page should say that import happens on next cron.
$this->assertText('Next import: on next cron run');
}
/**
* Tests if the expected next import time is shown when the import is queued
* via Job Scheduler.
*/
public function testNextImportTimeWhenQueuedViaJobScheduler() {
$this->initSyndication();
$this->drupalLogin($this->admin_user);
// Manually dispatch a job.
$job = db_select('job_schedule', NULL, array('fetch' => PDO::FETCH_ASSOC))
->fields('job_schedule')
->condition('type', 'syndication')
->condition('id', 18)
->execute()
->fetch();
try {
JobScheduler::get($job['name'])->dispatch($job);
$this->pass('No exceptions occurred while dispatching a feeds job.');
}
catch (Exception $e) {
watchdog_exception('feeds', $e);
$this->fail('No exceptions occurred while dispatching a feeds job.');
}
// Verify that a queue item is created.
$count = db_query("SELECT COUNT(*) FROM {queue} WHERE name = 'feeds_source_import'")->fetchField();
$this->assertEqual(1, $count, format_string('One import item is queued (actual: @count).', array(
'@count' => $count,
)));
// The page should say that import happens on next cron.
$this->drupalGet('node/18/import');
$this->assertText('Next import: on next cron run');
}
/**
* Test batching on cron.
*/
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment