@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+483 -247
+25
resources/sql/autopatches/20150930.drydock.log.1.sql
··· 1 + TRUNCATE {$NAMESPACE}_drydock.drydock_log; 2 + 3 + ALTER TABLE {$NAMESPACE}_drydock.drydock_log 4 + DROP resourceID; 5 + 6 + ALTER TABLE {$NAMESPACE}_drydock.drydock_log 7 + DROP leaseID; 8 + 9 + ALTER TABLE {$NAMESPACE}_drydock.drydock_log 10 + DROP message; 11 + 12 + ALTER TABLE {$NAMESPACE}_drydock.drydock_log 13 + ADD blueprintPHID VARBINARY(64); 14 + 15 + ALTER TABLE {$NAMESPACE}_drydock.drydock_log 16 + ADD resourcePHID VARBINARY(64); 17 + 18 + ALTER TABLE {$NAMESPACE}_drydock.drydock_log 19 + ADD leasePHID VARBINARY(64); 20 + 21 + ALTER TABLE {$NAMESPACE}_drydock.drydock_log 22 + ADD type VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT}; 23 + 24 + ALTER TABLE {$NAMESPACE}_drydock.drydock_log 25 + ADD data LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT};
+9 -6
src/applications/drydock/application/PhabricatorDrydockApplication.php
··· 47 47 return array( 48 48 '/drydock/' => array( 49 49 '' => 'DrydockConsoleController', 50 - 'blueprint/' => array( 50 + '(?P<type>blueprint)/' => array( 51 51 '(?:query/(?P<queryKey>[^/]+)/)?' => 'DrydockBlueprintListController', 52 52 '(?P<id>[1-9]\d*)/' => array( 53 53 '' => 'DrydockBlueprintViewController', ··· 55 55 'DrydockBlueprintDisableController', 56 56 'resources/(?:query/(?P<queryKey>[^/]+)/)?' => 57 57 'DrydockResourceListController', 58 + 'logs/(?:query/(?P<queryKey>[^/]+)/)?' => 59 + 'DrydockLogListController', 58 60 ), 59 61 'create/' => 'DrydockBlueprintCreateController', 60 62 'edit/(?:(?P<id>[1-9]\d*)/)?' => 'DrydockBlueprintEditController', 61 63 ), 62 - 'resource/' => array( 64 + '(?P<type>resource)/' => array( 63 65 '(?:query/(?P<queryKey>[^/]+)/)?' => 'DrydockResourceListController', 64 66 '(?P<id>[1-9]\d*)/' => array( 65 67 '' => 'DrydockResourceViewController', 66 68 'release/' => 'DrydockResourceReleaseController', 67 69 'leases/(?:query/(?P<queryKey>[^/]+)/)?' => 68 70 'DrydockLeaseListController', 71 + 'logs/(?:query/(?P<queryKey>[^/]+)/)?' => 72 + 'DrydockLogListController', 69 73 ), 70 74 ), 71 - 'lease/' => array( 75 + '(?P<type>lease)/' => array( 72 76 '(?:query/(?P<queryKey>[^/]+)/)?' => 'DrydockLeaseListController', 73 77 '(?P<id>[1-9]\d*)/' => array( 74 78 '' => 'DrydockLeaseViewController', 75 79 'release/' => 'DrydockLeaseReleaseController', 80 + 'logs/(?:query/(?P<queryKey>[^/]+)/)?' => 81 + 'DrydockLogListController', 76 82 ), 77 - ), 78 - 'log/' => array( 79 - '(?:query/(?P<queryKey>[^/]+)/)?' => 'DrydockLogListController', 80 83 ), 81 84 ), 82 85 );
-40
src/applications/drydock/blueprint/DrydockBlueprintImplementation.php
··· 250 250 /* -( Logging )------------------------------------------------------------ */ 251 251 252 252 253 - /** 254 - * @task log 255 - */ 256 - protected function logException(Exception $ex) { 257 - $this->log($ex->getMessage()); 258 - } 259 - 260 - 261 - /** 262 - * @task log 263 - */ 264 - protected function log($message) { 265 - self::writeLog(null, null, $message); 266 - } 267 - 268 - 269 - /** 270 - * @task log 271 - */ 272 - public static function writeLog( 273 - DrydockResource $resource = null, 274 - DrydockLease $lease = null, 275 - $message = null) { 276 - 277 - $log = id(new DrydockLog()) 278 - ->setEpoch(time()) 279 - ->setMessage($message); 280 - 281 - if ($resource) { 282 - $log->setResourceID($resource->getID()); 283 - } 284 - 285 - if ($lease) { 286 - $log->setLeaseID($lease->getID()); 287 - } 288 - 289 - $log->save(); 290 - } 291 - 292 - 293 253 public static function getAllBlueprintImplementations() { 294 254 return id(new PhutilClassMapQuery()) 295 255 ->setAncestorClass(__CLASS__)
+8
src/applications/drydock/controller/DrydockBlueprintViewController.php
··· 56 56 new DrydockBlueprintTransactionQuery()); 57 57 $timeline->setShouldTerminate(true); 58 58 59 + $log_query = id(new DrydockLogQuery()) 60 + ->withBlueprintPHIDs(array($blueprint->getPHID())); 61 + 62 + $log_box = $this->buildLogBox( 63 + $log_query, 64 + $this->getApplicationURI("blueprint/{$id}/logs/query/all/")); 65 + 59 66 return $this->buildApplicationPage( 60 67 array( 61 68 $crumbs, 62 69 $object_box, 63 70 $resource_box, 71 + $log_box, 64 72 $timeline, 65 73 ), 66 74 array(
+27
src/applications/drydock/controller/DrydockController.php
··· 85 85 ->addRawContent($table); 86 86 } 87 87 88 + protected function buildLogBox(DrydockLogQuery $query, $all_uri) { 89 + $viewer = $this->getViewer(); 90 + 91 + $logs = $query 92 + ->setViewer($viewer) 93 + ->setLimit(100) 94 + ->execute(); 95 + 96 + $log_table = id(new DrydockLogListView()) 97 + ->setUser($viewer) 98 + ->setLogs($logs) 99 + ->render(); 100 + 101 + $log_header = id(new PHUIHeaderView()) 102 + ->setHeader(pht('Logs')) 103 + ->addActionLink( 104 + id(new PHUIButtonView()) 105 + ->setTag('a') 106 + ->setHref($all_uri) 107 + ->setIconFont('fa-search') 108 + ->setText(pht('View All Logs'))); 109 + 110 + return id(new PHUIObjectBoxView()) 111 + ->setHeader($log_header) 112 + ->setTable($log_table); 113 + } 114 + 88 115 }
+7 -18
src/applications/drydock/controller/DrydockLeaseViewController.php
··· 15 15 return new Aphront404Response(); 16 16 } 17 17 18 - $lease_uri = $this->getApplicationURI('lease/'.$lease->getID().'/'); 18 + $id = $lease->getID(); 19 + $lease_uri = $this->getApplicationURI("lease/{$id}/"); 19 20 20 21 $title = pht('Lease %d', $lease->getID()); 21 22 ··· 29 30 $actions = $this->buildActionListView($lease); 30 31 $properties = $this->buildPropertyListView($lease, $actions); 31 32 32 - $pager = new PHUIPagerView(); 33 - $pager->setURI(new PhutilURI($lease_uri), 'offset'); 34 - $pager->setOffset($request->getInt('offset')); 33 + $log_query = id(new DrydockLogQuery()) 34 + ->withLeasePHIDs(array($lease->getPHID())); 35 35 36 - $logs = id(new DrydockLogQuery()) 37 - ->setViewer($viewer) 38 - ->withLeaseIDs(array($lease->getID())) 39 - ->executeWithOffsetPager($pager); 40 - 41 - $log_table = id(new DrydockLogListView()) 42 - ->setUser($viewer) 43 - ->setLogs($logs) 44 - ->render(); 45 - $log_table->appendChild($pager); 36 + $log_box = $this->buildLogBox( 37 + $log_query, 38 + $this->getApplicationURI("lease/{$id}/logs/query/all/")); 46 39 47 40 $crumbs = $this->buildApplicationCrumbs(); 48 41 $crumbs->addTextCrumb($title, $lease_uri); ··· 55 48 ->addPropertyList($properties, pht('Properties')) 56 49 ->addPropertyList($locks, pht('Slot Locks')) 57 50 ->addPropertyList($commands, pht('Commands')); 58 - 59 - $log_box = id(new PHUIObjectBoxView()) 60 - ->setHeaderText(pht('Lease Logs')) 61 - ->setTable($log_table); 62 51 63 52 return $this->buildApplicationPage( 64 53 array(
+98 -6
src/applications/drydock/controller/DrydockLogController.php
··· 3 3 abstract class DrydockLogController 4 4 extends DrydockController { 5 5 6 + private $blueprint; 7 + private $resource; 8 + private $lease; 9 + 10 + public function setBlueprint(DrydockBlueprint $blueprint) { 11 + $this->blueprint = $blueprint; 12 + return $this; 13 + } 14 + 15 + public function getBlueprint() { 16 + return $this->blueprint; 17 + } 18 + 19 + public function setResource(DrydockResource $resource) { 20 + $this->resource = $resource; 21 + return $this; 22 + } 23 + 24 + public function getResource() { 25 + return $this->resource; 26 + } 27 + 28 + public function setLease(DrydockLease $lease) { 29 + $this->lease = $lease; 30 + return $this; 31 + } 32 + 33 + public function getLease() { 34 + return $this->lease; 35 + } 36 + 6 37 public function buildSideNavView() { 7 38 $nav = new AphrontSideNavFilterView(); 8 39 $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); 9 40 10 - id(new DrydockLogSearchEngine()) 11 - ->setViewer($this->getRequest()->getUser()) 12 - ->addNavigationItems($nav->getMenu()); 41 + $engine = id(new DrydockLogSearchEngine()) 42 + ->setViewer($this->getRequest()->getUser()); 43 + 44 + $blueprint = $this->getBlueprint(); 45 + if ($blueprint) { 46 + $engine->setBlueprint($blueprint); 47 + } 48 + 49 + $resource = $this->getResource(); 50 + if ($resource) { 51 + $engine->setResource($resource); 52 + } 53 + 54 + $lease = $this->getLease(); 55 + if ($lease) { 56 + $engine->setLease($lease); 57 + } 58 + 59 + $engine->addNavigationItems($nav->getMenu()); 13 60 14 61 $nav->selectFilter(null); 15 62 ··· 18 65 19 66 protected function buildApplicationCrumbs() { 20 67 $crumbs = parent::buildApplicationCrumbs(); 21 - $crumbs->addTextCrumb( 22 - pht('Logs'), 23 - $this->getApplicationURI('log/')); 68 + 69 + $blueprint = $this->getBlueprint(); 70 + $resource = $this->getResource(); 71 + $lease = $this->getLease(); 72 + if ($blueprint) { 73 + $id = $blueprint->getID(); 74 + 75 + $crumbs->addTextCrumb( 76 + pht('Blueprints'), 77 + $this->getApplicationURI('blueprint/')); 78 + 79 + $crumbs->addTextCrumb( 80 + $blueprint->getBlueprintName(), 81 + $this->getApplicationURI("blueprint/{$id}/")); 82 + 83 + $crumbs->addTextCrumb( 84 + pht('Logs'), 85 + $this->getApplicationURI("blueprint/{$id}/logs/")); 86 + } else if ($resource) { 87 + $id = $resource->getID(); 88 + 89 + $crumbs->addTextCrumb( 90 + pht('Resources'), 91 + $this->getApplicationURI('resource/')); 92 + 93 + $crumbs->addTextCrumb( 94 + $resource->getName(), 95 + $this->getApplicationURI("resource/{$id}/")); 96 + 97 + $crumbs->addTextCrumb( 98 + pht('Logs'), 99 + $this->getApplicationURI("resource/{$id}/logs/")); 100 + } else if ($lease) { 101 + $id = $lease->getID(); 102 + 103 + $crumbs->addTextCrumb( 104 + pht('Leases'), 105 + $this->getApplicationURI('lease/')); 106 + 107 + $crumbs->addTextCrumb( 108 + $lease->getLeaseName(), 109 + $this->getApplicationURI("lease/{$id}/")); 110 + 111 + $crumbs->addTextCrumb( 112 + pht('Logs'), 113 + $this->getApplicationURI("lease/{$id}/logs/")); 114 + } 115 + 24 116 return $crumbs; 25 117 } 26 118
+45 -3
src/applications/drydock/controller/DrydockLogListController.php
··· 8 8 9 9 public function handleRequest(AphrontRequest $request) { 10 10 $viewer = $request->getViewer(); 11 - $querykey = $request->getURIData('queryKey'); 11 + $engine = new DrydockLogSearchEngine(); 12 + 13 + $id = $request->getURIData('id'); 14 + $type = $request->getURIData('type'); 15 + switch ($type) { 16 + case 'blueprint': 17 + $blueprint = id(new DrydockBlueprintQuery()) 18 + ->setViewer($viewer) 19 + ->withIDs(array($id)) 20 + ->executeOne(); 21 + if (!$blueprint) { 22 + return new Aphront404Response(); 23 + } 24 + $engine->setBlueprint($blueprint); 25 + $this->setBlueprint($blueprint); 26 + break; 27 + case 'resource': 28 + $resource = id(new DrydockResourceQuery()) 29 + ->setViewer($viewer) 30 + ->withIDs(array($id)) 31 + ->executeOne(); 32 + if (!$resource) { 33 + return new Aphront404Response(); 34 + } 35 + $engine->setResource($resource); 36 + $this->setResource($resource); 37 + break; 38 + case 'lease': 39 + $lease = id(new DrydockLeaseQuery()) 40 + ->setViewer($viewer) 41 + ->withIDs(array($id)) 42 + ->executeOne(); 43 + if (!$lease) { 44 + return new Aphront404Response(); 45 + } 46 + $engine->setLease($lease); 47 + $this->setLease($lease); 48 + break; 49 + default: 50 + return new Aphront404Response(); 51 + } 52 + 53 + $query_key = $request->getURIData('queryKey'); 12 54 13 55 $controller = id(new PhabricatorApplicationSearchController()) 14 - ->setQueryKey($querykey) 15 - ->setSearchEngine(new DrydockLogSearchEngine()) 56 + ->setQueryKey($query_key) 57 + ->setSearchEngine($engine) 16 58 ->setNavigation($this->buildSideNavView()); 17 59 18 60 return $this->delegateToController($controller);
+7 -19
src/applications/drydock/controller/DrydockResourceViewController.php
··· 29 29 $actions = $this->buildActionListView($resource); 30 30 $properties = $this->buildPropertyListView($resource, $actions); 31 31 32 - $resource_uri = 'resource/'.$resource->getID().'/'; 33 - $resource_uri = $this->getApplicationURI($resource_uri); 32 + $id = $resource->getID(); 33 + $resource_uri = $this->getApplicationURI("resource/{$id}/"); 34 34 35 - $pager = new PHUIPagerView(); 36 - $pager->setURI(new PhutilURI($resource_uri), 'offset'); 37 - $pager->setOffset($request->getInt('offset')); 38 - 39 - $logs = id(new DrydockLogQuery()) 40 - ->setViewer($viewer) 41 - ->withResourceIDs(array($resource->getID())) 42 - ->executeWithOffsetPager($pager); 35 + $log_query = id(new DrydockLogQuery()) 36 + ->withResourcePHIDs(array($resource->getPHID())); 43 37 44 - $log_table = id(new DrydockLogListView()) 45 - ->setUser($viewer) 46 - ->setLogs($logs) 47 - ->render(); 48 - $log_table->appendChild($pager); 38 + $log_box = $this->buildLogBox( 39 + $log_query, 40 + $this->getApplicationURI("resource/{$id}/logs/query/all/")); 49 41 50 42 $crumbs = $this->buildApplicationCrumbs(); 51 43 $crumbs->addTextCrumb(pht('Resource %d', $resource->getID())); ··· 60 52 ->addPropertyList($commands, pht('Commands')); 61 53 62 54 $lease_box = $this->buildLeaseBox($resource); 63 - 64 - $log_box = id(new PHUIObjectBoxView()) 65 - ->setHeaderText(pht('Resource Logs')) 66 - ->setTable($log_table); 67 55 68 56 return $this->buildApplicationPage( 69 57 array(
+69 -56
src/applications/drydock/query/DrydockLogQuery.php
··· 2 2 3 3 final class DrydockLogQuery extends DrydockQuery { 4 4 5 - private $resourceIDs; 6 - private $leaseIDs; 5 + private $blueprintPHIDs; 6 + private $resourcePHIDs; 7 + private $leasePHIDs; 7 8 8 - public function withResourceIDs(array $ids) { 9 - $this->resourceIDs = $ids; 9 + public function withBlueprintPHIDs(array $phids) { 10 + $this->blueprintPHIDs = $phids; 10 11 return $this; 11 12 } 12 13 13 - public function withLeaseIDs(array $ids) { 14 - $this->leaseIDs = $ids; 14 + public function withResourcePHIDs(array $phids) { 15 + $this->resourcePHIDs = $phids; 15 16 return $this; 16 17 } 17 18 19 + public function withLeasePHIDs(array $phids) { 20 + $this->leasePHIDs = $phids; 21 + return $this; 22 + } 23 + 24 + public function newResultObject() { 25 + return new DrydockLog(); 26 + } 27 + 18 28 protected function loadPage() { 19 - $table = new DrydockLog(); 20 - $conn_r = $table->establishConnection('r'); 29 + return $this->loadStandardPage($this->newResultObject()); 30 + } 21 31 22 - $data = queryfx_all( 23 - $conn_r, 24 - 'SELECT log.* FROM %T log %Q %Q %Q', 25 - $table->getTableName(), 26 - $this->buildWhereClause($conn_r), 27 - $this->buildOrderClause($conn_r), 28 - $this->buildLimitClause($conn_r)); 32 + protected function didFilterPage(array $logs) { 33 + $blueprint_phids = array_filter(mpull($logs, 'getBlueprintPHID')); 34 + if ($blueprint_phids) { 35 + $blueprints = id(new DrydockBlueprintQuery()) 36 + ->setParentQuery($this) 37 + ->setViewer($this->getViewer()) 38 + ->withPHIDs($blueprint_phids) 39 + ->execute(); 40 + $blueprints = mpull($blueprints, null, 'getPHID'); 41 + } else { 42 + $blueprints = array(); 43 + } 29 44 30 - return $table->loadAllFromArray($data); 31 - } 45 + foreach ($logs as $key => $log) { 46 + $blueprint = null; 47 + $blueprint_phid = $log->getBlueprintPHID(); 48 + if ($blueprint_phid) { 49 + $blueprint = idx($blueprints, $blueprint_phid); 50 + } 51 + $log->attachBlueprint($blueprint); 52 + } 32 53 33 - protected function willFilterPage(array $logs) { 34 - $resource_ids = array_filter(mpull($logs, 'getResourceID')); 35 - if ($resource_ids) { 54 + $resource_phids = array_filter(mpull($logs, 'getResourcePHID')); 55 + if ($resource_phids) { 36 56 $resources = id(new DrydockResourceQuery()) 37 57 ->setParentQuery($this) 38 58 ->setViewer($this->getViewer()) 39 - ->withIDs(array_unique($resource_ids)) 59 + ->withPHIDs($resource_phids) 40 60 ->execute(); 61 + $resources = mpull($resources, null, 'getPHID'); 41 62 } else { 42 63 $resources = array(); 43 64 } 44 65 45 66 foreach ($logs as $key => $log) { 46 67 $resource = null; 47 - if ($log->getResourceID()) { 48 - $resource = idx($resources, $log->getResourceID()); 49 - if (!$resource) { 50 - unset($logs[$key]); 51 - continue; 52 - } 68 + $resource_phid = $log->getResourcePHID(); 69 + if ($resource_phid) { 70 + $resource = idx($resources, $resource_phid); 53 71 } 54 72 $log->attachResource($resource); 55 73 } 56 74 57 - $lease_ids = array_filter(mpull($logs, 'getLeaseID')); 58 - if ($lease_ids) { 75 + $lease_phids = array_filter(mpull($logs, 'getLeasePHID')); 76 + if ($lease_phids) { 59 77 $leases = id(new DrydockLeaseQuery()) 60 78 ->setParentQuery($this) 61 79 ->setViewer($this->getViewer()) 62 - ->withIDs(array_unique($lease_ids)) 80 + ->withPHIDs($lease_phids) 63 81 ->execute(); 82 + $leases = mpull($leases, null, 'getPHID'); 64 83 } else { 65 84 $leases = array(); 66 85 } 67 86 68 87 foreach ($logs as $key => $log) { 69 88 $lease = null; 70 - if ($log->getLeaseID()) { 71 - $lease = idx($leases, $log->getLeaseID()); 72 - if (!$lease) { 73 - unset($logs[$key]); 74 - continue; 75 - } 89 + $lease_phid = $log->getLeasePHID(); 90 + if ($lease_phid) { 91 + $lease = idx($leases, $lease_phid); 76 92 } 77 93 $log->attachLease($lease); 78 94 } 79 95 80 - // These logs are meaningless and their policies aren't computable. They 81 - // shouldn't exist, but throw them away if they do. 82 - foreach ($logs as $key => $log) { 83 - if (!$log->getResource() && !$log->getLease()) { 84 - unset($logs[$key]); 85 - } 86 - } 87 - 88 96 return $logs; 89 97 } 90 98 91 - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { 92 - $where = array(); 99 + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { 100 + $where = parent::buildWhereClauseParts($conn); 93 101 94 - if ($this->resourceIDs !== null) { 102 + if ($this->blueprintPHIDs !== null) { 95 103 $where[] = qsprintf( 96 - $conn_r, 97 - 'resourceID IN (%Ld)', 98 - $this->resourceIDs); 104 + $conn, 105 + 'blueprintPHID IN (%Ls)', 106 + $this->blueprintPHIDs); 99 107 } 100 108 101 - if ($this->leaseIDs !== null) { 109 + if ($this->resourcePHIDs !== null) { 102 110 $where[] = qsprintf( 103 - $conn_r, 104 - 'leaseID IN (%Ld)', 105 - $this->leaseIDs); 111 + $conn, 112 + 'resourcePHID IN (%Ls)', 113 + $this->resourcePHIDs); 106 114 } 107 115 108 - $where[] = $this->buildPagingClause($conn_r); 116 + if ($this->leasePHIDs !== null) { 117 + $where[] = qsprintf( 118 + $conn, 119 + 'leasePHID IN (%Ls)', 120 + $this->leasePHIDs); 121 + } 109 122 110 - return $this->formatWhereClause($where); 123 + return $where; 111 124 } 112 125 113 126 }
+75 -54
src/applications/drydock/query/DrydockLogSearchEngine.php
··· 2 2 3 3 final class DrydockLogSearchEngine extends PhabricatorApplicationSearchEngine { 4 4 5 - public function getResultTypeDescription() { 6 - return pht('Drydock Logs'); 5 + private $blueprint; 6 + private $resource; 7 + private $lease; 8 + 9 + public function setBlueprint(DrydockBlueprint $blueprint) { 10 + $this->blueprint = $blueprint; 11 + return $this; 12 + } 13 + 14 + public function getBlueprint() { 15 + return $this->blueprint; 16 + } 17 + 18 + public function setResource(DrydockResource $resource) { 19 + $this->resource = $resource; 20 + return $this; 21 + } 22 + 23 + public function getResource() { 24 + return $this->resource; 7 25 } 8 26 9 - public function getApplicationClassName() { 10 - return 'PhabricatorDrydockApplication'; 27 + public function setLease(DrydockLease $lease) { 28 + $this->lease = $lease; 29 + return $this; 11 30 } 12 31 13 - public function buildSavedQueryFromRequest(AphrontRequest $request) { 14 - $query = new PhabricatorSavedQuery(); 32 + public function getLease() { 33 + return $this->lease; 34 + } 15 35 16 - $query->setParameter( 17 - 'resourcePHIDs', 18 - $this->readListFromRequest($request, 'resources')); 19 - $query->setParameter( 20 - 'leasePHIDs', 21 - $this->readListFromRequest($request, 'leases')); 36 + public function canUseInPanelContext() { 37 + // Prevent use on Dashboard panels since all log queries currently need a 38 + // parent object and these don't seem particularly useful in any case. 39 + return false; 40 + } 22 41 23 - return $query; 42 + public function getResultTypeDescription() { 43 + return pht('Drydock Logs'); 24 44 } 25 45 26 - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { 27 - $resource_phids = $saved->getParameter('resourcePHIDs', array()); 28 - $lease_phids = $saved->getParameter('leasePHIDs', array()); 46 + public function getApplicationClassName() { 47 + return 'PhabricatorDrydockApplication'; 48 + } 29 49 30 - // TODO: Change logs to use PHIDs instead of IDs. 31 - $resource_ids = array(); 32 - $lease_ids = array(); 50 + public function newQuery() { 51 + $query = new DrydockLogQuery(); 33 52 34 - if ($resource_phids) { 35 - $resource_ids = id(new DrydockResourceQuery()) 36 - ->setViewer(PhabricatorUser::getOmnipotentUser()) 37 - ->withPHIDs($resource_phids) 38 - ->execute(); 39 - $resource_ids = mpull($resource_ids, 'getID'); 53 + $blueprint = $this->getBlueprint(); 54 + if ($blueprint) { 55 + $query->withBlueprintPHIDs(array($blueprint->getPHID())); 40 56 } 41 57 42 - if ($lease_phids) { 43 - $lease_ids = id(new DrydockLeaseQuery()) 44 - ->setViewer(PhabricatorUser::getOmnipotentUser()) 45 - ->withPHIDs($lease_phids) 46 - ->execute(); 47 - $lease_ids = mpull($lease_ids, 'getID'); 58 + $resource = $this->getResource(); 59 + if ($resource) { 60 + $query->withResourcePHIDs(array($resource->getPHID())); 48 61 } 49 62 50 - $query = new DrydockLogQuery(); 51 - if ($resource_ids) { 52 - $query->withResourceIDs($resource_ids); 53 - } 54 - if ($lease_ids) { 55 - $query->withLeaseIDs($lease_ids); 63 + $lease = $this->getLease(); 64 + if ($lease) { 65 + $query->withLeasePHIDs(array($lease->getPHID())); 56 66 } 57 67 58 68 return $query; 59 69 } 60 70 61 - public function buildSearchForm( 62 - AphrontFormView $form, 63 - PhabricatorSavedQuery $saved) { 71 + protected function buildQueryFromParameters(array $map) { 72 + $query = $this->newQuery(); 64 73 65 - $form 66 - ->appendControl( 67 - id(new AphrontFormTokenizerControl()) 68 - ->setDatasource(new DrydockResourceDatasource()) 69 - ->setName('resources') 70 - ->setLabel(pht('Resources')) 71 - ->setValue($saved->getParameter('resourcePHIDs', array()))) 72 - ->appendControl( 73 - id(new AphrontFormTokenizerControl()) 74 - ->setDatasource(new DrydockLeaseDatasource()) 75 - ->setName('leases') 76 - ->setLabel(pht('Leases')) 77 - ->setValue($saved->getParameter('leasePHIDs', array()))); 74 + return $query; 75 + } 76 + 77 + protected function buildCustomSearchFields() { 78 + return array(); 78 79 } 79 80 80 81 protected function getURI($path) { 81 - return '/drydock/log/'.$path; 82 + $blueprint = $this->getBlueprint(); 83 + if ($blueprint) { 84 + $id = $blueprint->getID(); 85 + return "/drydock/blueprint/{$id}/logs/{$path}"; 86 + } 87 + 88 + $resource = $this->getResource(); 89 + if ($resource) { 90 + $id = $resource->getID(); 91 + return "/drydock/resource/{$id}/logs/{$path}"; 92 + } 93 + 94 + $lease = $this->getLease(); 95 + if ($lease) { 96 + $id = $lease->getID(); 97 + return "/drydock/lease/{$id}/logs/{$path}"; 98 + } 99 + 100 + throw new Exception( 101 + pht( 102 + 'Search engine has no blueprint, resource, or lease.')); 82 103 } 83 104 84 105 protected function getBuiltinQueryNames() {
+21
src/applications/drydock/storage/DrydockLease.php
··· 347 347 $viewer = PhabricatorUser::getOmnipotentUser(); 348 348 $need_update = false; 349 349 350 + // TODO: This is just a placeholder to get some data in the table. 351 + $this->logEvent('activated'); 352 + 350 353 $commands = id(new DrydockCommandQuery()) 351 354 ->setViewer($viewer) 352 355 ->withTargetPHIDs(array($this->getPHID())) ··· 370 373 PhabricatorWorker::awakenTaskIDs($awaken_ids); 371 374 } 372 375 } 376 + 377 + public function logEvent($type, array $data = array()) { 378 + $log = id(new DrydockLog()) 379 + ->setEpoch(PhabricatorTime::getNow()) 380 + ->setType($type) 381 + ->setData($data); 382 + 383 + $log->setLeasePHID($this->getPHID()); 384 + 385 + $resource = $this->getResource(); 386 + if ($resource) { 387 + $log->setResourcePHID($resource->getPHID()); 388 + $log->setBlueprintPHID($resource->getBlueprintPHID()); 389 + } 390 + 391 + return $log->save(); 392 + } 393 + 373 394 374 395 375 396 /* -( PhabricatorPolicyInterface )----------------------------------------- */
+52 -19
src/applications/drydock/storage/DrydockLog.php
··· 3 3 final class DrydockLog extends DrydockDAO 4 4 implements PhabricatorPolicyInterface { 5 5 6 - protected $resourceID; 7 - protected $leaseID; 6 + protected $blueprintPHID; 7 + protected $resourcePHID; 8 + protected $leasePHID; 8 9 protected $epoch; 9 - protected $message; 10 + protected $type; 11 + protected $data = array(); 10 12 13 + private $blueprint = self::ATTACHABLE; 11 14 private $resource = self::ATTACHABLE; 12 15 private $lease = self::ATTACHABLE; 13 16 14 17 protected function getConfiguration() { 15 18 return array( 16 19 self::CONFIG_TIMESTAMPS => false, 20 + self::CONFIG_SERIALIZATION => array( 21 + 'data' => self::SERIALIZATION_JSON, 22 + ), 17 23 self::CONFIG_COLUMN_SCHEMA => array( 18 - 'resourceID' => 'id?', 19 - 'leaseID' => 'id?', 20 - 'message' => 'text', 24 + 'blueprintPHID' => 'phid?', 25 + 'resourcePHID' => 'phid?', 26 + 'leasePHID' => 'phid?', 27 + 'type' => 'text64', 21 28 ), 22 29 self::CONFIG_KEY_SCHEMA => array( 23 - 'resourceID' => array( 24 - 'columns' => array('resourceID', 'epoch'), 30 + 'key_blueprint' => array( 31 + 'columns' => array('blueprintPHID', 'type'), 25 32 ), 26 - 'leaseID' => array( 27 - 'columns' => array('leaseID', 'epoch'), 33 + 'key_resource' => array( 34 + 'columns' => array('resourcePHID', 'type'), 35 + ), 36 + 'key_lease' => array( 37 + 'columns' => array('leasePHID', 'type'), 28 38 ), 29 39 'epoch' => array( 30 40 'columns' => array('epoch'), ··· 33 43 ) + parent::getConfiguration(); 34 44 } 35 45 46 + public function attachBlueprint(DrydockBlueprint $blueprint = null) { 47 + $this->blueprint = $blueprint; 48 + return $this; 49 + } 50 + 51 + public function getBlueprint() { 52 + return $this->assertAttached($this->blueprint); 53 + } 54 + 36 55 public function attachResource(DrydockResource $resource = null) { 37 56 $this->resource = $resource; 38 57 return $this; ··· 51 70 return $this->assertAttached($this->lease); 52 71 } 53 72 73 + public function isComplete() { 74 + if ($this->getBlueprintPHID() && !$this->getBlueprint()) { 75 + return false; 76 + } 77 + 78 + if ($this->getResourcePHID() && !$this->getResource()) { 79 + return false; 80 + } 81 + 82 + if ($this->getLeasePHID() && !$this->getLease()) { 83 + return false; 84 + } 85 + 86 + return true; 87 + } 88 + 54 89 55 90 /* -( PhabricatorPolicyInterface )----------------------------------------- */ 56 91 ··· 62 97 } 63 98 64 99 public function getPolicy($capability) { 65 - if ($this->getResource()) { 66 - return $this->getResource()->getPolicy($capability); 67 - } 68 - return $this->getLease()->getPolicy($capability); 100 + // NOTE: We let you see that logs exist no matter what, but don't actually 101 + // show you log content unless you can see all of the associated objects. 102 + return PhabricatorPolicies::getMostOpenPolicy(); 69 103 } 70 104 71 105 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 72 - if ($this->getResource()) { 73 - return $this->getResource()->hasAutomaticCapability($capability, $viewer); 74 - } 75 - return $this->getLease()->hasAutomaticCapability($capability, $viewer); 106 + return false; 76 107 } 77 108 78 109 public function describeAutomaticCapability($capability) { 79 - return pht('Logs inherit the policy of their resources.'); 110 + return pht( 111 + 'To view log details, you must be able to view the associated '. 112 + 'blueprint, resource and lease.'); 80 113 } 81 114 82 115 }
+40 -26
src/applications/drydock/view/DrydockLogListView.php
··· 18 18 19 19 $rows = array(); 20 20 foreach ($logs as $log) { 21 - $resource_uri = '/drydock/resource/'.$log->getResourceID().'/'; 22 - $lease_uri = '/drydock/lease/'.$log->getLeaseID().'/'; 21 + $blueprint_phid = $log->getBlueprintPHID(); 22 + if ($blueprint_phid) { 23 + $blueprint = $viewer->renderHandle($blueprint_phid); 24 + } else { 25 + $blueprint = null; 26 + } 27 + 28 + $resource_phid = $log->getResourcePHID(); 29 + if ($resource_phid) { 30 + $resource = $viewer->renderHandle($resource_phid); 31 + } else { 32 + $resource = null; 33 + } 23 34 24 - $resource_name = $log->getResourceID(); 25 - if ($log->getResourceID() !== null) { 26 - $resource_name = $log->getResource()->getName(); 35 + $lease_phid = $log->getLeasePHID(); 36 + if ($lease_phid) { 37 + $lease = $viewer->renderHandle($lease_phid); 38 + } else { 39 + $lease = null; 40 + } 41 + 42 + if ($log->isComplete()) { 43 + // TODO: This is a placeholder. 44 + $type = $log->getType(); 45 + $data = print_r($log->getData(), true); 46 + } else { 47 + $type = phutil_tag('em', array(), pht('Restricted')); 48 + $data = phutil_tag( 49 + 'em', 50 + array(), 51 + pht('You do not have permission to view this log event.')); 27 52 } 28 53 29 54 $rows[] = array( 30 - phutil_tag( 31 - 'a', 32 - array( 33 - 'href' => $resource_uri, 34 - ), 35 - $resource_name), 36 - phutil_tag( 37 - 'a', 38 - array( 39 - 'href' => $lease_uri, 40 - ), 41 - $log->getLeaseID()), 42 - $log->getMessage(), 55 + $blueprint, 56 + $resource, 57 + $lease, 58 + $type, 59 + $data, 43 60 phabricator_datetime($log->getEpoch(), $viewer), 44 61 ); 45 62 } ··· 48 65 $table->setDeviceReadyTable(true); 49 66 $table->setHeaders( 50 67 array( 68 + pht('Blueprint'), 51 69 pht('Resource'), 52 70 pht('Lease'), 53 - pht('Message'), 71 + pht('Type'), 72 + pht('Data'), 54 73 pht('Date'), 55 74 )); 56 - $table->setShortHeaders( 57 - array( 58 - pht('R'), 59 - pht('L'), 60 - pht('Message'), 61 - '', 62 - )); 63 75 $table->setColumnClasses( 64 76 array( 77 + '', 78 + '', 65 79 '', 66 80 '', 67 81 'wide',