diff --git a/src/applications/drydock/controller/DrydockLeaseViewController.php b/src/applications/drydock/controller/DrydockLeaseViewController.php index 4739dfdbcf..0cf2070a57 100644 --- a/src/applications/drydock/controller/DrydockLeaseViewController.php +++ b/src/applications/drydock/controller/DrydockLeaseViewController.php @@ -1,134 +1,135 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $lease = id(new DrydockLease())->load($this->id); if (!$lease) { return new Aphront404Response(); } $lease_uri = $this->getApplicationURI('lease/'.$lease->getID().'/'); $title = pht('Lease %d', $lease->getID()); $header = id(new PHUIHeaderView()) ->setHeader($title); $actions = $this->buildActionListView($lease); $properties = $this->buildPropertyListView($lease, $actions); $pager = new AphrontPagerView(); $pager->setURI(new PhutilURI($lease_uri), 'offset'); $pager->setOffset($request->getInt('offset')); $logs = id(new DrydockLogQuery()) + ->setViewer($user) ->withLeaseIDs(array($lease->getID())) ->executeWithOffsetPager($pager); $log_table = $this->buildLogTableView($logs); $log_table->appendChild($pager); $crumbs = $this->buildApplicationCrumbs(); $crumbs->setActionList($actions); $crumbs->addTextCrumb($title, $lease_uri); $object_box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addPropertyList($properties); return $this->buildApplicationPage( array( $crumbs, $object_box, $log_table, ), array( 'device' => true, 'title' => $title, )); } private function buildActionListView(DrydockLease $lease) { $view = id(new PhabricatorActionListView()) ->setUser($this->getRequest()->getUser()) ->setObjectURI($this->getRequest()->getRequestURI()) ->setObject($lease); $id = $lease->getID(); $can_release = ($lease->getStatus() == DrydockLeaseStatus::STATUS_ACTIVE); $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Release Lease')) ->setIcon('delete') ->setHref($this->getApplicationURI("/lease/{$id}/release/")) ->setWorkflow(true) ->setDisabled(!$can_release)); return $view; } private function buildPropertyListView( DrydockLease $lease, PhabricatorActionListView $actions) { $view = new PHUIPropertyListView(); $view->setActionList($actions); switch ($lease->getStatus()) { case DrydockLeaseStatus::STATUS_ACTIVE: $status = pht('Active'); break; case DrydockLeaseStatus::STATUS_RELEASED: $status = pht('Released'); break; case DrydockLeaseStatus::STATUS_EXPIRED: $status = pht('Expired'); break; case DrydockLeaseStatus::STATUS_PENDING: $status = pht('Pending'); break; case DrydockLeaseStatus::STATUS_BROKEN: $status = pht('Broken'); break; default: $status = pht('Unknown'); break; } $view->addProperty( pht('Status'), $status); $view->addProperty( pht('Resource Type'), $lease->getResourceType()); $view->addProperty( pht('Resource'), $lease->getResourceID()); $attributes = $lease->getAttributes(); if ($attributes) { $view->addSectionHeader(pht('Attributes')); foreach ($attributes as $key => $value) { $view->addProperty($key, $value); } } return $view; } } diff --git a/src/applications/drydock/controller/DrydockLogController.php b/src/applications/drydock/controller/DrydockLogController.php index 73907468b9..f17bfa816e 100644 --- a/src/applications/drydock/controller/DrydockLogController.php +++ b/src/applications/drydock/controller/DrydockLogController.php @@ -1,58 +1,59 @@ getRequest(); $user = $request->getUser(); $nav = $this->buildSideNav('log'); - $query = new DrydockLogQuery(); + $query = id(new DrydockLogQuery()) + ->setViewer($user); $resource_ids = $request->getStrList('resource'); if ($resource_ids) { $query->withResourceIDs($resource_ids); } $lease_ids = $request->getStrList('lease'); if ($lease_ids) { $query->withLeaseIDs($lease_ids); } $pager = new AphrontPagerView(); $pager->setPageSize(500); $pager->setOffset($request->getInt('offset')); $pager->setURI($request->getRequestURI(), 'offset'); $logs = $query->executeWithOffsetPager($pager); $title = pht('Logs'); $header = id(new PHUIHeaderView()) ->setHeader($title); $table = $this->buildLogTableView($logs); $table->appendChild($pager); $nav->appendChild( array( $header, $table, $pager, )); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title, $this->getApplicationURI('/logs/')); $nav->setCrumbs($crumbs); return $this->buildApplicationPage( $nav, array( 'title' => $title, 'device' => true, )); } } diff --git a/src/applications/drydock/controller/DrydockResourceViewController.php b/src/applications/drydock/controller/DrydockResourceViewController.php index 459d0160bf..3ca8df39c1 100644 --- a/src/applications/drydock/controller/DrydockResourceViewController.php +++ b/src/applications/drydock/controller/DrydockResourceViewController.php @@ -1,127 +1,128 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $resource = id(new DrydockResource())->load($this->id); if (!$resource) { return new Aphront404Response(); } $title = 'Resource '.$resource->getID().' '.$resource->getName(); $header = id(new PHUIHeaderView()) ->setHeader($title); $actions = $this->buildActionListView($resource); $properties = $this->buildPropertyListView($resource, $actions); $resource_uri = 'resource/'.$resource->getID().'/'; $resource_uri = $this->getApplicationURI($resource_uri); $leases = id(new DrydockLeaseQuery()) ->setViewer($user) ->withResourceIDs(array($resource->getID())) ->execute(); $lease_list = $this->buildLeaseListView($leases); $lease_list->setNoDataString(pht('This resource has no leases.')); $pager = new AphrontPagerView(); $pager->setURI(new PhutilURI($resource_uri), 'offset'); $pager->setOffset($request->getInt('offset')); $logs = id(new DrydockLogQuery()) + ->setViewer($user) ->withResourceIDs(array($resource->getID())) ->executeWithOffsetPager($pager); $log_table = $this->buildLogTableView($logs); $log_table->appendChild($pager); $crumbs = $this->buildApplicationCrumbs(); $crumbs->setActionList($actions); $crumbs->addTextCrumb(pht('Resource %d', $resource->getID())); $object_box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addPropertyList($properties); return $this->buildApplicationPage( array( $crumbs, $object_box, $lease_list, $log_table, ), array( 'device' => true, 'title' => $title, )); } private function buildActionListView(DrydockResource $resource) { $view = id(new PhabricatorActionListView()) ->setUser($this->getRequest()->getUser()) ->setObjectURI($this->getRequest()->getRequestURI()) ->setObject($resource); $can_close = ($resource->getStatus() == DrydockResourceStatus::STATUS_OPEN); $uri = '/resource/'.$resource->getID().'/close/'; $uri = $this->getApplicationURI($uri); $view->addAction( id(new PhabricatorActionView()) ->setHref($uri) ->setName(pht('Close Resource')) ->setIcon('delete') ->setWorkflow(true) ->setDisabled(!$can_close)); return $view; } private function buildPropertyListView( DrydockResource $resource, PhabricatorActionListView $actions) { $view = new PHUIPropertyListView(); $view->setActionList($actions); $status = $resource->getStatus(); $status = DrydockResourceStatus::getNameForStatus($status); $view->addProperty( pht('Status'), $status); $view->addProperty( pht('Resource Type'), $resource->getType()); // TODO: Load handle. $view->addProperty( pht('Blueprint'), $resource->getBlueprintPHID()); $attributes = $resource->getAttributes(); if ($attributes) { $view->addSectionHeader(pht('Attributes')); foreach ($attributes as $key => $value) { $view->addProperty($key, $value); } } return $view; } } diff --git a/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php b/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php index 9df072d88e..b8f6b583a6 100644 --- a/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php +++ b/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php @@ -1,79 +1,78 @@ setName('lease') ->setSynopsis('Lease a resource.') ->setArguments( array( array( 'name' => 'type', 'param' => 'resource_type', 'help' => 'Resource type.', ), array( 'name' => 'attributes', 'param' => 'name=value,...', 'help' => 'Resource specficiation.', ), )); } public function execute(PhutilArgumentParser $args) { $console = PhutilConsole::getConsole(); $resource_type = $args->getArg('type'); if (!$resource_type) { throw new PhutilArgumentUsageException( "Specify a resource type with `--type`."); } $attributes = $args->getArg('attributes'); if ($attributes) { $options = new PhutilSimpleOptions(); $options->setCaseSensitive(true); $attributes = $options->parse($attributes); } $lease = new DrydockLease(); $lease->setResourceType($resource_type); if ($attributes) { $lease->setAttributes($attributes); } $lease->queueForActivation(); $root = dirname(phutil_get_library_root('phabricator')); $wait = new ExecFuture( 'php -f %s wait-for-lease --id %s', $root.'/scripts/drydock/drydock_control.php', $lease->getID()); $cursor = 0; foreach (Futures(array($wait))->setUpdateInterval(1) as $key => $future) { if ($future) { $future->resolvex(); break; } $logs = id(new DrydockLogQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withLeaseIDs(array($lease->getID())) - ->withAfterID($cursor) - ->setOrder(DrydockLogQuery::ORDER_ID) ->execute(); if ($logs) { foreach ($logs as $log) { $console->writeErr("%s\n", $log->getMessage()); } $cursor = max(mpull($logs, 'getID')); } } $console->writeOut("Acquired Lease %s\n", $lease->getID()); return 0; } } diff --git a/src/applications/drydock/query/DrydockLogQuery.php b/src/applications/drydock/query/DrydockLogQuery.php index cc9f8abee9..16ed479868 100644 --- a/src/applications/drydock/query/DrydockLogQuery.php +++ b/src/applications/drydock/query/DrydockLogQuery.php @@ -1,86 +1,79 @@ resourceIDs = $ids; return $this; } public function withLeaseIDs(array $ids) { $this->leaseIDs = $ids; return $this; } - public function setOrder($order) { - $this->order = $order; - return $this; - } - - public function withAfterID($id) { - $this->afterID = $id; - return $this; - } - - public function execute() { + public function loadPage() { $table = new DrydockLog(); $conn_r = $table->establishConnection('r'); $data = queryfx_all( $conn_r, 'SELECT log.* FROM %T log %Q %Q %Q', $table->getTableName(), $this->buildWhereClause($conn_r), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r)); return $table->loadAllFromArray($data); } + public function willFilterPage(array $logs) { + $resource_ids = mpull($logs, 'getResourceID'); + $resources = id(new DrydockResourceQuery()) + ->setParentQuery($this) + ->setViewer($this->getViewer()) + ->withIDs($resource_ids) + ->execute(); + + foreach ($logs as $key => $log) { + $resource = idx($resources, $log->getResourceID()); + if (!$resource) { + unset($logs[$key]); + continue; + } + $log->attachResource($resource); + } + + return $logs; + } + private function buildWhereClause(AphrontDatabaseConnection $conn_r) { $where = array(); if ($this->resourceIDs) { $where[] = qsprintf( $conn_r, 'resourceID IN (%Ld)', $this->resourceIDs); } if ($this->leaseIDs) { $where[] = qsprintf( $conn_r, 'leaseID IN (%Ld)', $this->leaseIDs); } - if ($this->afterID) { - $where[] = qsprintf( - $conn_r, - 'id > %d', - $this->afterID); - } + $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); } - private function buildOrderClause(AphrontDatabaseConnection $conn_r) { - switch ($this->order) { - case self::ORDER_EPOCH: - return 'ORDER BY log.epoch DESC, log.id DESC'; - case self::ORDER_ID: - return 'ORDER BY id ASC'; - default: - throw new Exception("Unknown order '{$this->order}'!"); - } + public function getQueryApplicationClass() { + return 'PhabricatorApplicationDrydock'; } } diff --git a/src/applications/drydock/storage/DrydockLog.php b/src/applications/drydock/storage/DrydockLog.php index a26e593300..41f34a744c 100644 --- a/src/applications/drydock/storage/DrydockLog.php +++ b/src/applications/drydock/storage/DrydockLog.php @@ -1,16 +1,50 @@ false, ) + parent::getConfiguration(); } + public function attachResource(DrydockResource $resource) { + $this->resource = $resource; + return $this; + } + + public function getResource() { + return $this->assertAttached($this->resource); + } + + +/* -( PhabricatorPolicyInterface )----------------------------------------- */ + + + public function getCapabilities() { + return array( + PhabricatorPolicyCapability::CAN_VIEW, + ); + } + + public function getPolicy($capability) { + return $this->getResource()->getPolicy($capability); + } + + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + return $this->getResource()->hasAutomaticCapability($capability, $viewer); + } + + public function describeAutomaticCapability($capability) { + return pht('Logs inherit the policy of their resources.'); + } + }