Page MenuHomePhabricator

D16752.diff
No OneTemporary

D16752.diff

diff --git a/resources/sql/autopatches/20161026.calendar.01.importtriggers.sql b/resources/sql/autopatches/20161026.calendar.01.importtriggers.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20161026.calendar.01.importtriggers.sql
@@ -0,0 +1,8 @@
+ALTER TABLE {$NAMESPACE}_calendar.calendar_import
+ ADD triggerPHID VARBINARY(64);
+
+ALTER TABLE {$NAMESPACE}_calendar.calendar_import
+ ADD triggerFrequency VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT};
+
+UPDATE {$NAMESPACE}_calendar.calendar_import
+ SET triggerFrequency = 'once' WHERE triggerFrequency = '';
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2121,6 +2121,7 @@
'PhabricatorCalendarImportEpochLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportEpochLogType.php',
'PhabricatorCalendarImportFetchLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportFetchLogType.php',
'PhabricatorCalendarImportFrequencyLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportFrequencyLogType.php',
+ 'PhabricatorCalendarImportFrequencyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportFrequencyTransaction.php',
'PhabricatorCalendarImportICSFileTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php',
'PhabricatorCalendarImportICSLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportICSLogType.php',
'PhabricatorCalendarImportICSURITransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportICSURITransaction.php',
@@ -2139,10 +2140,12 @@
'PhabricatorCalendarImportQuery' => 'applications/calendar/query/PhabricatorCalendarImportQuery.php',
'PhabricatorCalendarImportReloadController' => 'applications/calendar/controller/PhabricatorCalendarImportReloadController.php',
'PhabricatorCalendarImportReloadTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportReloadTransaction.php',
+ 'PhabricatorCalendarImportReloadWorker' => 'applications/calendar/worker/PhabricatorCalendarImportReloadWorker.php',
'PhabricatorCalendarImportSearchEngine' => 'applications/calendar/query/PhabricatorCalendarImportSearchEngine.php',
'PhabricatorCalendarImportTransaction' => 'applications/calendar/storage/PhabricatorCalendarImportTransaction.php',
'PhabricatorCalendarImportTransactionQuery' => 'applications/calendar/query/PhabricatorCalendarImportTransactionQuery.php',
'PhabricatorCalendarImportTransactionType' => 'applications/calendar/xaction/PhabricatorCalendarImportTransactionType.php',
+ 'PhabricatorCalendarImportTriggerLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportTriggerLogType.php',
'PhabricatorCalendarImportUpdateLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportUpdateLogType.php',
'PhabricatorCalendarImportViewController' => 'applications/calendar/controller/PhabricatorCalendarImportViewController.php',
'PhabricatorCalendarRemarkupRule' => 'applications/calendar/remarkup/PhabricatorCalendarRemarkupRule.php',
@@ -6964,6 +6967,7 @@
'PhabricatorCalendarImportEpochLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportFetchLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportFrequencyLogType' => 'PhabricatorCalendarImportLogType',
+ 'PhabricatorCalendarImportFrequencyTransaction' => 'PhabricatorCalendarImportTransactionType',
'PhabricatorCalendarImportICSFileTransaction' => 'PhabricatorCalendarImportTransactionType',
'PhabricatorCalendarImportICSLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportICSURITransaction' => 'PhabricatorCalendarImportTransactionType',
@@ -6986,10 +6990,12 @@
'PhabricatorCalendarImportQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorCalendarImportReloadController' => 'PhabricatorCalendarController',
'PhabricatorCalendarImportReloadTransaction' => 'PhabricatorCalendarImportTransactionType',
+ 'PhabricatorCalendarImportReloadWorker' => 'PhabricatorWorker',
'PhabricatorCalendarImportSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorCalendarImportTransaction' => 'PhabricatorModularTransaction',
'PhabricatorCalendarImportTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorCalendarImportTransactionType' => 'PhabricatorModularTransactionType',
+ 'PhabricatorCalendarImportTriggerLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportUpdateLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportViewController' => 'PhabricatorCalendarController',
'PhabricatorCalendarRemarkupRule' => 'PhabricatorObjectRemarkupRule',
diff --git a/src/applications/calendar/controller/PhabricatorCalendarImportDropController.php b/src/applications/calendar/controller/PhabricatorCalendarImportDropController.php
--- a/src/applications/calendar/controller/PhabricatorCalendarImportDropController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarImportDropController.php
@@ -33,7 +33,7 @@
->addCancelButton($cancel_uri, pht('Done'));
}
- $engine = new PhabricatorCalendarICSImportEngine();
+ $engine = new PhabricatorCalendarICSFileImportEngine();
$imports = array();
foreach ($files as $file) {
$import = PhabricatorCalendarImport::initializeNewCalendarImport(
diff --git a/src/applications/calendar/controller/PhabricatorCalendarImportViewController.php b/src/applications/calendar/controller/PhabricatorCalendarImportViewController.php
--- a/src/applications/calendar/controller/PhabricatorCalendarImportViewController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarImportViewController.php
@@ -167,6 +167,50 @@
pht('Source Type'),
$engine->getImportEngineTypeName());
+ if ($import->getIsDisabled()) {
+ $auto_updates = phutil_tag('em', array(), pht('Import Disabled'));
+ $has_trigger = false;
+ } else {
+ $frequency = $import->getTriggerFrequency();
+ $frequency_map = PhabricatorCalendarImport::getTriggerFrequencyMap();
+ $frequency_names = ipull($frequency_map, 'name');
+ $auto_updates = idx($frequency_names, $frequency, $frequency);
+
+ if ($frequency == PhabricatorCalendarImport::FREQUENCY_ONCE) {
+ $has_trigger = false;
+ $auto_updates = phutil_tag('em', array(), $auto_updates);
+ } else {
+ $has_trigger = true;
+ }
+ }
+
+ $properties->addProperty(
+ pht('Automatic Updates'),
+ $auto_updates);
+
+ if ($has_trigger) {
+ $trigger = id(new PhabricatorWorkerTriggerQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($import->getTriggerPHID()))
+ ->needEvents(true)
+ ->executeOne();
+
+ if (!$trigger) {
+ $next_trigger = phutil_tag('em', array(), pht('Invalid Trigger'));
+ } else {
+ $now = PhabricatorTime::getNow();
+ $next_epoch = $trigger->getNextEventPrediction();
+ $next_trigger = pht(
+ '%s (%s)',
+ phabricator_datetime($next_epoch, $viewer),
+ phutil_format_relative_time($next_epoch - $now));
+ }
+
+ $properties->addProperty(
+ pht('Next Update'),
+ $next_trigger);
+ }
+
$engine->appendImportProperties(
$viewer,
$import,
diff --git a/src/applications/calendar/editor/PhabricatorCalendarImportEditEngine.php b/src/applications/calendar/editor/PhabricatorCalendarImportEditEngine.php
--- a/src/applications/calendar/editor/PhabricatorCalendarImportEditEngine.php
+++ b/src/applications/calendar/editor/PhabricatorCalendarImportEditEngine.php
@@ -80,6 +80,9 @@
protected function buildCustomEditFields($object) {
$viewer = $this->getViewer();
+ $engine = $object->getEngine();
+ $can_trigger = $engine->supportsTriggers($object);
+
$fields = array(
id(new PhabricatorTextEditField())
->setKey('name')
@@ -89,6 +92,7 @@
PhabricatorCalendarImportNameTransaction::TRANSACTIONTYPE)
->setConduitDescription(pht('Rename the import.'))
->setConduitTypeDescription(pht('New import name.'))
+ ->setPlaceholder($object->getDisplayName())
->setValue($object->getName()),
id(new PhabricatorBoolEditField())
->setKey('disabled')
@@ -123,6 +127,22 @@
->setValue(false),
);
+ if ($can_trigger) {
+ $frequency_map = PhabricatorCalendarImport::getTriggerFrequencyMap();
+ $frequency_options = ipull($frequency_map, 'name');
+
+ $fields[] = id(new PhabricatorSelectEditField())
+ ->setKey('frequency')
+ ->setLabel(pht('Update Automatically'))
+ ->setDescription(pht('Configure an automatic update frequncy.'))
+ ->setTransactionType(
+ PhabricatorCalendarImportFrequencyTransaction::TRANSACTIONTYPE)
+ ->setConduitDescription(pht('Set the automatic update frequency.'))
+ ->setConduitTypeDescription(pht('Update frequency constant.'))
+ ->setValue($object->getTriggerFrequency())
+ ->setOptions($frequency_options);
+ }
+
$import_engine = $object->getEngine();
foreach ($import_engine->newEditEngineFields($this, $object) as $field) {
$fields[] = $field;
diff --git a/src/applications/calendar/editor/PhabricatorCalendarImportEditor.php b/src/applications/calendar/editor/PhabricatorCalendarImportEditor.php
--- a/src/applications/calendar/editor/PhabricatorCalendarImportEditor.php
+++ b/src/applications/calendar/editor/PhabricatorCalendarImportEditor.php
@@ -27,26 +27,112 @@
protected function applyFinalEffects(
PhabricatorLiskDAO $object,
array $xactions) {
-
- $type_reload = PhabricatorCalendarImportReloadTransaction::TRANSACTIONTYPE;
+ $actor = $this->getActor();
// We import events when you create a source, or if you later reload it
// explicitly.
$should_reload = $this->getIsNewObject();
+
+ // We adjust the import trigger if you change the import frequency or
+ // disable the import.
+ $should_trigger = false;
+
foreach ($xactions as $xaction) {
- if ($xaction->getTransactionType() == $type_reload) {
- $should_reload = true;
- break;
+ $xaction_type = $xaction->getTransactionType();
+ switch ($xaction_type) {
+ case PhabricatorCalendarImportReloadTransaction::TRANSACTIONTYPE:
+ $should_reload = true;
+ break;
+ case PhabricatorCalendarImportFrequencyTransaction::TRANSACTIONTYPE:
+ $should_trigger = true;
+ break;
+ case PhabricatorCalendarImportDisableTransaction::TRANSACTIONTYPE:
+ $should_trigger = true;
+ break;
}
}
if ($should_reload) {
- $actor = $this->getActor();
-
$import_engine = $object->getEngine();
$import_engine->importEventsFromSource($actor, $object);
}
+ if ($should_trigger) {
+ $trigger_phid = $object->getTriggerPHID();
+ if ($trigger_phid) {
+ $trigger = id(new PhabricatorWorkerTriggerQuery())
+ ->setViewer($actor)
+ ->withPHIDs(array($trigger_phid))
+ ->executeOne();
+
+ if ($trigger) {
+ $engine = new PhabricatorDestructionEngine();
+ $engine->destroyObject($trigger);
+ }
+ }
+
+ $frequency = $object->getTriggerFrequency();
+ $now = PhabricatorTime::getNow();
+ switch ($frequency) {
+ case PhabricatorCalendarImport::FREQUENCY_ONCE:
+ $clock = null;
+ break;
+ case PhabricatorCalendarImport::FREQUENCY_HOURLY:
+ $clock = new PhabricatorMetronomicTriggerClock(
+ array(
+ 'period' => phutil_units('1 hour in seconds'),
+ ));
+ break;
+ case PhabricatorCalendarImport::FREQUENCY_DAILY:
+ $clock = new PhabricatorDailyRoutineTriggerClock(
+ array(
+ 'start' => $now,
+ ));
+ break;
+ default:
+ throw new Exception(
+ pht(
+ 'Unknown import trigger frequency "%s".',
+ $frequency));
+ }
+
+ // If the object has been disabled, don't write a new trigger.
+ if ($object->getIsDisabled()) {
+ $clock = null;
+ }
+
+ if ($clock) {
+ $trigger_action = new PhabricatorScheduleTaskTriggerAction(
+ array(
+ 'class' => 'PhabricatorCalendarImportReloadWorker',
+ 'data' => array(
+ 'importPHID' => $object->getPHID(),
+ ),
+ 'options' => array(
+ 'objectPHID' => $object->getPHID(),
+ 'priority' => PhabricatorWorker::PRIORITY_BULK,
+ ),
+ ));
+
+ $trigger_phid = PhabricatorPHID::generateNewPHID(
+ PhabricatorWorkerTriggerPHIDType::TYPECONST);
+
+ $object
+ ->setTriggerPHID($trigger_phid)
+ ->save();
+
+ $trigger = id(new PhabricatorWorkerTrigger())
+ ->setClock($clock)
+ ->setAction($trigger_action)
+ ->setPHID($trigger_phid)
+ ->save();
+ } else {
+ $object
+ ->setTriggerPHID(null)
+ ->save();
+ }
+ }
+
return $xactions;
}
diff --git a/src/applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php b/src/applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php
--- a/src/applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php
+++ b/src/applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php
@@ -17,6 +17,10 @@
return pht('Import an event in ".ics" (iCalendar) format.');
}
+ public function supportsTriggers(PhabricatorCalendarImport $import) {
+ return false;
+ }
+
public function appendImportProperties(
PhabricatorUser $viewer,
PhabricatorCalendarImport $import,
diff --git a/src/applications/calendar/import/PhabricatorCalendarICSURIImportEngine.php b/src/applications/calendar/import/PhabricatorCalendarICSURIImportEngine.php
--- a/src/applications/calendar/import/PhabricatorCalendarICSURIImportEngine.php
+++ b/src/applications/calendar/import/PhabricatorCalendarICSURIImportEngine.php
@@ -17,6 +17,10 @@
return pht('Import or subscribe to a calendar in .ics format by URI.');
}
+ public function supportsTriggers(PhabricatorCalendarImport $import) {
+ return true;
+ }
+
public function appendImportProperties(
PhabricatorUser $viewer,
PhabricatorCalendarImport $import,
diff --git a/src/applications/calendar/import/PhabricatorCalendarImportEngine.php b/src/applications/calendar/import/PhabricatorCalendarImportEngine.php
--- a/src/applications/calendar/import/PhabricatorCalendarImportEngine.php
+++ b/src/applications/calendar/import/PhabricatorCalendarImportEngine.php
@@ -39,6 +39,9 @@
throw new PhutilMethodNotImplementedException();
}
+ abstract public function supportsTriggers(
+ PhabricatorCalendarImport $import);
+
final public static function getAllImportEngines() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
diff --git a/src/applications/calendar/importlog/PhabricatorCalendarImportTriggerLogType.php b/src/applications/calendar/importlog/PhabricatorCalendarImportTriggerLogType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/calendar/importlog/PhabricatorCalendarImportTriggerLogType.php
@@ -0,0 +1,32 @@
+<?php
+
+final class PhabricatorCalendarImportTriggerLogType
+ extends PhabricatorCalendarImportLogType {
+
+ const LOGTYPE = 'trigger';
+
+ public function getDisplayType(
+ PhabricatorUser $viewer,
+ PhabricatorCalendarImportLog $log) {
+ return pht('Import Triggered');
+ }
+
+ public function getDisplayDescription(
+ PhabricatorUser $viewer,
+ PhabricatorCalendarImportLog $log) {
+ return pht('Triggered a periodic update.');
+ }
+
+ public function getDisplayIcon(
+ PhabricatorUser $viewer,
+ PhabricatorCalendarImportLog $log) {
+ return 'fa-clock-o';
+ }
+
+ public function getDisplayColor(
+ PhabricatorUser $viewer,
+ PhabricatorCalendarImportLog $log) {
+ return 'blue';
+ }
+
+}
diff --git a/src/applications/calendar/storage/PhabricatorCalendarImport.php b/src/applications/calendar/storage/PhabricatorCalendarImport.php
--- a/src/applications/calendar/storage/PhabricatorCalendarImport.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarImport.php
@@ -14,6 +14,12 @@
protected $engineType;
protected $parameters = array();
protected $isDisabled = 0;
+ protected $triggerPHID;
+ protected $triggerFrequency;
+
+ const FREQUENCY_ONCE = 'once';
+ const FREQUENCY_HOURLY = 'hourly';
+ const FREQUENCY_DAILY = 'daily';
private $engine = self::ATTACHABLE;
@@ -27,7 +33,8 @@
->setEditPolicy($actor->getPHID())
->setIsDisabled(0)
->setEngineType($engine->getImportEngineType())
- ->attachEngine($engine);
+ ->attachEngine($engine)
+ ->setTriggerFrequency(self::FREQUENCY_ONCE);
}
protected function getConfiguration() {
@@ -40,6 +47,8 @@
'name' => 'text',
'engineType' => 'text64',
'isDisabled' => 'bool',
+ 'triggerPHID' => 'phid?',
+ 'triggerFrequency' => 'text64',
),
self::CONFIG_KEY_SCHEMA => array(
'key_author' => array(
@@ -85,6 +94,21 @@
return $this->getEngine()->getDisplayName($this);
}
+ public static function getTriggerFrequencyMap() {
+ return array(
+ self::FREQUENCY_ONCE => array(
+ 'name' => pht('No Automatic Updates'),
+ ),
+ self::FREQUENCY_HOURLY => array(
+ 'name' => pht('Update Hourly'),
+ ),
+ self::FREQUENCY_DAILY => array(
+ 'name' => pht('Update Daily'),
+ ),
+ );
+ }
+
+
/* -( PhabricatorPolicyInterface )----------------------------------------- */
@@ -155,6 +179,17 @@
$this->openTransaction();
+ $trigger_phid = $this->getTriggerPHID();
+ if ($trigger_phid) {
+ $trigger = id(new PhabricatorWorkerTriggerQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($trigger_phid))
+ ->executeOne();
+ if ($trigger) {
+ $engine->destroyObject($trigger);
+ }
+ }
+
$events = id(new PhabricatorCalendarEventQuery())
->setViewer($viewer)
->withImportSourcePHIDs(array($this->getPHID()))
diff --git a/src/applications/calendar/worker/PhabricatorCalendarImportReloadWorker.php b/src/applications/calendar/worker/PhabricatorCalendarImportReloadWorker.php
new file mode 100644
--- /dev/null
+++ b/src/applications/calendar/worker/PhabricatorCalendarImportReloadWorker.php
@@ -0,0 +1,48 @@
+<?php
+
+final class PhabricatorCalendarImportReloadWorker extends PhabricatorWorker {
+
+ protected function doWork() {
+ $import = $this->loadImport();
+ $viewer = PhabricatorUser::getOmnipotentUser();
+
+ if ($import->getIsDisabled()) {
+ return;
+ }
+
+ $author = id(new PhabricatorPeopleQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($import->getAuthorPHID()))
+ ->needUserSettings(true)
+ ->executeOne();
+
+ $import_engine = $import->getEngine();
+
+ $import->newLogMessage(
+ PhabricatorCalendarImportTriggerLogType::LOGTYPE,
+ array());
+
+ $import_engine->importEventsFromSource($author, $import);
+ }
+
+ private function loadImport() {
+ $viewer = PhabricatorUser::getOmnipotentUser();
+
+ $data = $this->getTaskData();
+ $import_phid = idx($data, 'importPHID');
+
+ $import = id(new PhabricatorCalendarImportQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($import_phid))
+ ->executeOne();
+ if (!$import) {
+ throw new PhabricatorWorkerPermanentFailureException(
+ pht(
+ 'Failed to load import with PHID "%s".',
+ $import_phid));
+ }
+
+ return $import;
+ }
+
+}
diff --git a/src/applications/calendar/xaction/PhabricatorCalendarImportFrequencyTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarImportFrequencyTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/calendar/xaction/PhabricatorCalendarImportFrequencyTransaction.php
@@ -0,0 +1,45 @@
+<?php
+
+final class PhabricatorCalendarImportFrequencyTransaction
+ extends PhabricatorCalendarImportTransactionType {
+
+ const TRANSACTIONTYPE = 'calendar.import.frequency';
+
+ public function generateOldValue($object) {
+ return $object->getTriggerFrequency();
+ }
+
+ public function applyInternalEffects($object, $value) {
+ $object->setTriggerFrequency($value);
+ }
+
+ public function getTitle() {
+ return pht(
+ '%s changed the automatic update frequency for this import.',
+ $this->renderAuthor());
+ }
+
+ public function validateTransactions($object, array $xactions) {
+ $errors = array();
+
+ $frequency_map = PhabricatorCalendarImport::getTriggerFrequencyMap();
+ $valid = array_keys($frequency_map);
+ $valid = array_fuse($valid);
+
+ foreach ($xactions as $xaction) {
+ $value = $xaction->getNewValue();
+
+ if (!isset($valid[$value])) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Import frequency "%s" is not valid. Valid frequences are: %s.',
+ $value,
+ implode(', ', $valid)),
+ $xaction);
+ }
+ }
+
+ return $errors;
+ }
+
+}

File Metadata

Mime Type
text/plain
Expires
Wed, Dec 18, 9:56 PM (14 h, 19 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6904566
Default Alt Text
D16752.diff (21 KB)

Event Timeline