Page MenuHomePhabricator

D18010.diff
No OneTemporary

D18010.diff

diff --git a/resources/sql/autopatches/20170524.nuance.01.command.sql b/resources/sql/autopatches/20170524.nuance.01.command.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20170524.nuance.01.command.sql
@@ -0,0 +1,8 @@
+ALTER TABLE {$NAMESPACE}_nuance.nuance_itemcommand
+ ADD dateCreated INT UNSIGNED NOT NULL;
+
+ALTER TABLE {$NAMESPACE}_nuance.nuance_itemcommand
+ ADD dateModified INT UNSIGNED NOT NULL;
+
+ALTER TABLE {$NAMESPACE}_nuance.nuance_itemcommand
+ ADD queuePHID VARBINARY(64);
diff --git a/resources/sql/autopatches/20170524.nuance.02.commandstatus.sql b/resources/sql/autopatches/20170524.nuance.02.commandstatus.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20170524.nuance.02.commandstatus.sql
@@ -0,0 +1,5 @@
+ALTER TABLE {$NAMESPACE}_nuance.nuance_itemcommand
+ ADD status VARCHAR(64) NOT NULL;
+
+UPDATE {$NAMESPACE}_nuance.nuance_itemcommand
+ SET status = 'done' WHERE status = '';
diff --git a/src/applications/nuance/application/PhabricatorNuanceApplication.php b/src/applications/nuance/application/PhabricatorNuanceApplication.php
--- a/src/applications/nuance/application/PhabricatorNuanceApplication.php
+++ b/src/applications/nuance/application/PhabricatorNuanceApplication.php
@@ -52,6 +52,8 @@
$this->getEditRoutePattern('edit/') => 'NuanceQueueEditController',
'view/(?P<id>[1-9]\d*)/' => 'NuanceQueueViewController',
'work/(?P<id>[1-9]\d*)/' => 'NuanceQueueWorkController',
+ 'action/(?P<queueID>[1-9]\d*)/(?P<action>[^/]+)/(?P<id>[1-9]\d*)/'
+ => 'NuanceItemActionController',
),
),
'/action/' => array(
diff --git a/src/applications/nuance/controller/NuanceItemActionController.php b/src/applications/nuance/controller/NuanceItemActionController.php
--- a/src/applications/nuance/controller/NuanceItemActionController.php
+++ b/src/applications/nuance/controller/NuanceItemActionController.php
@@ -6,6 +6,14 @@
$viewer = $this->getViewer();
$id = $request->getURIData('id');
+ if (!$request->validateCSRF()) {
+ return new Aphront400Response();
+ }
+
+ // NOTE: This controller can be reached from an individual item (usually
+ // by a user) or while working through a queue (usually by staff). When
+ // a command originates from a queue, the URI will have a queue ID.
+
$item = id(new NuanceItemQuery())
->setViewer($viewer)
->withIDs(array($id))
@@ -14,13 +22,69 @@
return new Aphront404Response();
}
+ $cancel_uri = $item->getURI();
+
+ $queue_id = $request->getURIData('queueID');
+ $queue = null;
+ if ($queue_id) {
+ $queue = id(new NuanceQueueQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($queue_id))
+ ->executeOne();
+ if (!$queue) {
+ return new Aphront404Response();
+ }
+
+ $item_queue = $item->getQueue();
+ if (!$item_queue || ($item_queue->getPHID() != $queue->getPHID())) {
+ return $this->newDialog()
+ ->setTitle(pht('Wrong Queue'))
+ ->appendParagraph(
+ pht(
+ 'You are trying to act on this item from the wrong queue: it '.
+ 'is currently in a different queue.'))
+ ->addCancelButton($cancel_uri);
+ }
+ }
+
$action = $request->getURIData('action');
$impl = $item->getImplementation();
$impl->setViewer($viewer);
$impl->setController($this);
- return $impl->buildActionResponse($item, $action);
+ $command = NuanceItemCommand::initializeNewCommand()
+ ->setItemPHID($item->getPHID())
+ ->setAuthorPHID($viewer->getPHID())
+ ->setCommand($action);
+
+ if ($queue) {
+ $command->setQueuePHID($queue->getPHID());
+ }
+
+ $command->save();
+
+ // TODO: Here, we should check if the command should be tried immediately,
+ // and just defer it to the daemons if not. If we're going to try to apply
+ // the command directly, we should first acquire the worker lock. If we
+ // can not, we should defer the command even if it's an immediate command.
+ // For the moment, skip all this stuff by deferring unconditionally.
+
+ $should_defer = true;
+ if ($should_defer) {
+ $item->scheduleUpdate();
+ } else {
+ // ...
+ }
+
+ if ($queue) {
+ $done_uri = $queue->getWorkURI();
+ } else {
+ $done_uri = $item->getURI();
+ }
+
+ return id(new AphrontRedirectResponse())
+ ->setURI($done_uri);
}
}
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,14 +26,12 @@
$curtain = $this->buildCurtain($item);
$content = $this->buildContent($item);
- $commands = $this->buildCommands($item);
$timeline = $this->buildTransactionTimeline(
$item,
new NuanceItemTransactionQuery());
$main = array(
- $commands,
$content,
$timeline,
);
@@ -91,36 +89,4 @@
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/controller/NuanceQueueWorkController.php b/src/applications/nuance/controller/NuanceQueueWorkController.php
--- a/src/applications/nuance/controller/NuanceQueueWorkController.php
+++ b/src/applications/nuance/controller/NuanceQueueWorkController.php
@@ -64,12 +64,14 @@
$impl = $item->getImplementation()
->setViewer($viewer);
+ $commands = $this->buildCommands($item);
$work_content = $impl->buildItemWorkView($item);
$view = id(new PHUITwoColumnView())
->setCurtain($curtain)
->setMainColumn(
array(
+ $commands,
$work_content,
$timeline,
));
@@ -94,12 +96,15 @@
$item_id = $item->getID();
+ $action_uri = "queue/action/{$id}/{$command_key}/{$item_id}/";
+ $action_uri = $this->getApplicationURI($action_uri);
+
$curtain->addAction(
id(new PhabricatorActionView())
->setName($command->getName())
->setIcon($command->getIcon())
- ->setHref("queue/command/{$id}/{$command_key}/{$item_id}/"))
- ->setWorkflow(true);
+ ->setHref($action_uri)
+ ->setWorkflow(true));
}
$curtain->addAction(
@@ -120,4 +125,62 @@
return $curtain;
}
+ private function buildCommands(NuanceItem $item) {
+ $viewer = $this->getViewer();
+
+ $commands = id(new NuanceItemCommandQuery())
+ ->setViewer($viewer)
+ ->withItemPHIDs(array($item->getPHID()))
+ ->withStatuses(
+ array(
+ NuanceItemCommand::STATUS_ISSUED,
+ NuanceItemCommand::STATUS_EXECUTING,
+ NuanceItemCommand::STATUS_FAILED,
+ ))
+ ->execute();
+ $commands = msort($commands, 'getID');
+
+ if (!$commands) {
+ return null;
+ }
+
+ $rows = array();
+ foreach ($commands as $command) {
+ $icon = $command->getStatusIcon();
+ $color = $command->getStatusColor();
+
+ $rows[] = array(
+ $command->getID(),
+ id(new PHUIIconView())
+ ->setIcon($icon, $color),
+ $viewer->renderHandle($command->getAuthorPHID()),
+ $command->getCommand(),
+ phabricator_datetime($command->getDateCreated(), $viewer),
+ );
+ }
+
+ $table = id(new AphrontTableView($rows))
+ ->setHeaders(
+ array(
+ pht('ID'),
+ null,
+ pht('Actor'),
+ pht('Command'),
+ pht('Date'),
+ ))
+ ->setColumnClasses(
+ array(
+ null,
+ 'icon',
+ null,
+ 'pri',
+ 'wide right',
+ ));
+
+ return id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Pending Commands'))
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->setTable($table);
+ }
+
}
diff --git a/src/applications/nuance/item/NuanceFormItemType.php b/src/applications/nuance/item/NuanceFormItemType.php
--- a/src/applications/nuance/item/NuanceFormItemType.php
+++ b/src/applications/nuance/item/NuanceFormItemType.php
@@ -47,4 +47,8 @@
);
}
+ protected function handleAction(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
@@ -95,13 +95,7 @@
}
final public function buildActionResponse(NuanceItem $item, $action) {
- $response = $this->handleAction($item, $action);
-
- if ($response === null) {
- return new Aphront404Response();
- }
-
- return $response;
+ return $this->handleAction($item, $action);
}
protected function handleAction(NuanceItem $item, $action) {
diff --git a/src/applications/nuance/query/NuanceItemCommandQuery.php b/src/applications/nuance/query/NuanceItemCommandQuery.php
--- a/src/applications/nuance/query/NuanceItemCommandQuery.php
+++ b/src/applications/nuance/query/NuanceItemCommandQuery.php
@@ -5,6 +5,7 @@
private $ids;
private $itemPHIDs;
+ private $statuses;
public function withIDs(array $ids) {
$this->ids = $ids;
@@ -16,6 +17,11 @@
return $this;
}
+ public function withStatuses(array $statuses) {
+ $this->statuses = $statuses;
+ return $this;
+ }
+
public function newResultObject() {
return new NuanceItemCommand();
}
@@ -41,6 +47,13 @@
$this->itemPHIDs);
}
+ if ($this->statuses !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'status IN (%Ls)',
+ $this->statuses);
+ }
+
return $where;
}
diff --git a/src/applications/nuance/storage/NuanceItemCommand.php b/src/applications/nuance/storage/NuanceItemCommand.php
--- a/src/applications/nuance/storage/NuanceItemCommand.php
+++ b/src/applications/nuance/storage/NuanceItemCommand.php
@@ -4,32 +4,86 @@
extends NuanceDAO
implements PhabricatorPolicyInterface {
+ const STATUS_ISSUED = 'issued';
+ const STATUS_EXECUTING = 'executing';
+ const STATUS_DONE = 'done';
+ const STATUS_FAILED = 'failed';
+
protected $itemPHID;
protected $authorPHID;
+ protected $queuePHID;
protected $command;
- protected $parameters;
+ protected $status;
+ protected $parameters = array();
public static function initializeNewCommand() {
- return new self();
+ return id(new self())
+ ->setStatus(self::STATUS_ISSUED);
}
protected function getConfiguration() {
return array(
- self::CONFIG_TIMESTAMPS => false,
self::CONFIG_SERIALIZATION => array(
'parameters' => self::SERIALIZATION_JSON,
),
self::CONFIG_COLUMN_SCHEMA => array(
'command' => 'text64',
+ 'status' => 'text64',
+ 'queuePHID' => 'phid?',
),
self::CONFIG_KEY_SCHEMA => array(
- 'key_item' => array(
- 'columns' => array('itemPHID'),
+ 'key_pending' => array(
+ 'columns' => array('itemPHID', 'status'),
),
),
) + parent::getConfiguration();
}
+ public static function getStatusMap() {
+ return array(
+ self::STATUS_ISSUED => array(
+ 'name' => pht('Issued'),
+ 'icon' => 'fa-clock-o',
+ 'color' => 'bluegrey',
+ ),
+ self::STATUS_EXECUTING => array(
+ 'name' => pht('Executing'),
+ 'icon' => 'fa-play',
+ 'color' => 'green',
+ ),
+ self::STATUS_DONE => array(
+ 'name' => pht('Done'),
+ 'icon' => 'fa-check',
+ 'color' => 'blue',
+ ),
+ self::STATUS_FAILED => array(
+ 'name' => pht('Failed'),
+ 'icon' => 'fa-times',
+ 'color' => 'red',
+ ),
+ );
+ }
+
+ private function getStatusSpec() {
+ $map = self::getStatusMap();
+ return idx($map, $this->getStatus(), array());
+ }
+
+ public function getStatusIcon() {
+ $spec = $this->getStatusSpec();
+ return idx($spec, 'icon', 'fa-question');
+ }
+
+ public function getStatusColor() {
+ $spec = $this->getStatusSpec();
+ return idx($spec, 'color', 'indigo');
+ }
+
+ public function getStatusName() {
+ $spec = $this->getStatusSpec();
+ return idx($spec, 'name', $this->getStatus());
+ }
+
/* -( PhabricatorPolicyInterface )----------------------------------------- */
diff --git a/src/applications/nuance/storage/NuanceQueue.php b/src/applications/nuance/storage/NuanceQueue.php
--- a/src/applications/nuance/storage/NuanceQueue.php
+++ b/src/applications/nuance/storage/NuanceQueue.php
@@ -43,6 +43,10 @@
return '/nuance/queue/view/'.$this->getID().'/';
}
+ public function getWorkURI() {
+ return '/nuance/queue/work/'.$this->getID().'/';
+ }
+
/* -( PhabricatorPolicyInterface )----------------------------------------- */
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
@@ -61,12 +61,31 @@
$commands = id(new NuanceItemCommandQuery())
->setViewer($viewer)
->withItemPHIDs(array($item->getPHID()))
+ ->withStatuses(
+ array(
+ NuanceItemCommand::STATUS_ISSUED,
+ ))
->execute();
$commands = msort($commands, 'getID');
foreach ($commands as $command) {
- $impl->applyCommand($item, $command);
- $command->delete();
+ $command
+ ->setStatus(NuanceItemCommand::STATUS_EXECUTING)
+ ->save();
+
+ try {
+ $impl->applyCommand($item, $command);
+
+ $command
+ ->setStatus(NuanceItemCommand::STATUS_DONE)
+ ->save();
+ } catch (Exception $ex) {
+ $command
+ ->setStatus(NuanceItemCommand::STATUS_FAILED)
+ ->save();
+
+ throw $ex;
+ }
}
}

File Metadata

Mime Type
text/plain
Expires
Mon, Nov 4, 1:03 AM (2 w, 1 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6710154
Default Alt Text
D18010.diff (14 KB)

Event Timeline