Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15382139
D15506.id37377.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Referenced Files
None
Subscribers
None
D15506.id37377.diff
View Options
diff --git a/resources/sql/autopatches/20160322.nuance.01.itemcommand.sql b/resources/sql/autopatches/20160322.nuance.01.itemcommand.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20160322.nuance.01.itemcommand.sql
@@ -0,0 +1,8 @@
+CREATE TABLE {$NAMESPACE}_nuance.nuance_itemcommand (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ itemPHID VARBINARY(64) NOT NULL,
+ authorPHID VARBINARY(64) NOT NULL,
+ command VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT},
+ parameters LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
+ KEY `key_item` (itemPHID)
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
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
@@ -1437,6 +1437,8 @@
'NuanceImportCursorPHIDType' => 'applications/nuance/phid/NuanceImportCursorPHIDType.php',
'NuanceItem' => 'applications/nuance/storage/NuanceItem.php',
'NuanceItemActionController' => 'applications/nuance/controller/NuanceItemActionController.php',
+ 'NuanceItemCommand' => 'applications/nuance/storage/NuanceItemCommand.php',
+ 'NuanceItemCommandQuery' => 'applications/nuance/query/NuanceItemCommandQuery.php',
'NuanceItemController' => 'applications/nuance/controller/NuanceItemController.php',
'NuanceItemEditor' => 'applications/nuance/editor/NuanceItemEditor.php',
'NuanceItemListController' => 'applications/nuance/controller/NuanceItemListController.php',
@@ -5721,6 +5723,11 @@
'PhabricatorApplicationTransactionInterface',
),
'NuanceItemActionController' => 'NuanceController',
+ 'NuanceItemCommand' => array(
+ 'NuanceDAO',
+ 'PhabricatorPolicyInterface',
+ ),
+ 'NuanceItemCommandQuery' => 'NuanceQuery',
'NuanceItemController' => 'NuanceController',
'NuanceItemEditor' => 'PhabricatorApplicationTransactionEditor',
'NuanceItemListController' => 'NuanceItemController',
diff --git a/src/applications/nuance/controller/NuanceItemViewController.php b/src/applications/nuance/controller/NuanceItemViewController.php
--- a/src/applications/nuance/controller/NuanceItemViewController.php
+++ b/src/applications/nuance/controller/NuanceItemViewController.php
@@ -26,6 +26,17 @@
$curtain = $this->buildCurtain($item);
$content = $this->buildContent($item);
+ $commands = $this->buildCommands($item);
+
+ $timeline = $this->buildTransactionTimeline(
+ $item,
+ new NuanceItemTransactionQuery());
+
+ $main = array(
+ $commands,
+ $content,
+ $timeline,
+ );
$header = id(new PHUIHeaderView())
->setHeader($name);
@@ -33,7 +44,7 @@
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
- ->setMainColumn($content);
+ ->setMainColumn($main);
return $this->newPage()
->setTitle($title)
@@ -76,4 +87,36 @@
return $impl->buildItemView($item);
}
+ private function buildCommands(NuanceItem $item) {
+ $viewer = $this->getViewer();
+
+ $commands = id(new NuanceItemCommandQuery())
+ ->setViewer($viewer)
+ ->withItemPHIDs(array($item->getPHID()))
+ ->execute();
+ $commands = msort($commands, 'getID');
+
+ if (!$commands) {
+ return null;
+ }
+
+ $rows = array();
+ foreach ($commands as $command) {
+ $rows[] = array(
+ $command->getCommand(),
+ );
+ }
+
+ $table = id(new AphrontTableView($rows))
+ ->setHeaders(
+ array(
+ pht('Command'),
+ ));
+
+ return id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Pending Commands'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->setTable($table);
+ }
+
}
diff --git a/src/applications/nuance/editor/NuanceItemEditor.php b/src/applications/nuance/editor/NuanceItemEditor.php
--- a/src/applications/nuance/editor/NuanceItemEditor.php
+++ b/src/applications/nuance/editor/NuanceItemEditor.php
@@ -19,6 +19,7 @@
$types[] = NuanceItemTransaction::TYPE_REQUESTOR;
$types[] = NuanceItemTransaction::TYPE_PROPERTY;
$types[] = NuanceItemTransaction::TYPE_QUEUE;
+ $types[] = NuanceItemTransaction::TYPE_COMMAND;
$types[] = PhabricatorTransactions::TYPE_EDGE;
$types[] = PhabricatorTransactions::TYPE_COMMENT;
@@ -45,6 +46,8 @@
$key = $xaction->getMetadataValue(
NuanceItemTransaction::PROPERTY_KEY);
return $object->getNuanceProperty($key);
+ case NuanceItemTransaction::TYPE_COMMAND:
+ return null;
}
return parent::getCustomTransactionOldValue($object, $xaction);
@@ -60,6 +63,7 @@
case NuanceItemTransaction::TYPE_OWNER:
case NuanceItemTransaction::TYPE_PROPERTY:
case NuanceItemTransaction::TYPE_QUEUE:
+ case NuanceItemTransaction::TYPE_COMMAND:
return $xaction->getNewValue();
}
@@ -88,6 +92,8 @@
NuanceItemTransaction::PROPERTY_KEY);
$object->setNuanceProperty($key, $xaction->getNewValue());
break;
+ case NuanceItemTransaction::TYPE_COMMAND:
+ break;
}
}
@@ -101,6 +107,7 @@
case NuanceItemTransaction::TYPE_OWNER:
case NuanceItemTransaction::TYPE_PROPERTY:
case NuanceItemTransaction::TYPE_QUEUE:
+ case NuanceItemTransaction::TYPE_COMMAND:
return;
}
diff --git a/src/applications/nuance/item/NuanceGitHubEventItemType.php b/src/applications/nuance/item/NuanceGitHubEventItemType.php
--- a/src/applications/nuance/item/NuanceGitHubEventItemType.php
+++ b/src/applications/nuance/item/NuanceGitHubEventItemType.php
@@ -147,6 +147,12 @@
public function getItemActions(NuanceItem $item) {
$actions = array();
+ $actions[] = $this->newItemAction($item, 'sync')
+ ->setName(pht('Import to Maniphest'))
+ ->setIcon('fa-anchor')
+ ->setWorkflow(true)
+ ->setRenderAsForm(true);
+
$actions[] = $this->newItemAction($item, 'raw')
->setName(pht('View Raw Event'))
->setWorkflow(true)
@@ -156,6 +162,7 @@
}
protected function handleAction(NuanceItem $item, $action) {
+ $viewer = $this->getViewer();
$controller = $this->getController();
switch ($action) {
@@ -181,6 +188,9 @@
->setTitle(pht('GitHub Raw Event'))
->appendForm($form)
->addCancelButton($item->getURI(), pht('Done'));
+ case 'sync':
+ $item->issueCommand($viewer->getPHID(), $action);
+ return id(new AphrontRedirectResponse())->setURI($item->getURI());
}
return null;
@@ -228,5 +238,9 @@
->appendChild($property_list);
}
+ protected function handleCommand(NuanceItem $item, $action) {
+ return null;
+ }
+
}
diff --git a/src/applications/nuance/item/NuanceItemType.php b/src/applications/nuance/item/NuanceItemType.php
--- a/src/applications/nuance/item/NuanceItemType.php
+++ b/src/applications/nuance/item/NuanceItemType.php
@@ -96,4 +96,43 @@
return null;
}
+ final public function applyCommand(
+ NuanceItem $item,
+ NuanceItemCommand $command) {
+
+ $result = $this->handleCommand($item, $command);
+
+ if ($result === null) {
+ return;
+ }
+
+ $xaction = id(new NuanceItemTransaction())
+ ->setTransactionType(NuanceItemTransaction::TYPE_COMMAND)
+ ->setNewValue(
+ array(
+ 'command' => $command->getCommand(),
+ 'parameters' => $command->getParameters(),
+ 'result' => $result,
+ ));
+
+ $viewer = $this->getViewer();
+
+ // TODO: Maybe preserve the actor's original content source?
+ $source = PhabricatorContentSource::newForSource(
+ PhabricatorContentSource::SOURCE_DAEMON,
+ array());
+
+ $editor = id(new NuanceItemEditor())
+ ->setActor($viewer)
+ ->setActingAsPHID($command->getAuthorPHID())
+ ->setContentSource($source)
+ ->setContinueOnMissingFields(true)
+ ->setContinueOnNoEffect(true)
+ ->applyTransactions($item, array($xaction));
+ }
+
+ protected function handleCommand(NuanceItem $item, $action) {
+ return null;
+ }
+
}
diff --git a/src/applications/nuance/query/NuanceItemCommandQuery.php b/src/applications/nuance/query/NuanceItemCommandQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/nuance/query/NuanceItemCommandQuery.php
@@ -0,0 +1,47 @@
+<?php
+
+final class NuanceItemCommandQuery
+ extends NuanceQuery {
+
+ private $ids;
+ private $itemPHIDs;
+
+ public function withIDs(array $ids) {
+ $this->ids = $ids;
+ return $this;
+ }
+
+ public function withItemPHIDs(array $item_phids) {
+ $this->itemPHIDs = $item_phids;
+ return $this;
+ }
+
+ public function newResultObject() {
+ return new NuanceItemCommand();
+ }
+
+ protected function loadPage() {
+ return $this->loadStandardPage($this->newResultObject());
+ }
+
+ protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
+ $where = parent::buildWhereClauseParts($conn);
+
+ if ($this->ids !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'id IN (%Ld)',
+ $this->ids);
+ }
+
+ if ($this->itemPHIDs !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'itemPHID IN (%Ls)',
+ $this->itemPHIDs);
+ }
+
+ return $where;
+ }
+
+}
diff --git a/src/applications/nuance/storage/NuanceItem.php b/src/applications/nuance/storage/NuanceItem.php
--- a/src/applications/nuance/storage/NuanceItem.php
+++ b/src/applications/nuance/storage/NuanceItem.php
@@ -154,6 +154,23 @@
));
}
+ public function issueCommand(
+ $author_phid,
+ $command,
+ array $parameters = array()) {
+
+ $command = id(NuanceItemCommand::initializeNewCommand())
+ ->setItemPHID($this->getPHID())
+ ->setAuthorPHID($author_phid)
+ ->setCommand($command)
+ ->setParameters($parameters)
+ ->save();
+
+ $this->scheduleUpdate();
+
+ return $this;
+ }
+
public function getImplementation() {
return $this->assertAttached($this->implementation);
}
diff --git a/src/applications/nuance/storage/NuanceItemCommand.php b/src/applications/nuance/storage/NuanceItemCommand.php
new file mode 100644
--- /dev/null
+++ b/src/applications/nuance/storage/NuanceItemCommand.php
@@ -0,0 +1,55 @@
+<?php
+
+final class NuanceItemCommand
+ extends NuanceDAO
+ implements PhabricatorPolicyInterface {
+
+ protected $itemPHID;
+ protected $authorPHID;
+ protected $command;
+ protected $parameters;
+
+ public static function initializeNewCommand() {
+ return new self();
+ }
+
+ protected function getConfiguration() {
+ return array(
+ self::CONFIG_TIMESTAMPS => false,
+ self::CONFIG_SERIALIZATION => array(
+ 'parameters' => self::SERIALIZATION_JSON,
+ ),
+ self::CONFIG_COLUMN_SCHEMA => array(
+ 'command' => 'text64',
+ ),
+ self::CONFIG_KEY_SCHEMA => array(
+ 'key_item' => array(
+ 'columns' => array('itemPHID'),
+ ),
+ ),
+ ) + parent::getConfiguration();
+ }
+
+
+/* -( PhabricatorPolicyInterface )----------------------------------------- */
+
+
+ public function getCapabilities() {
+ return array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ );
+ }
+
+ public function getPolicy($capability) {
+ return PhabricatorPolicies::getMostOpenPolicy();
+ }
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ return false;
+ }
+
+ public function describeAutomaticCapability($capability) {
+ return null;
+ }
+
+}
diff --git a/src/applications/nuance/storage/NuanceItemTransaction.php b/src/applications/nuance/storage/NuanceItemTransaction.php
--- a/src/applications/nuance/storage/NuanceItemTransaction.php
+++ b/src/applications/nuance/storage/NuanceItemTransaction.php
@@ -10,6 +10,7 @@
const TYPE_SOURCE = 'nuance.item.source';
const TYPE_PROPERTY = 'nuance.item.property';
const TYPE_QUEUE = 'nuance.item.queue';
+ const TYPE_COMMAND = 'nuance.item.command';
public function getApplicationTransactionType() {
return NuanceItemPHIDType::TYPECONST;
@@ -65,6 +66,12 @@
'%s routed this item to the %s queue.',
$this->renderHandleLink($author_phid),
$this->renderHandleLink($new));
+ case self::TYPE_COMMAND:
+ // TODO: Give item types a chance to render this properly.
+ return pht(
+ '%s applied command "%s" to this item.',
+ $this->renderHandleLink($author_phid),
+ idx($new, 'command'));
}
return parent::getTitle();
diff --git a/src/applications/nuance/worker/NuanceItemUpdateWorker.php b/src/applications/nuance/worker/NuanceItemUpdateWorker.php
--- a/src/applications/nuance/worker/NuanceItemUpdateWorker.php
+++ b/src/applications/nuance/worker/NuanceItemUpdateWorker.php
@@ -15,6 +15,7 @@
$item = $this->loadItem($item_phid);
$this->updateItem($item);
$this->routeItem($item);
+ $this->applyCommands($item);
} catch (Exception $ex) {
$lock->unlock();
throw $ex;
@@ -51,4 +52,22 @@
->save();
}
+ private function applyCommands(NuanceItem $item) {
+ $viewer = $this->getViewer();
+
+ $impl = $item->getImplementation();
+ $impl->setViewer($viewer);
+
+ $commands = id(new NuanceItemCommandQuery())
+ ->setViewer($viewer)
+ ->withItemPHIDs(array($item->getPHID()))
+ ->execute();
+ $commands = msort($commands, 'getID');
+
+ foreach ($commands as $command) {
+ $impl->applyCommand($item, $command);
+ $command->delete();
+ }
+ }
+
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mar 15 2025, 10:53 AM (4 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7690942
Default Alt Text
D15506.id37377.diff (13 KB)
Attached To
Mode
D15506: Add an ItemCommand queue to Nuance
Attached
Detach File
Event Timeline
Log In to Comment