Page MenuHomePhabricator

D10745.diff
No OneTemporary

D10745.diff

diff --git a/resources/sql/autopatches/20141017.almanac.binding.sql b/resources/sql/autopatches/20141017.almanac.binding.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20141017.almanac.binding.sql
@@ -0,0 +1,14 @@
+CREATE TABLE {$NAMESPACE}_almanac.almanac_binding (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ phid VARBINARY(64) NOT NULL,
+ servicePHID VARBINARY(64) NOT NULL,
+ devicePHID VARBINARY(64) NOT NULL,
+ interfacePHID VARBINARY(64) NOT NULL,
+ mailKey BINARY(20) NOT NULL,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ UNIQUE KEY `key_phid` (phid),
+ UNIQUE KEY `key_service` (servicePHID, interfacePHID),
+ KEY `key_device` (devicePHID),
+ KEY `key_interface` (interfacePHID)
+) ENGINE=InnoDB, COLLATE utf8_general_ci;
diff --git a/resources/sql/autopatches/20141017.almanac.bxaction.sql b/resources/sql/autopatches/20141017.almanac.bxaction.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20141017.almanac.bxaction.sql
@@ -0,0 +1,19 @@
+CREATE TABLE {$NAMESPACE}_almanac.almanac_bindingtransaction (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ phid VARCHAR(64) COLLATE utf8_bin NOT NULL,
+ authorPHID VARCHAR(64) COLLATE utf8_bin NOT NULL,
+ objectPHID VARCHAR(64) COLLATE utf8_bin NOT NULL,
+ viewPolicy VARCHAR(64) COLLATE utf8_bin NOT NULL,
+ editPolicy VARCHAR(64) COLLATE utf8_bin NOT NULL,
+ commentPHID VARCHAR(64) COLLATE utf8_bin DEFAULT NULL,
+ commentVersion INT UNSIGNED NOT NULL,
+ transactionType VARCHAR(32) COLLATE utf8_bin NOT NULL,
+ oldValue LONGTEXT COLLATE utf8_bin NOT NULL,
+ newValue LONGTEXT COLLATE utf8_bin NOT NULL,
+ contentSource LONGTEXT COLLATE utf8_bin NOT NULL,
+ metadata LONGTEXT COLLATE utf8_bin NOT NULL,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ UNIQUE KEY `key_phid` (`phid`),
+ KEY `key_object` (`objectPHID`)
+) ENGINE=InnoDB, COLLATE utf8_general_ci;
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -10,6 +10,15 @@
'__library_version__' => 2,
'class' => array(
'AlmanacAddress' => 'applications/almanac/util/AlmanacAddress.php',
+ 'AlmanacBinding' => 'applications/almanac/storage/AlmanacBinding.php',
+ 'AlmanacBindingEditController' => 'applications/almanac/controller/AlmanacBindingEditController.php',
+ 'AlmanacBindingEditor' => 'applications/almanac/editor/AlmanacBindingEditor.php',
+ 'AlmanacBindingPHIDType' => 'applications/almanac/phid/AlmanacBindingPHIDType.php',
+ 'AlmanacBindingQuery' => 'applications/almanac/query/AlmanacBindingQuery.php',
+ 'AlmanacBindingTableView' => 'applications/almanac/view/AlmanacBindingTableView.php',
+ 'AlmanacBindingTransaction' => 'applications/almanac/storage/AlmanacBindingTransaction.php',
+ 'AlmanacBindingTransactionQuery' => 'applications/almanac/query/AlmanacBindingTransactionQuery.php',
+ 'AlmanacBindingViewController' => 'applications/almanac/controller/AlmanacBindingViewController.php',
'AlmanacConduitUtil' => 'applications/almanac/util/AlmanacConduitUtil.php',
'AlmanacConsoleController' => 'applications/almanac/controller/AlmanacConsoleController.php',
'AlmanacController' => 'applications/almanac/controller/AlmanacController.php',
@@ -30,6 +39,7 @@
'AlmanacDeviceTransactionQuery' => 'applications/almanac/query/AlmanacDeviceTransactionQuery.php',
'AlmanacDeviceViewController' => 'applications/almanac/controller/AlmanacDeviceViewController.php',
'AlmanacInterface' => 'applications/almanac/storage/AlmanacInterface.php',
+ 'AlmanacInterfaceDatasource' => 'applications/almanac/typeahead/AlmanacInterfaceDatasource.php',
'AlmanacInterfaceEditController' => 'applications/almanac/controller/AlmanacInterfaceEditController.php',
'AlmanacInterfacePHIDType' => 'applications/almanac/phid/AlmanacInterfacePHIDType.php',
'AlmanacInterfaceQuery' => 'applications/almanac/query/AlmanacInterfaceQuery.php',
@@ -2947,6 +2957,18 @@
),
'xmap' => array(
'AlmanacAddress' => 'Phobject',
+ 'AlmanacBinding' => array(
+ 'AlmanacDAO',
+ 'PhabricatorPolicyInterface',
+ ),
+ 'AlmanacBindingEditController' => 'AlmanacServiceController',
+ 'AlmanacBindingEditor' => 'PhabricatorApplicationTransactionEditor',
+ 'AlmanacBindingPHIDType' => 'PhabricatorPHIDType',
+ 'AlmanacBindingQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'AlmanacBindingTableView' => 'AphrontView',
+ 'AlmanacBindingTransaction' => 'PhabricatorApplicationTransaction',
+ 'AlmanacBindingTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+ 'AlmanacBindingViewController' => 'AlmanacServiceController',
'AlmanacConduitUtil' => 'Phobject',
'AlmanacConsoleController' => 'AlmanacController',
'AlmanacController' => 'PhabricatorController',
@@ -2973,6 +2995,7 @@
'AlmanacDAO',
'PhabricatorPolicyInterface',
),
+ 'AlmanacInterfaceDatasource' => 'PhabricatorTypeaheadDatasource',
'AlmanacInterfaceEditController' => 'AlmanacDeviceController',
'AlmanacInterfacePHIDType' => 'PhabricatorPHIDType',
'AlmanacInterfaceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
diff --git a/src/applications/almanac/application/PhabricatorAlmanacApplication.php b/src/applications/almanac/application/PhabricatorAlmanacApplication.php
--- a/src/applications/almanac/application/PhabricatorAlmanacApplication.php
+++ b/src/applications/almanac/application/PhabricatorAlmanacApplication.php
@@ -47,6 +47,10 @@
'interface/' => array(
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacInterfaceEditController',
),
+ 'binding/' => array(
+ 'edit/(?:(?P<id>\d+)/)?' => 'AlmanacBindingEditController',
+ '(?P<id>\d+)/' => 'AlmanacBindingViewController',
+ ),
'network/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'AlmanacNetworkListController',
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacNetworkEditController',
diff --git a/src/applications/almanac/controller/AlmanacBindingEditController.php b/src/applications/almanac/controller/AlmanacBindingEditController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/controller/AlmanacBindingEditController.php
@@ -0,0 +1,128 @@
+<?php
+
+final class AlmanacBindingEditController
+ extends AlmanacServiceController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+
+ $id = $request->getURIData('id');
+ if ($id) {
+ $binding = id(new AlmanacBindingQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$binding) {
+ return new Aphront404Response();
+ }
+
+ $service = $binding->getService();
+ $is_new = false;
+
+ $service_uri = $service->getURI();
+ $cancel_uri = $binding->getURI();
+ $title = pht('Edit Binding');
+ $save_button = pht('Save Changes');
+ } else {
+ $service = id(new AlmanacServiceQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($request->getStr('serviceID')))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+
+ $binding = AlmanacBinding::initializeNewBinding($service);
+ $is_new = true;
+
+ $service_uri = $service->getURI();
+ $cancel_uri = $service_uri;
+ $title = pht('Create Binding');
+ $save_button = pht('Create Binding');
+ }
+
+ $v_interface = array();
+ if ($binding->getInterfacePHID()) {
+ $v_interface = array($binding->getInterfacePHID());
+ }
+ $e_interface = true;
+
+ $validation_exception = null;
+ if ($request->isFormPost()) {
+ $v_interface = $request->getArr('interfacePHIDs');
+
+ $type_interface = AlmanacBindingTransaction::TYPE_INTERFACE;
+
+ $xactions = array();
+
+ $xactions[] = id(new AlmanacBindingTransaction())
+ ->setTransactionType($type_interface)
+ ->setNewValue(head($v_interface));
+
+ $editor = id(new AlmanacBindingEditor())
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true);
+
+ try {
+ $editor->applyTransactions($binding, $xactions);
+
+ $binding_uri = $binding->getURI();
+ return id(new AphrontRedirectResponse())->setURI($binding_uri);
+ } catch (PhabricatorApplicationTransactionValidationException $ex) {
+ $validation_exception = $ex;
+ $e_interface = $ex->getShortMessage($type_interface);
+ }
+ }
+
+ $interface_handles = array();
+ if ($v_interface) {
+ $interface_handles = $this->loadViewerHandles($v_interface);
+ }
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer)
+ ->appendChild(
+ id(new AphrontFormTokenizerControl())
+ ->setName('interfacePHIDs')
+ ->setLabel('Interface')
+ ->setLimit(1)
+ ->setDatasource(new AlmanacInterfaceDatasource())
+ ->setValue($interface_handles)
+ ->setError($e_interface))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->addCancelButton($cancel_uri)
+ ->setValue($save_button));
+
+ $box = id(new PHUIObjectBoxView())
+ ->setValidationException($validation_exception)
+ ->setHeaderText($title)
+ ->appendChild($form);
+
+ $crumbs = $this->buildApplicationCrumbs();
+ $crumbs->addTextCrumb($service->getName(), $service_uri);
+ if ($is_new) {
+ $crumbs->addTextCrumb(pht('Create Binding'));
+ } else {
+ $crumbs->addTextCrumb(pht('Edit Binding'));
+ }
+
+ return $this->buildApplicationPage(
+ array(
+ $crumbs,
+ $box,
+ ),
+ array(
+ 'title' => $title,
+ ));
+ }
+
+}
diff --git a/src/applications/almanac/controller/AlmanacBindingViewController.php b/src/applications/almanac/controller/AlmanacBindingViewController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/controller/AlmanacBindingViewController.php
@@ -0,0 +1,122 @@
+<?php
+
+final class AlmanacBindingViewController
+ extends AlmanacServiceController {
+
+ public function shouldAllowPublic() {
+ return true;
+ }
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+
+ $id = $request->getURIData('id');
+
+ $binding = id(new AlmanacBindingQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->executeOne();
+ if (!$binding) {
+ return new Aphront404Response();
+ }
+
+ $service = $binding->getService();
+ $service_uri = $service->getURI();
+
+ $title = pht('Binding %s', $binding->getID());
+
+ $property_list = $this->buildPropertyList($binding);
+ $action_list = $this->buildActionList($binding);
+ $property_list->setActionList($action_list);
+
+ $header = id(new PHUIHeaderView())
+ ->setUser($viewer)
+ ->setHeader($title)
+ ->setPolicyObject($binding);
+
+ $box = id(new PHUIObjectBoxView())
+ ->setHeader($header)
+ ->addPropertyList($property_list);
+
+ $crumbs = $this->buildApplicationCrumbs();
+ $crumbs->addTextCrumb($service->getName(), $service_uri);
+ $crumbs->addTextCrumb($title);
+
+ $xactions = id(new AlmanacBindingTransactionQuery())
+ ->setViewer($viewer)
+ ->withObjectPHIDs(array($binding->getPHID()))
+ ->execute();
+
+ $xaction_view = id(new PhabricatorApplicationTransactionView())
+ ->setUser($viewer)
+ ->setObjectPHID($binding->getPHID())
+ ->setTransactions($xactions)
+ ->setShouldTerminate(true);
+
+ return $this->buildApplicationPage(
+ array(
+ $crumbs,
+ $box,
+ $xaction_view,
+ ),
+ array(
+ 'title' => $title,
+ ));
+ }
+
+ private function buildPropertyList(AlmanacBinding $binding) {
+ $viewer = $this->getViewer();
+
+ $properties = id(new PHUIPropertyListView())
+ ->setUser($viewer);
+
+ $handles = $this->loadViewerHandles(
+ array(
+ $binding->getServicePHID(),
+ $binding->getDevicePHID(),
+ $binding->getInterface()->getNetworkPHID(),
+ ));
+
+ $properties->addProperty(
+ pht('Service'),
+ $handles[$binding->getServicePHID()]->renderLink());
+
+ $properties->addProperty(
+ pht('Device'),
+ $handles[$binding->getDevicePHID()]->renderLink());
+
+ $properties->addProperty(
+ pht('Network'),
+ $handles[$binding->getInterface()->getNetworkPHID()]->renderLink());
+
+ $properties->addProperty(
+ pht('Interface'),
+ $binding->getInterface()->renderDisplayAddress());
+
+ return $properties;
+ }
+
+ private function buildActionList(AlmanacBinding $binding) {
+ $viewer = $this->getViewer();
+ $id = $binding->getID();
+
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $binding,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
+ $actions = id(new PhabricatorActionListView())
+ ->setUser($viewer);
+
+ $actions->addAction(
+ id(new PhabricatorActionView())
+ ->setIcon('fa-pencil')
+ ->setName(pht('Edit Binding'))
+ ->setHref($this->getApplicationURI("binding/edit/{$id}/"))
+ ->setWorkflow(!$can_edit)
+ ->setDisabled(!$can_edit));
+
+ return $actions;
+ }
+
+}
diff --git a/src/applications/almanac/controller/AlmanacServiceViewController.php b/src/applications/almanac/controller/AlmanacServiceViewController.php
--- a/src/applications/almanac/controller/AlmanacServiceViewController.php
+++ b/src/applications/almanac/controller/AlmanacServiceViewController.php
@@ -35,6 +35,8 @@
->setHeader($header)
->addPropertyList($property_list);
+ $bindings = $this->buildBindingList($service);
+
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($service->getName());
@@ -53,6 +55,7 @@
array(
$crumbs,
$box,
+ $bindings,
$xaction_view,
),
array(
@@ -92,4 +95,51 @@
return $actions;
}
+ private function buildBindingList(AlmanacService $service) {
+ $viewer = $this->getViewer();
+ $id = $service->getID();
+
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $service,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
+ $bindings = id(new AlmanacBindingQuery())
+ ->setViewer($viewer)
+ ->withServicePHIDs(array($service->getPHID()))
+ ->execute();
+
+ $phids = array();
+ foreach ($bindings as $binding) {
+ $phids[] = $binding->getServicePHID();
+ $phids[] = $binding->getDevicePHID();
+ $phids[] = $binding->getInterface()->getNetworkPHID();
+ }
+ $handles = $this->loadViewerHandles($phids);
+
+ $table = id(new AlmanacBindingTableView())
+ ->setNoDataString(
+ pht('This service has not been bound to any device interfaces yet.'))
+ ->setUser($viewer)
+ ->setBindings($bindings)
+ ->setHandles($handles);
+
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Service Bindings'))
+ ->addActionLink(
+ id(new PHUIButtonView())
+ ->setTag('a')
+ ->setHref($this->getApplicationURI("binding/edit/?serviceID={$id}"))
+ ->setWorkflow(!$can_edit)
+ ->setDisabled(!$can_edit)
+ ->setText(pht('Add Binding'))
+ ->setIcon(
+ id(new PHUIIconView())
+ ->setIconFont('fa-plus')));
+
+ return id(new PHUIObjectBoxView())
+ ->setHeader($header)
+ ->appendChild($table);
+ }
+
}
diff --git a/src/applications/almanac/editor/AlmanacBindingEditor.php b/src/applications/almanac/editor/AlmanacBindingEditor.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/editor/AlmanacBindingEditor.php
@@ -0,0 +1,139 @@
+<?php
+
+final class AlmanacBindingEditor
+ extends PhabricatorApplicationTransactionEditor {
+
+ public function getEditorApplicationClass() {
+ return 'PhabricatorAlmanacApplication';
+ }
+
+ public function getEditorObjectsDescription() {
+ return pht('Almanac Binding');
+ }
+
+ public function getTransactionTypes() {
+ $types = parent::getTransactionTypes();
+
+ $types[] = AlmanacBindingTransaction::TYPE_INTERFACE;
+
+ return $types;
+ }
+
+ protected function getCustomTransactionOldValue(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+ switch ($xaction->getTransactionType()) {
+ case AlmanacBindingTransaction::TYPE_INTERFACE:
+ return $object->getInterfacePHID();
+ }
+
+ return parent::getCustomTransactionOldValue($object, $xaction);
+ }
+
+ protected function getCustomTransactionNewValue(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case AlmanacBindingTransaction::TYPE_INTERFACE:
+ return $xaction->getNewValue();
+ }
+
+ return parent::getCustomTransactionNewValue($object, $xaction);
+ }
+
+ protected function applyCustomInternalTransaction(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case AlmanacBindingTransaction::TYPE_INTERFACE:
+ $interface = id(new AlmanacInterfaceQuery())
+ ->setViewer($this->requireActor())
+ ->withPHIDs(array($xaction->getNewValue()))
+ ->executeOne();
+ $object->setDevicePHID($interface->getDevicePHID());
+ $object->setInterfacePHID($interface->getPHID());
+ return;
+ }
+
+ return parent::applyCustomInternalTransaction($object, $xaction);
+ }
+
+ protected function applyCustomExternalTransaction(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case AlmanacBindingTransaction::TYPE_INTERFACE:
+ return;
+ }
+
+ return parent::applyCustomExternalTransaction($object, $xaction);
+ }
+
+ protected function validateTransaction(
+ PhabricatorLiskDAO $object,
+ $type,
+ array $xactions) {
+
+ $errors = parent::validateTransaction($object, $type, $xactions);
+
+ switch ($type) {
+ case AlmanacBindingTransaction::TYPE_INTERFACE:
+ $missing = $this->validateIsEmptyTextField(
+ $object->getInterfacePHID(),
+ $xactions);
+ if ($missing) {
+ $error = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Required'),
+ pht('Bindings must specify an interface.'),
+ nonempty(last($xactions), null));
+ $error->setIsMissingFieldError(true);
+ $errors[] = $error;
+ } else if ($xactions) {
+ foreach ($xactions as $xaction) {
+ $interfaces = id(new AlmanacInterfaceQuery())
+ ->setViewer($this->requireActor())
+ ->withPHIDs(array($xaction->getNewValue()))
+ ->execute();
+ if (!$interfaces) {
+ $error = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Invalid'),
+ pht(
+ 'You can not bind a service to an invalid or restricted '.
+ 'interface.'),
+ $xaction);
+ $errors[] = $error;
+ }
+ }
+
+ $final_value = last($xactions)->getNewValue();
+
+ $binding = id(new AlmanacBindingQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withServicePHIDs(array($object->getServicePHID()))
+ ->withInterfacePHIDs(array($final_value))
+ ->executeOne();
+ if ($binding && ($binding->getID() != $object->getID())) {
+ $error = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Already Bound'),
+ pht(
+ 'You can not bind a service to the same interface multiple '.
+ 'times.'),
+ last($xactions));
+ $errors[] = $error;
+ }
+ }
+ break;
+ }
+
+ return $errors;
+ }
+
+
+
+}
diff --git a/src/applications/almanac/phid/AlmanacDevicePHIDType.php b/src/applications/almanac/phid/AlmanacBindingPHIDType.php
copy from src/applications/almanac/phid/AlmanacDevicePHIDType.php
copy to src/applications/almanac/phid/AlmanacBindingPHIDType.php
--- a/src/applications/almanac/phid/AlmanacDevicePHIDType.php
+++ b/src/applications/almanac/phid/AlmanacBindingPHIDType.php
@@ -1,22 +1,22 @@
<?php
-final class AlmanacDevicePHIDType extends PhabricatorPHIDType {
+final class AlmanacBindingPHIDType extends PhabricatorPHIDType {
- const TYPECONST = 'ADEV';
+ const TYPECONST = 'ABND';
public function getTypeName() {
- return pht('Almanac Device');
+ return pht('Almanac Binding');
}
public function newObject() {
- return new AlmanacDevice();
+ return new AlmanacBinding();
}
protected function buildQueryForObjects(
PhabricatorObjectQuery $query,
array $phids) {
- return id(new AlmanacDeviceQuery())
+ return id(new AlmanacBindingQuery())
->withPHIDs($phids);
}
@@ -26,13 +26,12 @@
array $objects) {
foreach ($handles as $phid => $handle) {
- $device = $objects[$phid];
+ $binding = $objects[$phid];
- $id = $device->getID();
- $name = $device->getName();
+ $id = $binding->getID();
- $handle->setObjectName(pht('Device %d', $id));
- $handle->setName($name);
+ $handle->setObjectName(pht('Binding %d', $id));
+ $handle->setName(pht('Binding %d', $id));
}
}
diff --git a/src/applications/almanac/phid/AlmanacDevicePHIDType.php b/src/applications/almanac/phid/AlmanacDevicePHIDType.php
--- a/src/applications/almanac/phid/AlmanacDevicePHIDType.php
+++ b/src/applications/almanac/phid/AlmanacDevicePHIDType.php
@@ -33,6 +33,7 @@
$handle->setObjectName(pht('Device %d', $id));
$handle->setName($name);
+ $handle->setURI($device->getURI());
}
}
diff --git a/src/applications/almanac/phid/AlmanacInterfacePHIDType.php b/src/applications/almanac/phid/AlmanacInterfacePHIDType.php
--- a/src/applications/almanac/phid/AlmanacInterfacePHIDType.php
+++ b/src/applications/almanac/phid/AlmanacInterfacePHIDType.php
@@ -30,8 +30,20 @@
$id = $interface->getID();
+ $device_name = $interface->getDevice()->getName();
+ $address = $interface->getAddress();
+ $port = $interface->getPort();
+ $network = $interface->getNetwork()->getName();
+
+ $name = pht(
+ '%s:%s (%s on %s)',
+ $device_name,
+ $port,
+ $address,
+ $network);
+
$handle->setObjectName(pht('Interface %d', $id));
- $handle->setName(pht('Interface %d', $id));
+ $handle->setName($name);
}
}
diff --git a/src/applications/almanac/phid/AlmanacNetworkPHIDType.php b/src/applications/almanac/phid/AlmanacNetworkPHIDType.php
--- a/src/applications/almanac/phid/AlmanacNetworkPHIDType.php
+++ b/src/applications/almanac/phid/AlmanacNetworkPHIDType.php
@@ -33,6 +33,7 @@
$handle->setObjectName(pht('Network %d', $id));
$handle->setName($name);
+ $handle->setURI($network->getURI());
}
}
diff --git a/src/applications/almanac/phid/AlmanacServicePHIDType.php b/src/applications/almanac/phid/AlmanacServicePHIDType.php
--- a/src/applications/almanac/phid/AlmanacServicePHIDType.php
+++ b/src/applications/almanac/phid/AlmanacServicePHIDType.php
@@ -33,6 +33,7 @@
$handle->setObjectName(pht('Service %d', $id));
$handle->setName($name);
+ $handle->setURI($service->getURI());
}
}
diff --git a/src/applications/almanac/query/AlmanacBindingQuery.php b/src/applications/almanac/query/AlmanacBindingQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/query/AlmanacBindingQuery.php
@@ -0,0 +1,143 @@
+<?php
+
+final class AlmanacBindingQuery
+ extends PhabricatorCursorPagedPolicyAwareQuery {
+
+ private $ids;
+ private $phids;
+ private $servicePHIDs;
+ private $devicePHIDs;
+ private $interfacePHIDs;
+
+ public function withIDs(array $ids) {
+ $this->ids = $ids;
+ return $this;
+ }
+
+ public function withPHIDs(array $phids) {
+ $this->phids = $phids;
+ return $this;
+ }
+
+ public function withServicePHIDs(array $phids) {
+ $this->servicePHIDs = $phids;
+ return $this;
+ }
+
+ public function withDevicePHIDs(array $phids) {
+ $this->devicePHIDs = $phids;
+ return $this;
+ }
+
+ public function withInterfacePHIDs(array $phids) {
+ $this->interfacePHIDs = $phids;
+ return $this;
+ }
+
+ protected function loadPage() {
+ $table = new AlmanacBinding();
+ $conn_r = $table->establishConnection('r');
+
+ $data = queryfx_all(
+ $conn_r,
+ 'SELECT * FROM %T %Q %Q %Q',
+ $table->getTableName(),
+ $this->buildWhereClause($conn_r),
+ $this->buildOrderClause($conn_r),
+ $this->buildLimitClause($conn_r));
+
+ return $table->loadAllFromArray($data);
+ }
+
+ protected function willFilterPage(array $bindings) {
+ $service_phids = mpull($bindings, 'getServicePHID');
+ $device_phids = mpull($bindings, 'getDevicePHID');
+ $interface_phids = mpull($bindings, 'getInterfacePHID');
+
+ $services = id(new AlmanacServiceQuery())
+ ->setParentQuery($this)
+ ->setViewer($this->getViewer())
+ ->withPHIDs($service_phids)
+ ->execute();
+ $services = mpull($services, null, 'getPHID');
+
+ $devices = id(new AlmanacDeviceQuery())
+ ->setParentQuery($this)
+ ->setViewer($this->getViewer())
+ ->withPHIDs($device_phids)
+ ->execute();
+ $devices = mpull($devices, null, 'getPHID');
+
+ $interfaces = id(new AlmanacInterfaceQuery())
+ ->setParentQuery($this)
+ ->setViewer($this->getViewer())
+ ->withPHIDs($interface_phids)
+ ->execute();
+ $interfaces = mpull($interfaces, null, 'getPHID');
+
+ foreach ($bindings as $key => $binding) {
+ $service = idx($services, $binding->getServicePHID());
+ $device = idx($devices, $binding->getDevicePHID());
+ $interface = idx($interfaces, $binding->getInterfacePHID());
+ if (!$service || !$device || !$interface) {
+ $this->didRejectResult($binding);
+ unset($bindings[$key]);
+ continue;
+ }
+
+ $binding->attachService($service);
+ $binding->attachDevice($device);
+ $binding->attachInterface($interface);
+ }
+
+ return $bindings;
+ }
+
+ protected function buildWhereClause($conn_r) {
+ $where = array();
+
+ if ($this->ids !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'id IN (%Ld)',
+ $this->ids);
+ }
+
+ if ($this->phids !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'phid IN (%Ls)',
+ $this->phids);
+ }
+
+ if ($this->servicePHIDs !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'servicePHID IN (%Ls)',
+ $this->servicePHIDs);
+ }
+
+ if ($this->devicePHIDs !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'devicePHID IN (%Ls)',
+ $this->devicePHIDs);
+ }
+
+ if ($this->interfacePHIDs !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'interfacePHID IN (%Ls)',
+ $this->interfacePHIDs);
+ }
+
+ $where[] = $this->buildPagingClause($conn_r);
+
+ return $this->formatWhereClause($where);
+ }
+
+ public function getQueryApplicationClass() {
+ return 'PhabricatorAlmanacApplication';
+ }
+
+}
diff --git a/src/applications/almanac/query/AlmanacBindingTransactionQuery.php b/src/applications/almanac/query/AlmanacBindingTransactionQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/query/AlmanacBindingTransactionQuery.php
@@ -0,0 +1,10 @@
+<?php
+
+final class AlmanacBindingTransactionQuery
+ extends PhabricatorApplicationTransactionQuery {
+
+ public function getTemplateApplicationTransaction() {
+ return new AlmanacBindingTransaction();
+ }
+
+}
diff --git a/src/applications/almanac/query/AlmanacDeviceQuery.php b/src/applications/almanac/query/AlmanacDeviceQuery.php
--- a/src/applications/almanac/query/AlmanacDeviceQuery.php
+++ b/src/applications/almanac/query/AlmanacDeviceQuery.php
@@ -6,6 +6,7 @@
private $ids;
private $phids;
private $names;
+ private $datasourceQuery;
public function withIDs(array $ids) {
$this->ids = $ids;
@@ -22,6 +23,11 @@
return $this;
}
+ public function withDatasourceQuery($query) {
+ $this->datasourceQuery = $query;
+ return $this;
+ }
+
protected function loadPage() {
$table = new AlmanacDevice();
$conn_r = $table->establishConnection('r');
@@ -65,6 +71,13 @@
$hashes);
}
+ if ($this->datasourceQuery !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'name LIKE %>',
+ $this->datasourceQuery);
+ }
+
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
diff --git a/src/applications/almanac/storage/AlmanacBinding.php b/src/applications/almanac/storage/AlmanacBinding.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/storage/AlmanacBinding.php
@@ -0,0 +1,112 @@
+<?php
+
+final class AlmanacBinding
+ extends AlmanacDAO
+ implements PhabricatorPolicyInterface {
+
+ protected $servicePHID;
+ protected $devicePHID;
+ protected $interfacePHID;
+ protected $mailKey;
+
+ private $service = self::ATTACHABLE;
+ private $device = self::ATTACHABLE;
+ private $interface = self::ATTACHABLE;
+
+ public static function initializeNewBinding(AlmanacService $service) {
+ return id(new AlmanacBinding())
+ ->setServicePHID($service->getPHID());
+ }
+
+ public function getConfiguration() {
+ return array(
+ self::CONFIG_AUX_PHID => true,
+ self::CONFIG_COLUMN_SCHEMA => array(
+ 'mailKey' => 'bytes20',
+ ),
+ self::CONFIG_KEY_SCHEMA => array(
+ 'key_service' => array(
+ 'columns' => array('servicePHID', 'interfacePHID'),
+ 'unique' => true,
+ ),
+ 'key_device' => array(
+ 'columns' => array('devicePHID'),
+ ),
+ 'key_interface' => array(
+ 'columns' => array('interfacePHID'),
+ ),
+ ),
+ ) + parent::getConfiguration();
+ }
+
+ public function generatePHID() {
+ return PhabricatorPHID::generateNewPHID(AlmanacBindingPHIDType::TYPECONST);
+ }
+
+ public function save() {
+ if (!$this->mailKey) {
+ $this->mailKey = Filesystem::readRandomCharacters(20);
+ }
+ return parent::save();
+ }
+
+ public function getURI() {
+ return '/almanac/binding/'.$this->getID().'/';
+ }
+
+ public function getService() {
+ return $this->assertAttached($this->service);
+ }
+
+ public function attachService(AlmanacService $service) {
+ $this->service = $service;
+ return $this;
+ }
+
+ public function getDevice() {
+ return $this->assertAttached($this->device);
+ }
+
+ public function attachDevice(AlmanacDevice $device) {
+ $this->device = $device;
+ return $this;
+ }
+
+ public function getInterface() {
+ return $this->assertAttached($this->interface);
+ }
+
+ public function attachInterface(AlmanacInterface $interface) {
+ $this->interface = $interface;
+ return $this;
+ }
+
+
+/* -( PhabricatorPolicyInterface )----------------------------------------- */
+
+
+ public function getCapabilities() {
+ return array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ );
+ }
+
+ public function getPolicy($capability) {
+ return $this->getService()->getPolicy($capability);
+ }
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ return $this->getService()->hasAutomaticCapability($capability, $viewer);
+ }
+
+ public function describeAutomaticCapability($capability) {
+ return array(
+ pht('A binding inherits the policies of its service.'),
+ pht(
+ 'To view a binding, you must also be able to view its device and '.
+ 'interface.'),
+ );
+ }
+
+}
diff --git a/src/applications/almanac/storage/AlmanacBindingTransaction.php b/src/applications/almanac/storage/AlmanacBindingTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/storage/AlmanacBindingTransaction.php
@@ -0,0 +1,65 @@
+<?php
+
+final class AlmanacBindingTransaction
+ extends PhabricatorApplicationTransaction {
+
+ const TYPE_INTERFACE = 'almanac:binding:interface';
+
+ public function getApplicationName() {
+ return 'almanac';
+ }
+
+ public function getApplicationTransactionType() {
+ return AlmanacBindingPHIDType::TYPECONST;
+ }
+
+ public function getApplicationTransactionCommentObject() {
+ return null;
+ }
+
+ public function getRequiredHandlePHIDs() {
+ $phids = parent::getRequiredHandlePHIDs();
+
+ $old = $this->getOldValue();
+ $new = $this->getNewValue();
+
+ switch ($this->getTransactionType()) {
+ case self::TYPE_INTERFACE:
+ if ($old) {
+ $phids[] = $old;
+ }
+ if ($new) {
+ $phids[] = $new;
+ }
+ break;
+ }
+
+ return $phids;
+ }
+
+ public function getTitle() {
+ $author_phid = $this->getAuthorPHID();
+
+ $old = $this->getOldValue();
+ $new = $this->getNewValue();
+
+ switch ($this->getTransactionType()) {
+ case self::TYPE_INTERFACE:
+ if ($old === null) {
+ return pht(
+ '%s created this binding.',
+ $this->renderHandleLink($author_phid));
+ } else {
+ return pht(
+ '%s changed this binding from %s to %s.',
+ $this->renderHandleLink($author_phid),
+ $this->renderHandleLink($old),
+ $this->renderHandleLink($new));
+ }
+ break;
+ }
+
+ return parent::getTitle();
+ }
+
+}
diff --git a/src/applications/almanac/storage/AlmanacInterface.php b/src/applications/almanac/storage/AlmanacInterface.php
--- a/src/applications/almanac/storage/AlmanacInterface.php
+++ b/src/applications/almanac/storage/AlmanacInterface.php
@@ -52,8 +52,8 @@
return $this->assertAttached($this->network);
}
- public function attachNetwork(AlmanacNetwork $device) {
- $this->device = $device;
+ public function attachNetwork(AlmanacNetwork $network) {
+ $this->network = $network;
return $this;
}
@@ -68,6 +68,10 @@
return $this->toAddress()->toHash();
}
+ public function renderDisplayAddress() {
+ return $this->getAddress().':'.$this->getPort();
+ }
+
/* -( PhabricatorPolicyInterface )----------------------------------------- */
diff --git a/src/applications/almanac/typeahead/AlmanacInterfaceDatasource.php b/src/applications/almanac/typeahead/AlmanacInterfaceDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/typeahead/AlmanacInterfaceDatasource.php
@@ -0,0 +1,51 @@
+<?php
+
+final class AlmanacInterfaceDatasource
+ extends PhabricatorTypeaheadDatasource {
+
+ public function getPlaceholderText() {
+ return pht('Type an interface name...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorAlmanacApplication';
+ }
+
+ public function loadResults() {
+ $viewer = $this->getViewer();
+ $raw_query = $this->getRawQuery();
+
+ $devices = id(new AlmanacDeviceQuery())
+ ->setViewer($viewer)
+ ->withDatasourceQuery($raw_query)
+ ->execute();
+
+ if ($devices) {
+ $interfaces = id(new AlmanacInterfaceQuery())
+ ->setViewer($viewer)
+ ->withDevicePHIDs(mpull($devices, 'getPHID'))
+ ->execute();
+ } else {
+ $interfaces = array();
+ }
+
+ if ($interfaces) {
+ $handles = id(new PhabricatorHandleQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(mpull($interfaces, 'getPHID'))
+ ->execute();
+ } else {
+ $handles = array();
+ }
+
+ $results = array();
+ foreach ($handles as $handle) {
+ $results[] = id(new PhabricatorTypeaheadResult())
+ ->setName($handle->getName())
+ ->setPHID($handle->getPHID());
+ }
+
+ return $results;
+ }
+
+}
diff --git a/src/applications/almanac/view/AlmanacBindingTableView.php b/src/applications/almanac/view/AlmanacBindingTableView.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/view/AlmanacBindingTableView.php
@@ -0,0 +1,86 @@
+<?php
+
+final class AlmanacBindingTableView extends AphrontView {
+
+ private $bindings;
+ private $handles;
+ private $noDataString;
+
+ public function setNoDataString($no_data_string) {
+ $this->noDataString = $no_data_string;
+ return $this;
+ }
+
+ public function getNoDataString() {
+ return $this->noDataString;
+ }
+
+ public function setHandles(array $handles) {
+ $this->handles = $handles;
+ return $this;
+ }
+
+ public function getHandles() {
+ return $this->handles;
+ }
+
+ public function setBindings(array $bindings) {
+ $this->bindings = $bindings;
+ return $this;
+ }
+
+ public function getBindings() {
+ return $this->bindings;
+ }
+
+ public function render() {
+ $bindings = $this->getBindings();
+ $handles = $this->getHandles();
+ $viewer = $this->getUser();
+
+ $rows = array();
+ foreach ($bindings as $binding) {
+ $addr = $binding->getInterface()->getAddress();
+ $port = $binding->getInterface()->getPort();
+
+ $rows[] = array(
+ $binding->getID(),
+ $handles[$binding->getServicePHID()]->renderLink(),
+ $handles[$binding->getDevicePHID()]->renderLink(),
+ $handles[$binding->getInterface()->getNetworkPHID()]->renderLink(),
+ $binding->getInterface()->renderDisplayAddress(),
+ phutil_tag(
+ 'a',
+ array(
+ 'class' => 'small grey button',
+ 'href' => '/almanac/binding/'.$binding->getID().'/',
+ ),
+ pht('Details')),
+ );
+ }
+
+ $table = id(new AphrontTableView($rows))
+ ->setNoDataString($this->getNoDataString())
+ ->setHeaders(
+ array(
+ pht('ID'),
+ pht('Service'),
+ pht('Device'),
+ pht('Network'),
+ pht('Interface'),
+ null,
+ ))
+ ->setColumnClasses(
+ array(
+ '',
+ '',
+ '',
+ '',
+ 'wide',
+ 'action',
+ ));
+
+ return $table;
+ }
+
+}

File Metadata

Mime Type
text/plain
Expires
Thu, May 9, 12:45 AM (3 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6273654
Default Alt Text
D10745.diff (38 KB)

Event Timeline