From 2ef5b5321d1fec56e5f33fc91858df92d6fe083c Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 1 Oct 2015 08:06:23 -0700 Subject: [PATCH] Move Drydock logs to PHIDs and increased structure Summary: Ref T9252. Several general changes here: - Moves logs to use PHIDs instead of IDs. This generally improves flexibility (for example, it's a lot easier to render handles). - Adds `blueprintPHID` to logs. Although you can usually figure this out from the leasePHID or resourcePHID, it lets us query relevant logs on Blueprint views. - Instead of making logs a top-level object, make them strictly a sub-object of Blueprints, Resources and Leases. So you go Drydock > Lease > Logs, etc., to get to logs. - I might restore the "everything" view eventually, but it doesn't interact well with policies and I'm not sure it's very useful. A policy-violating `bin/drydock log` might be cleaner. - Policy-wise, we always show you that logs exist, we just don't show you log content if it's about something you can't see. This is similar to seeing restricted handles in other applications. - Instead of just having a message, give logs "type" + "data". This will let logs be more structured and translatable. This is similar to recent changes to Herald which seem to have worked well. Test Plan: Added some placeholder log writes, viewed those logs in the UI. {F855199} Reviewers: chad Reviewed By: chad Maniphest Tasks: T9252 Differential Revision: https://secure.phabricator.com/D14196 --- .../autopatches/20150930.drydock.log.1.sql | 25 ++++ .../PhabricatorDrydockApplication.php | 15 +- .../DrydockBlueprintImplementation.php | 40 ----- .../DrydockBlueprintViewController.php | 8 + .../drydock/controller/DrydockController.php | 27 ++++ .../controller/DrydockLeaseViewController.php | 25 +--- .../controller/DrydockLogController.php | 104 ++++++++++++- .../controller/DrydockLogListController.php | 48 +++++- .../DrydockResourceViewController.php | 26 +--- .../drydock/query/DrydockLogQuery.php | 127 ++++++++-------- .../drydock/query/DrydockLogSearchEngine.php | 137 ++++++++++-------- .../drydock/storage/DrydockLease.php | 21 +++ .../drydock/storage/DrydockLog.php | 71 ++++++--- .../drydock/view/DrydockLogListView.php | 66 +++++---- 14 files changed, 488 insertions(+), 252 deletions(-) create mode 100644 resources/sql/autopatches/20150930.drydock.log.1.sql diff --git a/resources/sql/autopatches/20150930.drydock.log.1.sql b/resources/sql/autopatches/20150930.drydock.log.1.sql new file mode 100644 index 0000000000..e84859b718 --- /dev/null +++ b/resources/sql/autopatches/20150930.drydock.log.1.sql @@ -0,0 +1,25 @@ +TRUNCATE {$NAMESPACE}_drydock.drydock_log; + +ALTER TABLE {$NAMESPACE}_drydock.drydock_log + DROP resourceID; + +ALTER TABLE {$NAMESPACE}_drydock.drydock_log + DROP leaseID; + +ALTER TABLE {$NAMESPACE}_drydock.drydock_log + DROP message; + +ALTER TABLE {$NAMESPACE}_drydock.drydock_log + ADD blueprintPHID VARBINARY(64); + +ALTER TABLE {$NAMESPACE}_drydock.drydock_log + ADD resourcePHID VARBINARY(64); + +ALTER TABLE {$NAMESPACE}_drydock.drydock_log + ADD leasePHID VARBINARY(64); + +ALTER TABLE {$NAMESPACE}_drydock.drydock_log + ADD type VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT}; + +ALTER TABLE {$NAMESPACE}_drydock.drydock_log + ADD data LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}; diff --git a/src/applications/drydock/application/PhabricatorDrydockApplication.php b/src/applications/drydock/application/PhabricatorDrydockApplication.php index 5df54593ee..e662fea9e6 100644 --- a/src/applications/drydock/application/PhabricatorDrydockApplication.php +++ b/src/applications/drydock/application/PhabricatorDrydockApplication.php @@ -47,7 +47,7 @@ final class PhabricatorDrydockApplication extends PhabricatorApplication { return array( '/drydock/' => array( '' => 'DrydockConsoleController', - 'blueprint/' => array( + '(?Pblueprint)/' => array( '(?:query/(?P[^/]+)/)?' => 'DrydockBlueprintListController', '(?P[1-9]\d*)/' => array( '' => 'DrydockBlueprintViewController', @@ -55,29 +55,32 @@ final class PhabricatorDrydockApplication extends PhabricatorApplication { 'DrydockBlueprintDisableController', 'resources/(?:query/(?P[^/]+)/)?' => 'DrydockResourceListController', + 'logs/(?:query/(?P[^/]+)/)?' => + 'DrydockLogListController', ), 'create/' => 'DrydockBlueprintCreateController', 'edit/(?:(?P[1-9]\d*)/)?' => 'DrydockBlueprintEditController', ), - 'resource/' => array( + '(?Presource)/' => array( '(?:query/(?P[^/]+)/)?' => 'DrydockResourceListController', '(?P[1-9]\d*)/' => array( '' => 'DrydockResourceViewController', 'release/' => 'DrydockResourceReleaseController', 'leases/(?:query/(?P[^/]+)/)?' => 'DrydockLeaseListController', + 'logs/(?:query/(?P[^/]+)/)?' => + 'DrydockLogListController', ), ), - 'lease/' => array( + '(?Please)/' => array( '(?:query/(?P[^/]+)/)?' => 'DrydockLeaseListController', '(?P[1-9]\d*)/' => array( '' => 'DrydockLeaseViewController', 'release/' => 'DrydockLeaseReleaseController', + 'logs/(?:query/(?P[^/]+)/)?' => + 'DrydockLogListController', ), ), - 'log/' => array( - '(?:query/(?P[^/]+)/)?' => 'DrydockLogListController', - ), ), ); } diff --git a/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php index f58767c4fc..b7e39a49a4 100644 --- a/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php +++ b/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php @@ -250,46 +250,6 @@ abstract class DrydockBlueprintImplementation extends Phobject { /* -( Logging )------------------------------------------------------------ */ - /** - * @task log - */ - protected function logException(Exception $ex) { - $this->log($ex->getMessage()); - } - - - /** - * @task log - */ - protected function log($message) { - self::writeLog(null, null, $message); - } - - - /** - * @task log - */ - public static function writeLog( - DrydockResource $resource = null, - DrydockLease $lease = null, - $message = null) { - - $log = id(new DrydockLog()) - ->setEpoch(time()) - ->setMessage($message); - - if ($resource) { - $log->setResourceID($resource->getID()); - } - - if ($lease) { - $log->setLeaseID($lease->getID()); - } - - $log->save(); - } - - public static function getAllBlueprintImplementations() { return id(new PhutilClassMapQuery()) ->setAncestorClass(__CLASS__) diff --git a/src/applications/drydock/controller/DrydockBlueprintViewController.php b/src/applications/drydock/controller/DrydockBlueprintViewController.php index 6991e18fa2..7102962600 100644 --- a/src/applications/drydock/controller/DrydockBlueprintViewController.php +++ b/src/applications/drydock/controller/DrydockBlueprintViewController.php @@ -56,11 +56,19 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController { new DrydockBlueprintTransactionQuery()); $timeline->setShouldTerminate(true); + $log_query = id(new DrydockLogQuery()) + ->withBlueprintPHIDs(array($blueprint->getPHID())); + + $log_box = $this->buildLogBox( + $log_query, + $this->getApplicationURI("blueprint/{$id}/logs/query/all/")); + return $this->buildApplicationPage( array( $crumbs, $object_box, $resource_box, + $log_box, $timeline, ), array( diff --git a/src/applications/drydock/controller/DrydockController.php b/src/applications/drydock/controller/DrydockController.php index e0130bdf56..760334cbdf 100644 --- a/src/applications/drydock/controller/DrydockController.php +++ b/src/applications/drydock/controller/DrydockController.php @@ -85,4 +85,31 @@ abstract class DrydockController extends PhabricatorController { ->addRawContent($table); } + protected function buildLogBox(DrydockLogQuery $query, $all_uri) { + $viewer = $this->getViewer(); + + $logs = $query + ->setViewer($viewer) + ->setLimit(100) + ->execute(); + + $log_table = id(new DrydockLogListView()) + ->setUser($viewer) + ->setLogs($logs) + ->render(); + + $log_header = id(new PHUIHeaderView()) + ->setHeader(pht('Logs')) + ->addActionLink( + id(new PHUIButtonView()) + ->setTag('a') + ->setHref($all_uri) + ->setIconFont('fa-search') + ->setText(pht('View All Logs'))); + + return id(new PHUIObjectBoxView()) + ->setHeader($log_header) + ->setTable($log_table); + } + } diff --git a/src/applications/drydock/controller/DrydockLeaseViewController.php b/src/applications/drydock/controller/DrydockLeaseViewController.php index af893ca49b..b9cf592313 100644 --- a/src/applications/drydock/controller/DrydockLeaseViewController.php +++ b/src/applications/drydock/controller/DrydockLeaseViewController.php @@ -15,7 +15,8 @@ final class DrydockLeaseViewController extends DrydockLeaseController { return new Aphront404Response(); } - $lease_uri = $this->getApplicationURI('lease/'.$lease->getID().'/'); + $id = $lease->getID(); + $lease_uri = $this->getApplicationURI("lease/{$id}/"); $title = pht('Lease %d', $lease->getID()); @@ -29,20 +30,12 @@ final class DrydockLeaseViewController extends DrydockLeaseController { $actions = $this->buildActionListView($lease); $properties = $this->buildPropertyListView($lease, $actions); - $pager = new PHUIPagerView(); - $pager->setURI(new PhutilURI($lease_uri), 'offset'); - $pager->setOffset($request->getInt('offset')); + $log_query = id(new DrydockLogQuery()) + ->withLeasePHIDs(array($lease->getPHID())); - $logs = id(new DrydockLogQuery()) - ->setViewer($viewer) - ->withLeaseIDs(array($lease->getID())) - ->executeWithOffsetPager($pager); - - $log_table = id(new DrydockLogListView()) - ->setUser($viewer) - ->setLogs($logs) - ->render(); - $log_table->appendChild($pager); + $log_box = $this->buildLogBox( + $log_query, + $this->getApplicationURI("lease/{$id}/logs/query/all/")); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title, $lease_uri); @@ -56,10 +49,6 @@ final class DrydockLeaseViewController extends DrydockLeaseController { ->addPropertyList($locks, pht('Slot Locks')) ->addPropertyList($commands, pht('Commands')); - $log_box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Lease Logs')) - ->setTable($log_table); - return $this->buildApplicationPage( array( $crumbs, diff --git a/src/applications/drydock/controller/DrydockLogController.php b/src/applications/drydock/controller/DrydockLogController.php index 0e28c62cb4..5ae87e6aad 100644 --- a/src/applications/drydock/controller/DrydockLogController.php +++ b/src/applications/drydock/controller/DrydockLogController.php @@ -3,13 +3,60 @@ abstract class DrydockLogController extends DrydockController { + private $blueprint; + private $resource; + private $lease; + + public function setBlueprint(DrydockBlueprint $blueprint) { + $this->blueprint = $blueprint; + return $this; + } + + public function getBlueprint() { + return $this->blueprint; + } + + public function setResource(DrydockResource $resource) { + $this->resource = $resource; + return $this; + } + + public function getResource() { + return $this->resource; + } + + public function setLease(DrydockLease $lease) { + $this->lease = $lease; + return $this; + } + + public function getLease() { + return $this->lease; + } + public function buildSideNavView() { $nav = new AphrontSideNavFilterView(); $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); - id(new DrydockLogSearchEngine()) - ->setViewer($this->getRequest()->getUser()) - ->addNavigationItems($nav->getMenu()); + $engine = id(new DrydockLogSearchEngine()) + ->setViewer($this->getRequest()->getUser()); + + $blueprint = $this->getBlueprint(); + if ($blueprint) { + $engine->setBlueprint($blueprint); + } + + $resource = $this->getResource(); + if ($resource) { + $engine->setResource($resource); + } + + $lease = $this->getLease(); + if ($lease) { + $engine->setLease($lease); + } + + $engine->addNavigationItems($nav->getMenu()); $nav->selectFilter(null); @@ -18,9 +65,54 @@ abstract class DrydockLogController protected function buildApplicationCrumbs() { $crumbs = parent::buildApplicationCrumbs(); - $crumbs->addTextCrumb( - pht('Logs'), - $this->getApplicationURI('log/')); + + $blueprint = $this->getBlueprint(); + $resource = $this->getResource(); + $lease = $this->getLease(); + if ($blueprint) { + $id = $blueprint->getID(); + + $crumbs->addTextCrumb( + pht('Blueprints'), + $this->getApplicationURI('blueprint/')); + + $crumbs->addTextCrumb( + $blueprint->getBlueprintName(), + $this->getApplicationURI("blueprint/{$id}/")); + + $crumbs->addTextCrumb( + pht('Logs'), + $this->getApplicationURI("blueprint/{$id}/logs/")); + } else if ($resource) { + $id = $resource->getID(); + + $crumbs->addTextCrumb( + pht('Resources'), + $this->getApplicationURI('resource/')); + + $crumbs->addTextCrumb( + $resource->getName(), + $this->getApplicationURI("resource/{$id}/")); + + $crumbs->addTextCrumb( + pht('Logs'), + $this->getApplicationURI("resource/{$id}/logs/")); + } else if ($lease) { + $id = $lease->getID(); + + $crumbs->addTextCrumb( + pht('Leases'), + $this->getApplicationURI('lease/')); + + $crumbs->addTextCrumb( + $lease->getLeaseName(), + $this->getApplicationURI("lease/{$id}/")); + + $crumbs->addTextCrumb( + pht('Logs'), + $this->getApplicationURI("lease/{$id}/logs/")); + } + return $crumbs; } diff --git a/src/applications/drydock/controller/DrydockLogListController.php b/src/applications/drydock/controller/DrydockLogListController.php index aecf77dc77..b5e4d4ff0c 100644 --- a/src/applications/drydock/controller/DrydockLogListController.php +++ b/src/applications/drydock/controller/DrydockLogListController.php @@ -8,11 +8,53 @@ final class DrydockLogListController extends DrydockLogController { public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); - $querykey = $request->getURIData('queryKey'); + $engine = new DrydockLogSearchEngine(); + + $id = $request->getURIData('id'); + $type = $request->getURIData('type'); + switch ($type) { + case 'blueprint': + $blueprint = id(new DrydockBlueprintQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->executeOne(); + if (!$blueprint) { + return new Aphront404Response(); + } + $engine->setBlueprint($blueprint); + $this->setBlueprint($blueprint); + break; + case 'resource': + $resource = id(new DrydockResourceQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->executeOne(); + if (!$resource) { + return new Aphront404Response(); + } + $engine->setResource($resource); + $this->setResource($resource); + break; + case 'lease': + $lease = id(new DrydockLeaseQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->executeOne(); + if (!$lease) { + return new Aphront404Response(); + } + $engine->setLease($lease); + $this->setLease($lease); + break; + default: + return new Aphront404Response(); + } + + $query_key = $request->getURIData('queryKey'); $controller = id(new PhabricatorApplicationSearchController()) - ->setQueryKey($querykey) - ->setSearchEngine(new DrydockLogSearchEngine()) + ->setQueryKey($query_key) + ->setSearchEngine($engine) ->setNavigation($this->buildSideNavView()); return $this->delegateToController($controller); diff --git a/src/applications/drydock/controller/DrydockResourceViewController.php b/src/applications/drydock/controller/DrydockResourceViewController.php index 23f81c5225..f97081e673 100644 --- a/src/applications/drydock/controller/DrydockResourceViewController.php +++ b/src/applications/drydock/controller/DrydockResourceViewController.php @@ -29,23 +29,15 @@ final class DrydockResourceViewController extends DrydockResourceController { $actions = $this->buildActionListView($resource); $properties = $this->buildPropertyListView($resource, $actions); - $resource_uri = 'resource/'.$resource->getID().'/'; - $resource_uri = $this->getApplicationURI($resource_uri); + $id = $resource->getID(); + $resource_uri = $this->getApplicationURI("resource/{$id}/"); - $pager = new PHUIPagerView(); - $pager->setURI(new PhutilURI($resource_uri), 'offset'); - $pager->setOffset($request->getInt('offset')); + $log_query = id(new DrydockLogQuery()) + ->withResourcePHIDs(array($resource->getPHID())); - $logs = id(new DrydockLogQuery()) - ->setViewer($viewer) - ->withResourceIDs(array($resource->getID())) - ->executeWithOffsetPager($pager); - - $log_table = id(new DrydockLogListView()) - ->setUser($viewer) - ->setLogs($logs) - ->render(); - $log_table->appendChild($pager); + $log_box = $this->buildLogBox( + $log_query, + $this->getApplicationURI("resource/{$id}/logs/query/all/")); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Resource %d', $resource->getID())); @@ -61,10 +53,6 @@ final class DrydockResourceViewController extends DrydockResourceController { $lease_box = $this->buildLeaseBox($resource); - $log_box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Resource Logs')) - ->setTable($log_table); - return $this->buildApplicationPage( array( $crumbs, diff --git a/src/applications/drydock/query/DrydockLogQuery.php b/src/applications/drydock/query/DrydockLogQuery.php index 47a6795463..00980edb4d 100644 --- a/src/applications/drydock/query/DrydockLogQuery.php +++ b/src/applications/drydock/query/DrydockLogQuery.php @@ -2,112 +2,125 @@ final class DrydockLogQuery extends DrydockQuery { - private $resourceIDs; - private $leaseIDs; + private $blueprintPHIDs; + private $resourcePHIDs; + private $leasePHIDs; - public function withResourceIDs(array $ids) { - $this->resourceIDs = $ids; + public function withBlueprintPHIDs(array $phids) { + $this->blueprintPHIDs = $phids; return $this; } - public function withLeaseIDs(array $ids) { - $this->leaseIDs = $ids; + public function withResourcePHIDs(array $phids) { + $this->resourcePHIDs = $phids; return $this; } + public function withLeasePHIDs(array $phids) { + $this->leasePHIDs = $phids; + return $this; + } + + public function newResultObject() { + return new DrydockLog(); + } + protected 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); + return $this->loadStandardPage($this->newResultObject()); } - protected function willFilterPage(array $logs) { - $resource_ids = array_filter(mpull($logs, 'getResourceID')); - if ($resource_ids) { + protected function didFilterPage(array $logs) { + $blueprint_phids = array_filter(mpull($logs, 'getBlueprintPHID')); + if ($blueprint_phids) { + $blueprints = id(new DrydockBlueprintQuery()) + ->setParentQuery($this) + ->setViewer($this->getViewer()) + ->withPHIDs($blueprint_phids) + ->execute(); + $blueprints = mpull($blueprints, null, 'getPHID'); + } else { + $blueprints = array(); + } + + foreach ($logs as $key => $log) { + $blueprint = null; + $blueprint_phid = $log->getBlueprintPHID(); + if ($blueprint_phid) { + $blueprint = idx($blueprints, $blueprint_phid); + } + $log->attachBlueprint($blueprint); + } + + $resource_phids = array_filter(mpull($logs, 'getResourcePHID')); + if ($resource_phids) { $resources = id(new DrydockResourceQuery()) ->setParentQuery($this) ->setViewer($this->getViewer()) - ->withIDs(array_unique($resource_ids)) + ->withPHIDs($resource_phids) ->execute(); + $resources = mpull($resources, null, 'getPHID'); } else { $resources = array(); } foreach ($logs as $key => $log) { $resource = null; - if ($log->getResourceID()) { - $resource = idx($resources, $log->getResourceID()); - if (!$resource) { - unset($logs[$key]); - continue; - } + $resource_phid = $log->getResourcePHID(); + if ($resource_phid) { + $resource = idx($resources, $resource_phid); } $log->attachResource($resource); } - $lease_ids = array_filter(mpull($logs, 'getLeaseID')); - if ($lease_ids) { + $lease_phids = array_filter(mpull($logs, 'getLeasePHID')); + if ($lease_phids) { $leases = id(new DrydockLeaseQuery()) ->setParentQuery($this) ->setViewer($this->getViewer()) - ->withIDs(array_unique($lease_ids)) + ->withPHIDs($lease_phids) ->execute(); + $leases = mpull($leases, null, 'getPHID'); } else { $leases = array(); } foreach ($logs as $key => $log) { $lease = null; - if ($log->getLeaseID()) { - $lease = idx($leases, $log->getLeaseID()); - if (!$lease) { - unset($logs[$key]); - continue; - } + $lease_phid = $log->getLeasePHID(); + if ($lease_phid) { + $lease = idx($leases, $lease_phid); } $log->attachLease($lease); } - // These logs are meaningless and their policies aren't computable. They - // shouldn't exist, but throw them away if they do. - foreach ($logs as $key => $log) { - if (!$log->getResource() && !$log->getLease()) { - unset($logs[$key]); - } - } - return $logs; } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); - if ($this->resourceIDs !== null) { + if ($this->blueprintPHIDs !== null) { $where[] = qsprintf( - $conn_r, - 'resourceID IN (%Ld)', - $this->resourceIDs); + $conn, + 'blueprintPHID IN (%Ls)', + $this->blueprintPHIDs); } - if ($this->leaseIDs !== null) { + if ($this->resourcePHIDs !== null) { $where[] = qsprintf( - $conn_r, - 'leaseID IN (%Ld)', - $this->leaseIDs); + $conn, + 'resourcePHID IN (%Ls)', + $this->resourcePHIDs); } - $where[] = $this->buildPagingClause($conn_r); + if ($this->leasePHIDs !== null) { + $where[] = qsprintf( + $conn, + 'leasePHID IN (%Ls)', + $this->leasePHIDs); + } - return $this->formatWhereClause($where); + return $where; } } diff --git a/src/applications/drydock/query/DrydockLogSearchEngine.php b/src/applications/drydock/query/DrydockLogSearchEngine.php index 13777031d6..43b1511c01 100644 --- a/src/applications/drydock/query/DrydockLogSearchEngine.php +++ b/src/applications/drydock/query/DrydockLogSearchEngine.php @@ -2,6 +2,43 @@ final class DrydockLogSearchEngine extends PhabricatorApplicationSearchEngine { + private $blueprint; + private $resource; + private $lease; + + public function setBlueprint(DrydockBlueprint $blueprint) { + $this->blueprint = $blueprint; + return $this; + } + + public function getBlueprint() { + return $this->blueprint; + } + + public function setResource(DrydockResource $resource) { + $this->resource = $resource; + return $this; + } + + public function getResource() { + return $this->resource; + } + + public function setLease(DrydockLease $lease) { + $this->lease = $lease; + return $this; + } + + public function getLease() { + return $this->lease; + } + + public function canUseInPanelContext() { + // Prevent use on Dashboard panels since all log queries currently need a + // parent object and these don't seem particularly useful in any case. + return false; + } + public function getResultTypeDescription() { return pht('Drydock Logs'); } @@ -10,75 +47,59 @@ final class DrydockLogSearchEngine extends PhabricatorApplicationSearchEngine { return 'PhabricatorDrydockApplication'; } - public function buildSavedQueryFromRequest(AphrontRequest $request) { - $query = new PhabricatorSavedQuery(); - - $query->setParameter( - 'resourcePHIDs', - $this->readListFromRequest($request, 'resources')); - $query->setParameter( - 'leasePHIDs', - $this->readListFromRequest($request, 'leases')); - - return $query; - } - - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - $resource_phids = $saved->getParameter('resourcePHIDs', array()); - $lease_phids = $saved->getParameter('leasePHIDs', array()); - - // TODO: Change logs to use PHIDs instead of IDs. - $resource_ids = array(); - $lease_ids = array(); - - if ($resource_phids) { - $resource_ids = id(new DrydockResourceQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withPHIDs($resource_phids) - ->execute(); - $resource_ids = mpull($resource_ids, 'getID'); - } - - if ($lease_phids) { - $lease_ids = id(new DrydockLeaseQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withPHIDs($lease_phids) - ->execute(); - $lease_ids = mpull($lease_ids, 'getID'); - } - + public function newQuery() { $query = new DrydockLogQuery(); - if ($resource_ids) { - $query->withResourceIDs($resource_ids); + + $blueprint = $this->getBlueprint(); + if ($blueprint) { + $query->withBlueprintPHIDs(array($blueprint->getPHID())); } - if ($lease_ids) { - $query->withLeaseIDs($lease_ids); + + $resource = $this->getResource(); + if ($resource) { + $query->withResourcePHIDs(array($resource->getPHID())); + } + + $lease = $this->getLease(); + if ($lease) { + $query->withLeasePHIDs(array($lease->getPHID())); } return $query; } - public function buildSearchForm( - AphrontFormView $form, - PhabricatorSavedQuery $saved) { + protected function buildQueryFromParameters(array $map) { + $query = $this->newQuery(); - $form - ->appendControl( - id(new AphrontFormTokenizerControl()) - ->setDatasource(new DrydockResourceDatasource()) - ->setName('resources') - ->setLabel(pht('Resources')) - ->setValue($saved->getParameter('resourcePHIDs', array()))) - ->appendControl( - id(new AphrontFormTokenizerControl()) - ->setDatasource(new DrydockLeaseDatasource()) - ->setName('leases') - ->setLabel(pht('Leases')) - ->setValue($saved->getParameter('leasePHIDs', array()))); + return $query; + } + + protected function buildCustomSearchFields() { + return array(); } protected function getURI($path) { - return '/drydock/log/'.$path; + $blueprint = $this->getBlueprint(); + if ($blueprint) { + $id = $blueprint->getID(); + return "/drydock/blueprint/{$id}/logs/{$path}"; + } + + $resource = $this->getResource(); + if ($resource) { + $id = $resource->getID(); + return "/drydock/resource/{$id}/logs/{$path}"; + } + + $lease = $this->getLease(); + if ($lease) { + $id = $lease->getID(); + return "/drydock/lease/{$id}/logs/{$path}"; + } + + throw new Exception( + pht( + 'Search engine has no blueprint, resource, or lease.')); } protected function getBuiltinQueryNames() { diff --git a/src/applications/drydock/storage/DrydockLease.php b/src/applications/drydock/storage/DrydockLease.php index af0b322b62..b16efbabbb 100644 --- a/src/applications/drydock/storage/DrydockLease.php +++ b/src/applications/drydock/storage/DrydockLease.php @@ -347,6 +347,9 @@ final class DrydockLease extends DrydockDAO $viewer = PhabricatorUser::getOmnipotentUser(); $need_update = false; + // TODO: This is just a placeholder to get some data in the table. + $this->logEvent('activated'); + $commands = id(new DrydockCommandQuery()) ->setViewer($viewer) ->withTargetPHIDs(array($this->getPHID())) @@ -371,6 +374,24 @@ final class DrydockLease extends DrydockDAO } } + public function logEvent($type, array $data = array()) { + $log = id(new DrydockLog()) + ->setEpoch(PhabricatorTime::getNow()) + ->setType($type) + ->setData($data); + + $log->setLeasePHID($this->getPHID()); + + $resource = $this->getResource(); + if ($resource) { + $log->setResourcePHID($resource->getPHID()); + $log->setBlueprintPHID($resource->getBlueprintPHID()); + } + + return $log->save(); + } + + /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff --git a/src/applications/drydock/storage/DrydockLog.php b/src/applications/drydock/storage/DrydockLog.php index 36d310c510..5d75d82c65 100644 --- a/src/applications/drydock/storage/DrydockLog.php +++ b/src/applications/drydock/storage/DrydockLog.php @@ -3,28 +3,38 @@ final class DrydockLog extends DrydockDAO implements PhabricatorPolicyInterface { - protected $resourceID; - protected $leaseID; + protected $blueprintPHID; + protected $resourcePHID; + protected $leasePHID; protected $epoch; - protected $message; + protected $type; + protected $data = array(); + private $blueprint = self::ATTACHABLE; private $resource = self::ATTACHABLE; private $lease = self::ATTACHABLE; protected function getConfiguration() { return array( self::CONFIG_TIMESTAMPS => false, + self::CONFIG_SERIALIZATION => array( + 'data' => self::SERIALIZATION_JSON, + ), self::CONFIG_COLUMN_SCHEMA => array( - 'resourceID' => 'id?', - 'leaseID' => 'id?', - 'message' => 'text', + 'blueprintPHID' => 'phid?', + 'resourcePHID' => 'phid?', + 'leasePHID' => 'phid?', + 'type' => 'text64', ), self::CONFIG_KEY_SCHEMA => array( - 'resourceID' => array( - 'columns' => array('resourceID', 'epoch'), + 'key_blueprint' => array( + 'columns' => array('blueprintPHID', 'type'), ), - 'leaseID' => array( - 'columns' => array('leaseID', 'epoch'), + 'key_resource' => array( + 'columns' => array('resourcePHID', 'type'), + ), + 'key_lease' => array( + 'columns' => array('leasePHID', 'type'), ), 'epoch' => array( 'columns' => array('epoch'), @@ -33,6 +43,15 @@ final class DrydockLog extends DrydockDAO ) + parent::getConfiguration(); } + public function attachBlueprint(DrydockBlueprint $blueprint = null) { + $this->blueprint = $blueprint; + return $this; + } + + public function getBlueprint() { + return $this->assertAttached($this->blueprint); + } + public function attachResource(DrydockResource $resource = null) { $this->resource = $resource; return $this; @@ -51,6 +70,22 @@ final class DrydockLog extends DrydockDAO return $this->assertAttached($this->lease); } + public function isComplete() { + if ($this->getBlueprintPHID() && !$this->getBlueprint()) { + return false; + } + + if ($this->getResourcePHID() && !$this->getResource()) { + return false; + } + + if ($this->getLeasePHID() && !$this->getLease()) { + return false; + } + + return true; + } + /* -( PhabricatorPolicyInterface )----------------------------------------- */ @@ -62,21 +97,19 @@ final class DrydockLog extends DrydockDAO } public function getPolicy($capability) { - if ($this->getResource()) { - return $this->getResource()->getPolicy($capability); - } - return $this->getLease()->getPolicy($capability); + // NOTE: We let you see that logs exist no matter what, but don't actually + // show you log content unless you can see all of the associated objects. + return PhabricatorPolicies::getMostOpenPolicy(); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { - if ($this->getResource()) { - return $this->getResource()->hasAutomaticCapability($capability, $viewer); - } - return $this->getLease()->hasAutomaticCapability($capability, $viewer); + return false; } public function describeAutomaticCapability($capability) { - return pht('Logs inherit the policy of their resources.'); + return pht( + 'To view log details, you must be able to view the associated '. + 'blueprint, resource and lease.'); } } diff --git a/src/applications/drydock/view/DrydockLogListView.php b/src/applications/drydock/view/DrydockLogListView.php index 22e280939b..f6560270a0 100644 --- a/src/applications/drydock/view/DrydockLogListView.php +++ b/src/applications/drydock/view/DrydockLogListView.php @@ -18,28 +18,45 @@ final class DrydockLogListView extends AphrontView { $rows = array(); foreach ($logs as $log) { - $resource_uri = '/drydock/resource/'.$log->getResourceID().'/'; - $lease_uri = '/drydock/lease/'.$log->getLeaseID().'/'; + $blueprint_phid = $log->getBlueprintPHID(); + if ($blueprint_phid) { + $blueprint = $viewer->renderHandle($blueprint_phid); + } else { + $blueprint = null; + } - $resource_name = $log->getResourceID(); - if ($log->getResourceID() !== null) { - $resource_name = $log->getResource()->getName(); + $resource_phid = $log->getResourcePHID(); + if ($resource_phid) { + $resource = $viewer->renderHandle($resource_phid); + } else { + $resource = null; + } + + $lease_phid = $log->getLeasePHID(); + if ($lease_phid) { + $lease = $viewer->renderHandle($lease_phid); + } else { + $lease = null; + } + + if ($log->isComplete()) { + // TODO: This is a placeholder. + $type = $log->getType(); + $data = print_r($log->getData(), true); + } else { + $type = phutil_tag('em', array(), pht('Restricted')); + $data = phutil_tag( + 'em', + array(), + pht('You do not have permission to view this log event.')); } $rows[] = array( - phutil_tag( - 'a', - array( - 'href' => $resource_uri, - ), - $resource_name), - phutil_tag( - 'a', - array( - 'href' => $lease_uri, - ), - $log->getLeaseID()), - $log->getMessage(), + $blueprint, + $resource, + $lease, + $type, + $data, phabricator_datetime($log->getEpoch(), $viewer), ); } @@ -48,20 +65,17 @@ final class DrydockLogListView extends AphrontView { $table->setDeviceReadyTable(true); $table->setHeaders( array( + pht('Blueprint'), pht('Resource'), pht('Lease'), - pht('Message'), + pht('Type'), + pht('Data'), pht('Date'), )); - $table->setShortHeaders( - array( - pht('R'), - pht('L'), - pht('Message'), - '', - )); $table->setColumnClasses( array( + '', + '', '', '', 'wide',