1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-19 13:22:42 +01:00

Allow Almanac Devices and Bindings to have properties

Summary:
Ref T5833. Adds support for arbitrary properites to Almanac devices and bindings.

  - For Devices, this allows you to maybe mark what `rack` a server is on, the `serial` number of a router, etc.
  - For Bindings, this allows you to maybe mark that a bound device is `active`, provide `credentials`, expose it as `readonly`, etc.

Test Plan: Added properties to Devices and Bindings.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T5833

Differential Revision: https://secure.phabricator.com/D10781
This commit is contained in:
epriestley 2014-11-05 15:28:36 -08:00
parent 2f1b5ae010
commit fcad9435ea
12 changed files with 249 additions and 61 deletions

View file

@ -65,6 +65,7 @@ phutil_register_library_map(array(
'AlmanacPropertyEditController' => 'applications/almanac/controller/AlmanacPropertyEditController.php', 'AlmanacPropertyEditController' => 'applications/almanac/controller/AlmanacPropertyEditController.php',
'AlmanacPropertyInterface' => 'applications/almanac/property/AlmanacPropertyInterface.php', 'AlmanacPropertyInterface' => 'applications/almanac/property/AlmanacPropertyInterface.php',
'AlmanacPropertyQuery' => 'applications/almanac/query/AlmanacPropertyQuery.php', 'AlmanacPropertyQuery' => 'applications/almanac/query/AlmanacPropertyQuery.php',
'AlmanacQuery' => 'applications/almanac/query/AlmanacQuery.php',
'AlmanacService' => 'applications/almanac/storage/AlmanacService.php', 'AlmanacService' => 'applications/almanac/storage/AlmanacService.php',
'AlmanacServiceController' => 'applications/almanac/controller/AlmanacServiceController.php', 'AlmanacServiceController' => 'applications/almanac/controller/AlmanacServiceController.php',
'AlmanacServiceEditController' => 'applications/almanac/controller/AlmanacServiceEditController.php', 'AlmanacServiceEditController' => 'applications/almanac/controller/AlmanacServiceEditController.php',
@ -2972,11 +2973,14 @@ phutil_register_library_map(array(
'AlmanacBinding' => array( 'AlmanacBinding' => array(
'AlmanacDAO', 'AlmanacDAO',
'PhabricatorPolicyInterface', 'PhabricatorPolicyInterface',
'PhabricatorCustomFieldInterface',
'PhabricatorApplicationTransactionInterface',
'AlmanacPropertyInterface',
), ),
'AlmanacBindingEditController' => 'AlmanacServiceController', 'AlmanacBindingEditController' => 'AlmanacServiceController',
'AlmanacBindingEditor' => 'PhabricatorApplicationTransactionEditor', 'AlmanacBindingEditor' => 'PhabricatorApplicationTransactionEditor',
'AlmanacBindingPHIDType' => 'PhabricatorPHIDType', 'AlmanacBindingPHIDType' => 'PhabricatorPHIDType',
'AlmanacBindingQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'AlmanacBindingQuery' => 'AlmanacQuery',
'AlmanacBindingTableView' => 'AphrontView', 'AlmanacBindingTableView' => 'AphrontView',
'AlmanacBindingTransaction' => 'PhabricatorApplicationTransaction', 'AlmanacBindingTransaction' => 'PhabricatorApplicationTransaction',
'AlmanacBindingTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacBindingTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
@ -2996,13 +3000,16 @@ phutil_register_library_map(array(
'AlmanacDevice' => array( 'AlmanacDevice' => array(
'AlmanacDAO', 'AlmanacDAO',
'PhabricatorPolicyInterface', 'PhabricatorPolicyInterface',
'PhabricatorCustomFieldInterface',
'PhabricatorApplicationTransactionInterface',
'AlmanacPropertyInterface',
), ),
'AlmanacDeviceController' => 'AlmanacController', 'AlmanacDeviceController' => 'AlmanacController',
'AlmanacDeviceEditController' => 'AlmanacDeviceController', 'AlmanacDeviceEditController' => 'AlmanacDeviceController',
'AlmanacDeviceEditor' => 'PhabricatorApplicationTransactionEditor', 'AlmanacDeviceEditor' => 'PhabricatorApplicationTransactionEditor',
'AlmanacDeviceListController' => 'AlmanacDeviceController', 'AlmanacDeviceListController' => 'AlmanacDeviceController',
'AlmanacDevicePHIDType' => 'PhabricatorPHIDType', 'AlmanacDevicePHIDType' => 'PhabricatorPHIDType',
'AlmanacDeviceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'AlmanacDeviceQuery' => 'AlmanacQuery',
'AlmanacDeviceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'AlmanacDeviceSearchEngine' => 'PhabricatorApplicationSearchEngine',
'AlmanacDeviceTransaction' => 'PhabricatorApplicationTransaction', 'AlmanacDeviceTransaction' => 'PhabricatorApplicationTransaction',
'AlmanacDeviceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacDeviceTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
@ -3041,6 +3048,7 @@ phutil_register_library_map(array(
'AlmanacPropertyController' => 'AlmanacController', 'AlmanacPropertyController' => 'AlmanacController',
'AlmanacPropertyEditController' => 'AlmanacDeviceController', 'AlmanacPropertyEditController' => 'AlmanacDeviceController',
'AlmanacPropertyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'AlmanacPropertyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'AlmanacQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'AlmanacService' => array( 'AlmanacService' => array(
'AlmanacDAO', 'AlmanacDAO',
'PhabricatorPolicyInterface', 'PhabricatorPolicyInterface',
@ -3053,7 +3061,7 @@ phutil_register_library_map(array(
'AlmanacServiceEditor' => 'PhabricatorApplicationTransactionEditor', 'AlmanacServiceEditor' => 'PhabricatorApplicationTransactionEditor',
'AlmanacServiceListController' => 'AlmanacServiceController', 'AlmanacServiceListController' => 'AlmanacServiceController',
'AlmanacServicePHIDType' => 'PhabricatorPHIDType', 'AlmanacServicePHIDType' => 'PhabricatorPHIDType',
'AlmanacServiceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'AlmanacServiceQuery' => 'AlmanacQuery',
'AlmanacServiceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'AlmanacServiceSearchEngine' => 'PhabricatorApplicationSearchEngine',
'AlmanacServiceTransaction' => 'PhabricatorApplicationTransaction', 'AlmanacServiceTransaction' => 'PhabricatorApplicationTransaction',
'AlmanacServiceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacServiceTransactionQuery' => 'PhabricatorApplicationTransactionQuery',

View file

@ -57,6 +57,7 @@ final class AlmanacBindingViewController
array( array(
$crumbs, $crumbs,
$box, $box,
$this->buildAlmanacPropertiesTable($binding),
$xaction_view, $xaction_view,
), ),
array( array(

View file

@ -3,14 +3,11 @@
abstract class AlmanacController abstract class AlmanacController
extends PhabricatorController { extends PhabricatorController {
protected function buildAlmanacPropertiesTable(
AlmanacPropertyInterface $object) {
protected function buildAlmanacPropertiesTable($object) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$properties = $object->getAlmanacProperties();
$properties = id(new AlmanacPropertyQuery())
->setViewer($viewer)
->withObjectPHIDs(array($object->getPHID()))
->execute();
$rows = array(); $rows = array();
foreach ($properties as $property) { foreach ($properties as $property) {

View file

@ -56,6 +56,7 @@ final class AlmanacDeviceViewController
$crumbs, $crumbs,
$box, $box,
$interfaces, $interfaces,
$this->buildAlmanacPropertiesTable($device),
$xaction_view, $xaction_view,
), ),
array( array(

View file

@ -15,7 +15,6 @@ final class AlmanacServiceViewController
$service = id(new AlmanacServiceQuery()) $service = id(new AlmanacServiceQuery())
->setViewer($viewer) ->setViewer($viewer)
->withNames(array($name)) ->withNames(array($name))
->needProperties(true)
->executeOne(); ->executeOne();
if (!$service) { if (!$service) {
return new Aphront404Response(); return new Aphront404Response();

View file

@ -1,7 +1,7 @@
<?php <?php
final class AlmanacBindingQuery final class AlmanacBindingQuery
extends PhabricatorCursorPagedPolicyAwareQuery { extends AlmanacQuery {
private $ids; private $ids;
private $phids; private $phids;
@ -136,8 +136,4 @@ final class AlmanacBindingQuery
return $this->formatWhereClause($where); return $this->formatWhereClause($where);
} }
public function getQueryApplicationClass() {
return 'PhabricatorAlmanacApplication';
}
} }

View file

@ -1,7 +1,7 @@
<?php <?php
final class AlmanacDeviceQuery final class AlmanacDeviceQuery
extends PhabricatorCursorPagedPolicyAwareQuery { extends AlmanacQuery {
private $ids; private $ids;
private $phids; private $phids;

View file

@ -3,8 +3,15 @@
final class AlmanacPropertyQuery final class AlmanacPropertyQuery
extends PhabricatorCursorPagedPolicyAwareQuery { extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $objectPHIDs; private $objectPHIDs;
private $names; private $names;
private $disablePolicyFilteringAndAttachment;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withObjectPHIDs(array $phids) { public function withObjectPHIDs(array $phids) {
$this->phids = $phids; $this->phids = $phids;
@ -16,6 +23,15 @@ final class AlmanacPropertyQuery
return $this; return $this;
} }
public function setDisablePolicyFilteringAndAttachment($disable) {
$this->disablePolicyFilteringAndAttachment = $disable;
return $this;
}
protected function shouldDisablePolicyFiltering() {
return $this->disablePolicyFilteringAndAttachment;
}
protected function loadPage() { protected function loadPage() {
$table = new AlmanacProperty(); $table = new AlmanacProperty();
$conn_r = $table->establishConnection('r'); $conn_r = $table->establishConnection('r');
@ -32,22 +48,24 @@ final class AlmanacPropertyQuery
} }
protected function willFilterPage(array $properties) { protected function willFilterPage(array $properties) {
$object_phids = mpull($properties, 'getObjectPHID'); if (!$this->disablePolicyFilteringAndAttachment) {
$object_phids = mpull($properties, 'getObjectPHID');
$objects = id(new PhabricatorObjectQuery()) $objects = id(new PhabricatorObjectQuery())
->setViewer($this->getViewer()) ->setViewer($this->getViewer())
->setParentQuery($this) ->setParentQuery($this)
->withPHIDs($object_phids) ->withPHIDs($object_phids)
->execute(); ->execute();
$objects = mpull($objects, null, 'getPHID'); $objects = mpull($objects, null, 'getPHID');
foreach ($properties as $key => $property) { foreach ($properties as $key => $property) {
$object = idx($objects, $property->getObjectPHID()); $object = idx($objects, $property->getObjectPHID());
if (!$object) { if (!$object) {
unset($properties[$key]); unset($properties[$key]);
continue; continue;
}
$property->attachObject($object);
} }
$property->attachObject($object);
} }
return $properties; return $properties;
@ -56,6 +74,13 @@ final class AlmanacPropertyQuery
protected function buildWhereClause($conn_r) { protected function buildWhereClause($conn_r) {
$where = array(); $where = array();
if ($this->ids !== null) {
$where[] = qsprintf(
$conn_r,
'id IN (%Ld)',
$this->ids);
}
if ($this->objectPHIDs !== null) { if ($this->objectPHIDs !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn_r,

View file

@ -0,0 +1,41 @@
<?php
abstract class AlmanacQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
protected function didFilterPage(array $objects) {
if (head($objects) instanceof AlmanacPropertyInterface) {
// NOTE: We load properties unconditionally because CustomField assumes
// it can always generate a list of fields on an object. It may make
// sense to re-examine that assumption eventually.
$property_query = id(new AlmanacPropertyQuery())
->setViewer($this->getViewer())
->setParentQuery($this)
->withObjectPHIDs(mpull($objects, null, 'getPHID'));
// NOTE: We disable policy filtering and object attachment to avoid
// a cyclic dependency where objects need their properties and properties
// need their objects. We'll attach the objects below, and have already
// implicitly checked the necessary policies.
$property_query->setDisablePolicyFilteringAndAttachment(true);
$properties = $property_query->execute();
$properties = mgroup($properties, 'getObjectPHID');
foreach ($objects as $object) {
$object_properties = idx($properties, $object->getPHID(), array());
foreach ($object_properties as $property) {
$property->attachObject($object);
}
$object->attachAlmanacProperties($object_properties);
}
}
return $objects;
}
public function getQueryApplicationClass() {
return 'PhabricatorAlmanacApplication';
}
}

View file

@ -1,12 +1,11 @@
<?php <?php
final class AlmanacServiceQuery final class AlmanacServiceQuery
extends PhabricatorCursorPagedPolicyAwareQuery { extends AlmanacQuery {
private $ids; private $ids;
private $phids; private $phids;
private $names; private $names;
private $needProperties;
public function withIDs(array $ids) { public function withIDs(array $ids) {
$this->ids = $ids; $this->ids = $ids;
@ -23,11 +22,6 @@ final class AlmanacServiceQuery
return $this; return $this;
} }
public function needProperties($need) {
$this->needProperties = $need;
return $this;
}
protected function loadPage() { protected function loadPage() {
$table = new AlmanacService(); $table = new AlmanacService();
$conn_r = $table->establishConnection('r'); $conn_r = $table->establishConnection('r');
@ -77,27 +71,4 @@ final class AlmanacServiceQuery
return $this->formatWhereClause($where); return $this->formatWhereClause($where);
} }
protected function didFilterPage(array $services) {
// NOTE: We load properties unconditionally because CustomField assumes
// it can always generate a list of fields on an object. It may make
// sense to re-examine that assumption eventually.
$properties = id(new AlmanacPropertyQuery())
->setViewer($this->getViewer())
->setParentQuery($this)
->withObjectPHIDs(mpull($services, null, 'getPHID'))
->execute();
$properties = mgroup($properties, 'getObjectPHID');
foreach ($services as $service) {
$service_properties = idx($properties, $service->getPHID(), array());
$service->attachAlmanacProperties($service_properties);
}
return $services;
}
public function getQueryApplicationClass() {
return 'PhabricatorAlmanacApplication';
}
} }

View file

@ -2,7 +2,11 @@
final class AlmanacBinding final class AlmanacBinding
extends AlmanacDAO extends AlmanacDAO
implements PhabricatorPolicyInterface { implements
PhabricatorPolicyInterface,
PhabricatorCustomFieldInterface,
PhabricatorApplicationTransactionInterface,
AlmanacPropertyInterface {
protected $servicePHID; protected $servicePHID;
protected $devicePHID; protected $devicePHID;
@ -12,6 +16,8 @@ final class AlmanacBinding
private $service = self::ATTACHABLE; private $service = self::ATTACHABLE;
private $device = self::ATTACHABLE; private $device = self::ATTACHABLE;
private $interface = self::ATTACHABLE; private $interface = self::ATTACHABLE;
private $customFields = self::ATTACHABLE;
private $almanacProperties = self::ATTACHABLE;
public static function initializeNewBinding(AlmanacService $service) { public static function initializeNewBinding(AlmanacService $service) {
return id(new AlmanacBinding()) return id(new AlmanacBinding())
@ -82,6 +88,37 @@ final class AlmanacBinding
} }
/* -( AlmanacPropertyInterface )------------------------------------------- */
public function attachAlmanacProperties(array $properties) {
assert_instances_of($properties, 'AlmanacProperty');
$this->almanacProperties = mpull($properties, null, 'getFieldName');
return $this;
}
public function getAlmanacProperties() {
return $this->assertAttached($this->almanacProperties);
}
public function hasAlmanacProperty($key) {
$this->assertAttached($this->almanacProperties);
return isset($this->almanacProperties[$key]);
}
public function getAlmanacProperty($key) {
return $this->assertAttachedKey($this->almanacProperties, $key);
}
public function getAlmanacPropertyValue($key, $default = null) {
if ($this->hasAlmanacProperty($key)) {
return $this->getAlmanacProperty($key)->getFieldValue();
} else {
return $default;
}
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */
@ -109,4 +146,41 @@ final class AlmanacBinding
); );
} }
/* -( PhabricatorCustomFieldInterface )------------------------------------ */
public function getCustomFieldSpecificationForRole($role) {
return array();
}
public function getCustomFieldBaseClass() {
return 'AlmanacCustomField';
}
public function getCustomFields() {
return $this->assertAttached($this->customFields);
}
public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) {
$this->customFields = $fields;
return $this;
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new AlmanacBindingEditor();
}
public function getApplicationTransactionObject() {
return $this;
}
public function getApplicationTransactionTemplate() {
return new AlmanacBindingTransaction();
}
} }

View file

@ -2,7 +2,11 @@
final class AlmanacDevice final class AlmanacDevice
extends AlmanacDAO extends AlmanacDAO
implements PhabricatorPolicyInterface { implements
PhabricatorPolicyInterface,
PhabricatorCustomFieldInterface,
PhabricatorApplicationTransactionInterface,
AlmanacPropertyInterface {
protected $name; protected $name;
protected $nameIndex; protected $nameIndex;
@ -10,6 +14,9 @@ final class AlmanacDevice
protected $viewPolicy; protected $viewPolicy;
protected $editPolicy; protected $editPolicy;
private $customFields = self::ATTACHABLE;
private $almanacProperties = self::ATTACHABLE;
public static function initializeNewDevice() { public static function initializeNewDevice() {
return id(new AlmanacDevice()) return id(new AlmanacDevice())
->setViewPolicy(PhabricatorPolicies::POLICY_USER) ->setViewPolicy(PhabricatorPolicies::POLICY_USER)
@ -57,6 +64,37 @@ final class AlmanacDevice
} }
/* -( AlmanacPropertyInterface )------------------------------------------- */
public function attachAlmanacProperties(array $properties) {
assert_instances_of($properties, 'AlmanacProperty');
$this->almanacProperties = mpull($properties, null, 'getFieldName');
return $this;
}
public function getAlmanacProperties() {
return $this->assertAttached($this->almanacProperties);
}
public function hasAlmanacProperty($key) {
$this->assertAttached($this->almanacProperties);
return isset($this->almanacProperties[$key]);
}
public function getAlmanacProperty($key) {
return $this->assertAttachedKey($this->almanacProperties, $key);
}
public function getAlmanacPropertyValue($key, $default = null) {
if ($this->hasAlmanacProperty($key)) {
return $this->getAlmanacProperty($key)->getFieldValue();
} else {
return $default;
}
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */
@ -84,4 +122,41 @@ final class AlmanacDevice
return null; return null;
} }
/* -( PhabricatorCustomFieldInterface )------------------------------------ */
public function getCustomFieldSpecificationForRole($role) {
return array();
}
public function getCustomFieldBaseClass() {
return 'AlmanacCustomField';
}
public function getCustomFields() {
return $this->assertAttached($this->customFields);
}
public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) {
$this->customFields = $fields;
return $this;
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new AlmanacDeviceEditor();
}
public function getApplicationTransactionObject() {
return $this;
}
public function getApplicationTransactionTemplate() {
return new AlmanacDeviceTransaction();
}
} }