diff --git a/src/applications/nuance/controller/NuanceItemEditController.php b/src/applications/nuance/controller/NuanceItemEditController.php --- a/src/applications/nuance/controller/NuanceItemEditController.php +++ b/src/applications/nuance/controller/NuanceItemEditController.php @@ -3,30 +3,91 @@ final class NuanceItemEditController extends NuanceController { public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); + $viewer = $this->getViewer(); $id = $request->getURIData('id'); - if (!$id) { - $item = new NuanceItem(); - } else { - $item = id(new NuanceItemQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - } - + $item = id(new NuanceItemQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); if (!$item) { return new Aphront404Response(); } + $title = pht('Item %d', $item->getID()); + $crumbs = $this->buildApplicationCrumbs(); - $title = 'TODO'; + $crumbs->addTextCrumb($title); + $crumbs->addTextCrumb(pht('Edit')); + + $properties = $this->buildPropertyView($item); + $actions = $this->buildActionView($item); + $properties->setActionList($actions); + + $box = id(new PHUIObjectBoxView()) + ->setHeaderText($title) + ->addPropertyList($properties); return $this->buildApplicationPage( - $crumbs, + array( + $crumbs, + $box, + ), array( 'title' => $title, )); } + private function buildPropertyView(NuanceItem $item) { + $viewer = $this->getViewer(); + + $properties = id(new PHUIPropertyListView()) + ->setUser($viewer) + ->setObject($item); + + $properties->addProperty( + pht('Date Created'), + phabricator_datetime($item->getDateCreated(), $viewer)); + + $properties->addProperty( + pht('Requestor'), + $viewer->renderHandle($item->getRequestorPHID())); + + $properties->addProperty( + pht('Source'), + $viewer->renderHandle($item->getSourcePHID())); + + $source = $item->getSource(); + $definition = $source->requireDefinition(); + + $definition->renderItemEditProperties( + $viewer, + $item, + $properties); + + return $properties; + } + + private function buildActionView(NuanceItem $item) { + $viewer = $this->getViewer(); + $id = $item->getID(); + + $actions = id(new PhabricatorActionListView()) + ->setUser($viewer); + + $actions->addAction( + id(new PhabricatorActionView()) + ->setName(pht('View Item')) + ->setIcon('fa-eye') + ->setHref($this->getApplicationURI("item/view/{$id}/"))); + + return $actions; + } + + } 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 @@ -3,25 +3,84 @@ final class NuanceItemViewController extends NuanceController { public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); + $viewer = $this->getViewer(); $id = $request->getURIData('id'); $item = id(new NuanceItemQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->executeOne(); - if (!$item) { return new Aphront404Response(); } + $title = pht('Item %d', $item->getID()); + $crumbs = $this->buildApplicationCrumbs(); - $title = 'TODO'; + $crumbs->addTextCrumb($title); + + $properties = $this->buildPropertyView($item); + $actions = $this->buildActionView($item); + $properties->setActionList($actions); + + $box = id(new PHUIObjectBoxView()) + ->setHeaderText($title) + ->addPropertyList($properties); return $this->buildApplicationPage( - $crumbs, + array( + $crumbs, + $box, + ), array( 'title' => $title, )); } + + private function buildPropertyView(NuanceItem $item) { + $viewer = $this->getViewer(); + + $properties = id(new PHUIPropertyListView()) + ->setUser($viewer) + ->setObject($item); + + $properties->addProperty( + pht('Date Created'), + phabricator_datetime($item->getDateCreated(), $viewer)); + + $source = $item->getSource(); + $definition = $source->requireDefinition(); + + $definition->renderItemViewProperties( + $viewer, + $item, + $properties); + + return $properties; + } + + private function buildActionView(NuanceItem $item) { + $viewer = $this->getViewer(); + $id = $item->getID(); + + $actions = id(new PhabricatorActionListView()) + ->setUser($viewer); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $item, + PhabricatorPolicyCapability::CAN_EDIT); + + $actions->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Item')) + ->setIcon('fa-pencil') + ->setHref($this->getApplicationURI("item/edit/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + + return $actions; + } + + } diff --git a/src/applications/nuance/phid/NuanceRequestorPHIDType.php b/src/applications/nuance/phid/NuanceRequestorPHIDType.php --- a/src/applications/nuance/phid/NuanceRequestorPHIDType.php +++ b/src/applications/nuance/phid/NuanceRequestorPHIDType.php @@ -29,7 +29,9 @@ foreach ($handles as $phid => $handle) { $requestor = $objects[$phid]; - $handle->setName($requestor->getBestName()); + // TODO: This is currently useless and should be far more informative. + $handle->setName(pht('Requestor %d', $requestor->getID())); + $handle->setURI($requestor->getURI()); } } diff --git a/src/applications/nuance/query/NuanceItemQuery.php b/src/applications/nuance/query/NuanceItemQuery.php --- a/src/applications/nuance/query/NuanceItemQuery.php +++ b/src/applications/nuance/query/NuanceItemQuery.php @@ -17,25 +17,42 @@ return $this; } - public function withSourcePHIDs($source_phids) { + public function withSourcePHIDs(array $source_phids) { $this->sourcePHIDs = $source_phids; return $this; } + public function newResultObject() { + return new NuanceItem(); + } + protected function loadPage() { - $table = new NuanceItem(); - $conn = $table->establishConnection('r'); - - $data = queryfx_all( - $conn, - '%Q FROM %T %Q %Q %Q', - $this->buildSelectClause($conn), - $table->getTableName(), - $this->buildWhereClause($conn), - $this->buildOrderClause($conn), - $this->buildLimitClause($conn)); - - return $table->loadAllFromArray($data); + return $this->loadStandardPage($this->newResultObject()); + } + + protected function willFilterPage(array $items) { + $source_phids = mpull($items, 'getSourcePHID'); + + // NOTE: We always load sources, even if the viewer can't formally see + // them. If they can see the item, they're allowed to be aware of the + // source in some sense. + $sources = id(new NuanceSourceQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withPHIDs($source_phids) + ->execute(); + $sources = mpull($sources, null, 'getPHID'); + + foreach ($items as $key => $item) { + $source = idx($sources, $item->getSourcePHID()); + if (!$source) { + $this->didRejectResult($items[$key]); + unset($items[$key]); + continue; + } + $item->attachSource($source); + } + + return $items; } protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { diff --git a/src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php b/src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php --- a/src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php +++ b/src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php @@ -61,7 +61,7 @@ if ($request->isFormPost()) { $properties = array( - 'complaint' => (string)$request->getStr('text'), + 'complaint' => (string)$request->getStr('complaint'), ); $content_source = PhabricatorContentSource::newFromRequest($request); @@ -100,4 +100,33 @@ return $box; } + public function renderItemViewProperties( + PhabricatorUser $viewer, + NuanceItem $item, + PHUIPropertyListView $view) { + $this->renderItemCommonProperties($viewer, $item, $view); + } + + public function renderItemEditProperties( + PhabricatorUser $viewer, + NuanceItem $item, + PHUIPropertyListView $view) { + $this->renderItemCommonProperties($viewer, $item, $view); + } + + private function renderItemCommonProperties( + PhabricatorUser $viewer, + NuanceItem $item, + PHUIPropertyListView $view) { + + $complaint = $item->getNuanceProperty('complaint'); + $complaint = PhabricatorMarkupEngine::renderOneObject( + id(new PhabricatorMarkupOneOff())->setContent($complaint), + 'default', + $viewer); + + $view->addSectionHeader(pht('Complaint')); + $view->addTextContent($complaint); + } + } diff --git a/src/applications/nuance/source/NuanceSourceDefinition.php b/src/applications/nuance/source/NuanceSourceDefinition.php --- a/src/applications/nuance/source/NuanceSourceDefinition.php +++ b/src/applications/nuance/source/NuanceSourceDefinition.php @@ -268,6 +268,20 @@ return $item; } + public function renderItemViewProperties( + PhabricatorUser $viewer, + NuanceItem $item, + PHUIPropertyListView $view) { + return; + } + + public function renderItemEditProperties( + PhabricatorUser $viewer, + NuanceItem $item, + PHUIPropertyListView $view) { + return; + } + /* -( Handling Action Requests )------------------------------------------- */ 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 @@ -19,6 +19,8 @@ protected $mailKey; protected $dateNuanced; + private $source = self::ATTACHABLE; + public static function initializeNewItem() { return id(new NuanceItem()) ->setDateNuanced(time())