Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15625524
D10745.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
38 KB
Referenced Files
None
Subscribers
None
D10745.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Mon, May 19, 8:17 AM (15 h, 34 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
8005121
Default Alt Text
D10745.diff (38 KB)
Attached To
Mode
D10745: Add AlmanacBinding, to bind a service to an interface
Attached
Detach File
Event Timeline
Log In to Comment