Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14305900
D16752.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
21 KB
Referenced Files
None
Subscribers
None
D16752.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D16752: Allow Calendar imports to be configured with hourly or daily auto-updates
Attached
Detach File
Event Timeline
Log In to Comment