@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.

Build AlmanacInterface

Summary: Ref T5833. An interface is an IP (maybe v4, maybe v6) and port on a specified network (public internet, VPN, NAT block, etc).

Test Plan: See screenshots.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T5833

Differential Revision: https://secure.phabricator.com/D10718

+835
+13
resources/sql/autopatches/20141016.almanac.interface.sql
··· 1 + CREATE TABLE {$NAMESPACE}_almanac.almanac_interface ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARBINARY(64) NOT NULL, 4 + devicePHID VARBINARY(64) NOT NULL, 5 + networkPHID VARBINARY(64) NOT NULL, 6 + address VARCHAR(128) NOT NULL COLLATE utf8_bin, 7 + port INT UNSIGNED NOT NULL, 8 + dateCreated INT UNSIGNED NOT NULL, 9 + dateModified INT UNSIGNED NOT NULL, 10 + UNIQUE KEY `key_phid` (phid), 11 + KEY `key_location` (networkPHID, address, port), 12 + KEY `key_device` (devicePHID) 13 + ) ENGINE=InnoDB, COLLATE utf8_general_ci;
+15
src/__phutil_library_map__.php
··· 9 9 phutil_register_library_map(array( 10 10 '__library_version__' => 2, 11 11 'class' => array( 12 + 'AlmanacAddress' => 'applications/almanac/util/AlmanacAddress.php', 12 13 'AlmanacConduitUtil' => 'applications/almanac/util/AlmanacConduitUtil.php', 13 14 'AlmanacConsoleController' => 'applications/almanac/controller/AlmanacConsoleController.php', 14 15 'AlmanacController' => 'applications/almanac/controller/AlmanacController.php', ··· 28 29 'AlmanacDeviceTransaction' => 'applications/almanac/storage/AlmanacDeviceTransaction.php', 29 30 'AlmanacDeviceTransactionQuery' => 'applications/almanac/query/AlmanacDeviceTransactionQuery.php', 30 31 'AlmanacDeviceViewController' => 'applications/almanac/controller/AlmanacDeviceViewController.php', 32 + 'AlmanacInterface' => 'applications/almanac/storage/AlmanacInterface.php', 33 + 'AlmanacInterfaceEditController' => 'applications/almanac/controller/AlmanacInterfaceEditController.php', 34 + 'AlmanacInterfacePHIDType' => 'applications/almanac/phid/AlmanacInterfacePHIDType.php', 35 + 'AlmanacInterfaceQuery' => 'applications/almanac/query/AlmanacInterfaceQuery.php', 36 + 'AlmanacInterfaceTableView' => 'applications/almanac/view/AlmanacInterfaceTableView.php', 31 37 'AlmanacManagementRegisterWorkflow' => 'applications/almanac/management/AlmanacManagementRegisterWorkflow.php', 32 38 'AlmanacManagementWorkflow' => 'applications/almanac/management/AlmanacManagementWorkflow.php', 33 39 'AlmanacNames' => 'applications/almanac/util/AlmanacNames.php', ··· 2940 2946 'require_celerity_resource' => 'applications/celerity/api.php', 2941 2947 ), 2942 2948 'xmap' => array( 2949 + 'AlmanacAddress' => 'Phobject', 2943 2950 'AlmanacConduitUtil' => 'Phobject', 2944 2951 'AlmanacConsoleController' => 'AlmanacController', 2945 2952 'AlmanacController' => 'PhabricatorController', ··· 2962 2969 'AlmanacDeviceTransaction' => 'PhabricatorApplicationTransaction', 2963 2970 'AlmanacDeviceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 2964 2971 'AlmanacDeviceViewController' => 'AlmanacDeviceController', 2972 + 'AlmanacInterface' => array( 2973 + 'AlmanacDAO', 2974 + 'PhabricatorPolicyInterface', 2975 + ), 2976 + 'AlmanacInterfaceEditController' => 'AlmanacDeviceController', 2977 + 'AlmanacInterfacePHIDType' => 'PhabricatorPHIDType', 2978 + 'AlmanacInterfaceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 2979 + 'AlmanacInterfaceTableView' => 'AphrontView', 2965 2980 'AlmanacManagementRegisterWorkflow' => 'AlmanacManagementWorkflow', 2966 2981 'AlmanacManagementWorkflow' => 'PhabricatorManagementWorkflow', 2967 2982 'AlmanacNames' => 'Phobject',
+3
src/applications/almanac/application/PhabricatorAlmanacApplication.php
··· 44 44 'edit/(?:(?P<id>\d+)/)?' => 'AlmanacDeviceEditController', 45 45 'view/(?P<name>[^/]+)/' => 'AlmanacDeviceViewController', 46 46 ), 47 + 'interface/' => array( 48 + 'edit/(?:(?P<id>\d+)/)?' => 'AlmanacInterfaceEditController', 49 + ), 47 50 'network/' => array( 48 51 '(?:query/(?P<queryKey>[^/]+)/)?' => 'AlmanacNetworkListController', 49 52 'edit/(?:(?P<id>\d+)/)?' => 'AlmanacNetworkEditController',
+47
src/applications/almanac/controller/AlmanacDeviceViewController.php
··· 35 35 ->setHeader($header) 36 36 ->addPropertyList($property_list); 37 37 38 + $interfaces = $this->buildInterfaceList($device); 39 + 38 40 $crumbs = $this->buildApplicationCrumbs(); 39 41 $crumbs->addTextCrumb($device->getName()); 40 42 ··· 53 55 array( 54 56 $crumbs, 55 57 $box, 58 + $interfaces, 56 59 $xaction_view, 57 60 ), 58 61 array( ··· 90 93 ->setDisabled(!$can_edit)); 91 94 92 95 return $actions; 96 + } 97 + 98 + private function buildInterfaceList(AlmanacDevice $device) { 99 + $viewer = $this->getViewer(); 100 + $id = $device->getID(); 101 + 102 + $can_edit = PhabricatorPolicyFilter::hasCapability( 103 + $viewer, 104 + $device, 105 + PhabricatorPolicyCapability::CAN_EDIT); 106 + 107 + $interfaces = id(new AlmanacInterfaceQuery()) 108 + ->setViewer($viewer) 109 + ->withDevicePHIDs(array($device->getPHID())) 110 + ->execute(); 111 + 112 + $phids = array(); 113 + foreach ($interfaces as $interface) { 114 + $phids[] = $interface->getNetworkPHID(); 115 + $phids[] = $interface->getDevicePHID(); 116 + } 117 + $handles = $this->loadViewerHandles($phids); 118 + 119 + $table = id(new AlmanacInterfaceTableView()) 120 + ->setUser($viewer) 121 + ->setInterfaces($interfaces) 122 + ->setHandles($handles); 123 + 124 + $header = id(new PHUIHeaderView()) 125 + ->setHeader(pht('Device Interfaces')) 126 + ->addActionLink( 127 + id(new PHUIButtonView()) 128 + ->setTag('a') 129 + ->setHref($this->getApplicationURI("interface/edit/?deviceID={$id}")) 130 + ->setWorkflow(!$can_edit) 131 + ->setDisabled(!$can_edit) 132 + ->setText(pht('Add Interface')) 133 + ->setIcon( 134 + id(new PHUIIconView()) 135 + ->setIconFont('fa-plus'))); 136 + 137 + return id(new PHUIObjectBoxView()) 138 + ->setHeader($header) 139 + ->appendChild($table); 93 140 } 94 141 95 142 }
+155
src/applications/almanac/controller/AlmanacInterfaceEditController.php
··· 1 + <?php 2 + 3 + final class AlmanacInterfaceEditController 4 + extends AlmanacDeviceController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getViewer(); 8 + 9 + $id = $request->getURIData('id'); 10 + if ($id) { 11 + $interface = id(new AlmanacInterfaceQuery()) 12 + ->setViewer($viewer) 13 + ->withIDs(array($id)) 14 + ->requireCapabilities( 15 + array( 16 + PhabricatorPolicyCapability::CAN_VIEW, 17 + PhabricatorPolicyCapability::CAN_EDIT, 18 + )) 19 + ->executeOne(); 20 + if (!$interface) { 21 + return new Aphront404Response(); 22 + } 23 + 24 + $device = $interface->getDevice(); 25 + 26 + $is_new = false; 27 + $title = pht('Edit Interface'); 28 + $save_button = pht('Save Changes'); 29 + } else { 30 + $device = id(new AlmanacDeviceQuery()) 31 + ->setViewer($viewer) 32 + ->withIDs(array($request->getStr('deviceID'))) 33 + ->requireCapabilities( 34 + array( 35 + PhabricatorPolicyCapability::CAN_VIEW, 36 + PhabricatorPolicyCapability::CAN_EDIT, 37 + )) 38 + ->executeOne(); 39 + if (!$device) { 40 + return new Aphront404Response(); 41 + } 42 + 43 + $interface = AlmanacInterface::initializeNewInterface(); 44 + $is_new = true; 45 + 46 + $title = pht('Create Interface'); 47 + $save_button = pht('Create Interface'); 48 + } 49 + 50 + $device_uri = $device->getURI(); 51 + $cancel_uri = $device_uri; 52 + 53 + $v_network = $interface->getNetworkPHID(); 54 + 55 + $v_address = $interface->getAddress(); 56 + $e_address = true; 57 + 58 + $v_port = $interface->getPort(); 59 + 60 + $validation_exception = null; 61 + 62 + if ($request->isFormPost()) { 63 + $v_network = $request->getStr('networkPHID'); 64 + $v_address = $request->getStr('address'); 65 + $v_port = $request->getStr('port'); 66 + 67 + $type_interface = AlmanacDeviceTransaction::TYPE_INTERFACE; 68 + 69 + $address = AlmanacAddress::newFromParts($v_network, $v_address, $v_port); 70 + 71 + $xaction = id(new AlmanacDeviceTransaction()) 72 + ->setTransactionType($type_interface) 73 + ->setNewValue($address->toDictionary()); 74 + 75 + if ($interface->getID()) { 76 + $xaction->setOldValue(array( 77 + 'id' => $interface->getID(), 78 + ) + $interface->toAddress()->toDictionary()); 79 + } else { 80 + $xaction->setOldValue(array()); 81 + } 82 + 83 + $xactions = array(); 84 + $xactions[] = $xaction; 85 + 86 + $editor = id(new AlmanacDeviceEditor()) 87 + ->setActor($viewer) 88 + ->setContentSourceFromRequest($request) 89 + ->setContinueOnNoEffect(true) 90 + ->setContinueOnMissingFields(true); 91 + 92 + try { 93 + $editor->applyTransactions($device, $xactions); 94 + 95 + $device_uri = $device->getURI(); 96 + return id(new AphrontRedirectResponse())->setURI($device_uri); 97 + } catch (PhabricatorApplicationTransactionValidationException $ex) { 98 + $validation_exception = $ex; 99 + $e_address = $ex->getShortMessage($type_interface); 100 + } 101 + } 102 + 103 + $networks = id(new AlmanacNetworkQuery()) 104 + ->setViewer($viewer) 105 + ->execute(); 106 + 107 + $form = id(new AphrontFormView()) 108 + ->setUser($viewer) 109 + ->appendChild( 110 + id(new AphrontFormSelectControl()) 111 + ->setLabel(pht('Network')) 112 + ->setName('networkPHID') 113 + ->setValue($v_network) 114 + ->setOptions(mpull($networks, 'getName', 'getPHID'))) 115 + ->appendChild( 116 + id(new AphrontFormTextControl()) 117 + ->setLabel(pht('Address')) 118 + ->setName('address') 119 + ->setValue($v_address) 120 + ->setError($e_address)) 121 + ->appendChild( 122 + id(new AphrontFormTextControl()) 123 + ->setLabel(pht('Port')) 124 + ->setName('port') 125 + ->setValue($v_port) 126 + ->setError($e_address)) 127 + ->appendChild( 128 + id(new AphrontFormSubmitControl()) 129 + ->addCancelButton($cancel_uri) 130 + ->setValue($save_button)); 131 + 132 + $box = id(new PHUIObjectBoxView()) 133 + ->setValidationException($validation_exception) 134 + ->setHeaderText($title) 135 + ->appendChild($form); 136 + 137 + $crumbs = $this->buildApplicationCrumbs(); 138 + $crumbs->addTextCrumb($device->getName(), $device_uri); 139 + if ($is_new) { 140 + $crumbs->addTextCrumb(pht('Create Interface')); 141 + } else { 142 + $crumbs->addTextCrumb(pht('Edit Interface')); 143 + } 144 + 145 + return $this->buildApplicationPage( 146 + array( 147 + $crumbs, 148 + $box, 149 + ), 150 + array( 151 + 'title' => $title, 152 + )); 153 + } 154 + 155 + }
+148
src/applications/almanac/editor/AlmanacDeviceEditor.php
··· 15 15 $types = parent::getTransactionTypes(); 16 16 17 17 $types[] = AlmanacDeviceTransaction::TYPE_NAME; 18 + $types[] = AlmanacDeviceTransaction::TYPE_INTERFACE; 18 19 $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; 19 20 $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; 20 21 ··· 38 39 39 40 switch ($xaction->getTransactionType()) { 40 41 case AlmanacDeviceTransaction::TYPE_NAME: 42 + case AlmanacDeviceTransaction::TYPE_INTERFACE: 41 43 return $xaction->getNewValue(); 42 44 } 43 45 ··· 52 54 case AlmanacDeviceTransaction::TYPE_NAME: 53 55 $object->setName($xaction->getNewValue()); 54 56 return; 57 + case AlmanacDeviceTransaction::TYPE_INTERFACE: 55 58 case PhabricatorTransactions::TYPE_VIEW_POLICY: 56 59 case PhabricatorTransactions::TYPE_EDIT_POLICY: 57 60 return; ··· 69 72 case PhabricatorTransactions::TYPE_VIEW_POLICY: 70 73 case PhabricatorTransactions::TYPE_EDIT_POLICY: 71 74 return; 75 + case AlmanacDeviceTransaction::TYPE_INTERFACE: 76 + $old = $xaction->getOldValue(); 77 + if ($old) { 78 + $interface = id(new AlmanacInterfaceQuery()) 79 + ->setViewer($this->requireActor()) 80 + ->withIDs(array($old['id'])) 81 + ->executeOne(); 82 + if (!$interface) { 83 + throw new Exception(pht('Unable to load interface!')); 84 + } 85 + } else { 86 + $interface = AlmanacInterface::initializeNewInterface() 87 + ->setDevicePHID($object->getPHID()); 88 + } 89 + 90 + $new = $xaction->getNewValue(); 91 + if ($new) { 92 + $interface 93 + ->setNetworkPHID($new['networkPHID']) 94 + ->setAddress($new['address']) 95 + ->setPort((int)$new['port']) 96 + ->save(); 97 + } else { 98 + $interface->delete(); 99 + } 100 + return; 72 101 } 73 102 74 103 return parent::applyCustomExternalTransaction($object, $xaction); ··· 134 163 } 135 164 136 165 break; 166 + case AlmanacDeviceTransaction::TYPE_INTERFACE: 167 + // We want to make sure that all the affected networks are visible to 168 + // the actor, any edited interfaces exist, and that the actual address 169 + // components are valid. 170 + 171 + $network_phids = array(); 172 + foreach ($xactions as $xaction) { 173 + $old = $xaction->getOldValue(); 174 + $new = $xaction->getNewValue(); 175 + if ($old) { 176 + $network_phids[] = $old['networkPHID']; 177 + } 178 + if ($new) { 179 + $network_phids[] = $new['networkPHID']; 180 + 181 + $address = $new['address']; 182 + if (!strlen($address)) { 183 + $error = new PhabricatorApplicationTransactionValidationError( 184 + $type, 185 + pht('Invalid'), 186 + pht('Interfaces must have an address.'), 187 + $xaction); 188 + $errors[] = $error; 189 + } else { 190 + // TODO: Validate addresses, but IPv6 addresses are not trival 191 + // to validate. 192 + } 193 + 194 + $port = $new['port']; 195 + if (!strlen($port)) { 196 + $error = new PhabricatorApplicationTransactionValidationError( 197 + $type, 198 + pht('Invalid'), 199 + pht('Interfaces must have a port.'), 200 + $xaction); 201 + $errors[] = $error; 202 + } else if ((int)$port < 1 || (int)$port > 65535) { 203 + $error = new PhabricatorApplicationTransactionValidationError( 204 + $type, 205 + pht('Invalid'), 206 + pht( 207 + 'Port numbers must be between 1 and 65535, inclusive.'), 208 + $xaction); 209 + $errors[] = $error; 210 + } 211 + } 212 + } 213 + 214 + if ($network_phids) { 215 + $networks = id(new AlmanacNetworkQuery()) 216 + ->setViewer($this->requireActor()) 217 + ->withPHIDs($network_phids) 218 + ->execute(); 219 + $networks = mpull($networks, null, 'getPHID'); 220 + } else { 221 + $networks = array(); 222 + } 223 + 224 + $addresses = array(); 225 + foreach ($xactions as $xaction) { 226 + $old = $xaction->getOldValue(); 227 + if ($old) { 228 + $network = idx($networks, $old['networkPHID']); 229 + if (!$network) { 230 + $error = new PhabricatorApplicationTransactionValidationError( 231 + $type, 232 + pht('Invalid'), 233 + pht( 234 + 'You can not edit an interface which belongs to a '. 235 + 'nonexistent or restricted network.'), 236 + $xaction); 237 + $errors[] = $error; 238 + } 239 + 240 + $addresses[] = $old['id']; 241 + } 242 + 243 + $new = $xaction->getNewValue(); 244 + if ($new) { 245 + $network = idx($networks, $new['networkPHID']); 246 + if (!$network) { 247 + $error = new PhabricatorApplicationTransactionValidationError( 248 + $type, 249 + pht('Invalid'), 250 + pht( 251 + 'You can not add an interface on a nonexistent or '. 252 + 'restricted network.'), 253 + $xaction); 254 + $errors[] = $error; 255 + } 256 + } 257 + } 258 + 259 + if ($addresses) { 260 + $interfaces = id(new AlmanacInterfaceQuery()) 261 + ->setViewer($this->requireActor()) 262 + ->withDevicePHIDs(array($object->getPHID())) 263 + ->withIDs($addresses) 264 + ->execute(); 265 + $interfaces = mpull($interfaces, null, 'getID'); 266 + } else { 267 + $interfaces = array(); 268 + } 269 + 270 + foreach ($xactions as $xaction) { 271 + $old = $xaction->getOldValue(); 272 + if ($old) { 273 + $interface = idx($interfaces, $old['id']); 274 + if (!$interface) { 275 + $error = new PhabricatorApplicationTransactionValidationError( 276 + $type, 277 + pht('Invalid'), 278 + pht('You can not edit an invalid or restricted interface.'), 279 + $xaction); 280 + $errors[] = $error; 281 + } 282 + } 283 + } 284 + break; 137 285 } 138 286 139 287 return $errors;
+38
src/applications/almanac/phid/AlmanacInterfacePHIDType.php
··· 1 + <?php 2 + 3 + final class AlmanacInterfacePHIDType extends PhabricatorPHIDType { 4 + 5 + const TYPECONST = 'AINT'; 6 + 7 + public function getTypeName() { 8 + return pht('Almanac Interface'); 9 + } 10 + 11 + public function newObject() { 12 + return new AlmanacInterface(); 13 + } 14 + 15 + protected function buildQueryForObjects( 16 + PhabricatorObjectQuery $query, 17 + array $phids) { 18 + 19 + return id(new AlmanacInterfaceQuery()) 20 + ->withPHIDs($phids); 21 + } 22 + 23 + public function loadHandles( 24 + PhabricatorHandleQuery $query, 25 + array $handles, 26 + array $objects) { 27 + 28 + foreach ($handles as $phid => $handle) { 29 + $interface = $objects[$phid]; 30 + 31 + $id = $interface->getID(); 32 + 33 + $handle->setObjectName(pht('Interface %d', $id)); 34 + $handle->setName(pht('Interface %d', $id)); 35 + } 36 + } 37 + 38 + }
+139
src/applications/almanac/query/AlmanacInterfaceQuery.php
··· 1 + <?php 2 + 3 + final class AlmanacInterfaceQuery 4 + extends PhabricatorCursorPagedPolicyAwareQuery { 5 + 6 + private $ids; 7 + private $phids; 8 + private $networkPHIDs; 9 + private $devicePHIDs; 10 + private $addresses; 11 + 12 + public function withIDs(array $ids) { 13 + $this->ids = $ids; 14 + return $this; 15 + } 16 + 17 + public function withPHIDs(array $phids) { 18 + $this->phids = $phids; 19 + return $this; 20 + } 21 + 22 + public function withNetworkPHIDs(array $phids) { 23 + $this->networkPHIDs = $phids; 24 + return $this; 25 + } 26 + 27 + public function withDevicePHIDs(array $phids) { 28 + $this->devicePHIDs = $phids; 29 + return $this; 30 + } 31 + 32 + public function withAddresses(array $addresses) { 33 + $this->addresses = $addresses; 34 + return $this; 35 + } 36 + 37 + protected function loadPage() { 38 + $table = new AlmanacInterface(); 39 + $conn_r = $table->establishConnection('r'); 40 + 41 + $data = queryfx_all( 42 + $conn_r, 43 + 'SELECT * FROM %T %Q %Q %Q', 44 + $table->getTableName(), 45 + $this->buildWhereClause($conn_r), 46 + $this->buildOrderClause($conn_r), 47 + $this->buildLimitClause($conn_r)); 48 + 49 + return $table->loadAllFromArray($data); 50 + } 51 + 52 + protected function willFilterPage(array $interfaces) { 53 + $network_phids = mpull($interfaces, 'getNetworkPHID'); 54 + $device_phids = mpull($interfaces, 'getDevicePHID'); 55 + 56 + $networks = id(new AlmanacNetworkQuery()) 57 + ->setParentQuery($this) 58 + ->setViewer($this->getViewer()) 59 + ->withPHIDs($network_phids) 60 + ->execute(); 61 + $networks = mpull($networks, null, 'getPHID'); 62 + 63 + $devices = id(new AlmanacDeviceQuery()) 64 + ->setParentQuery($this) 65 + ->setViewer($this->getViewer()) 66 + ->withPHIDs($device_phids) 67 + ->execute(); 68 + $devices = mpull($devices, null, 'getPHID'); 69 + 70 + foreach ($interfaces as $key => $interface) { 71 + $network = idx($networks, $interface->getNetworkPHID()); 72 + $device = idx($devices, $interface->getDevicePHID()); 73 + if (!$network || !$device) { 74 + $this->didRejectResult($interface); 75 + unset($interfaces[$key]); 76 + continue; 77 + } 78 + 79 + $interface->attachNetwork($network); 80 + $interface->attachDevice($device); 81 + } 82 + 83 + return $interfaces; 84 + } 85 + 86 + protected function buildWhereClause($conn_r) { 87 + $where = array(); 88 + 89 + if ($this->ids !== null) { 90 + $where[] = qsprintf( 91 + $conn_r, 92 + 'id IN (%Ld)', 93 + $this->ids); 94 + } 95 + 96 + if ($this->phids !== null) { 97 + $where[] = qsprintf( 98 + $conn_r, 99 + 'phid IN (%Ls)', 100 + $this->phids); 101 + } 102 + 103 + if ($this->networkPHIDs !== null) { 104 + $where[] = qsprintf( 105 + $conn_r, 106 + 'networkPHID IN (%Ls)', 107 + $this->networkPHIDs); 108 + } 109 + 110 + if ($this->devicePHIDs !== null) { 111 + $where[] = qsprintf( 112 + $conn_r, 113 + 'devicePHID IN (%Ls)', 114 + $this->devicePHIDs); 115 + } 116 + 117 + if ($this->addresses !== null) { 118 + $parts = array(); 119 + foreach ($this->addresses as $address) { 120 + $parts[] = qsprintf( 121 + $conn_r, 122 + '(networkPHID = %s AND address = %s AND port = %d)', 123 + $address->getNetworkPHID(), 124 + $address->getAddress(), 125 + $address->getPort()); 126 + } 127 + $where[] = implode(' OR ', $parts); 128 + } 129 + 130 + $where[] = $this->buildPagingClause($conn_r); 131 + 132 + return $this->formatWhereClause($where); 133 + } 134 + 135 + public function getQueryApplicationClass() { 136 + return 'PhabricatorAlmanacApplication'; 137 + } 138 + 139 + }
+55
src/applications/almanac/storage/AlmanacDeviceTransaction.php
··· 4 4 extends PhabricatorApplicationTransaction { 5 5 6 6 const TYPE_NAME = 'almanac:device:name'; 7 + const TYPE_INTERFACE = 'almanac:device:interface'; 7 8 8 9 public function getApplicationName() { 9 10 return 'almanac'; ··· 17 18 return null; 18 19 } 19 20 21 + public function getRequiredHandlePHIDs() { 22 + $phids = parent::getRequiredHandlePHIDs(); 23 + 24 + $old = $this->getOldValue(); 25 + $new = $this->getNewValue(); 26 + 27 + switch ($this->getTransactionType()) { 28 + case self::TYPE_INTERFACE: 29 + if ($old) { 30 + $phids[] = $old['networkPHID']; 31 + } 32 + if ($new) { 33 + $phids[] = $new['networkPHID']; 34 + } 35 + break; 36 + } 37 + 38 + return $phids; 39 + } 40 + 20 41 public function getTitle() { 21 42 $author_phid = $this->getAuthorPHID(); 22 43 ··· 37 58 $new); 38 59 } 39 60 break; 61 + case self::TYPE_INTERFACE: 62 + if ($old && $new) { 63 + return pht( 64 + '%s changed interface %s on this device to %s.', 65 + $this->renderHandleLink($author_phid), 66 + $this->describeInterface($old), 67 + $this->describeInterface($new)); 68 + } else if ($old) { 69 + return pht( 70 + '%s removed the interface %s from this device.', 71 + $this->renderHandleLink($author_phid), 72 + $this->describeInterface($new)); 73 + } else if ($new) { 74 + return pht( 75 + '%s added the interface %s to this device.', 76 + $this->renderHandleLink($author_phid), 77 + $this->describeInterface($new)); 78 + } 40 79 } 41 80 42 81 return parent::getTitle(); 82 + } 83 + 84 + public function shouldGenerateOldValue() { 85 + switch ($this->getTransactionType()) { 86 + case self::TYPE_INTERFACE: 87 + return false; 88 + } 89 + return parent::shouldGenerateOldValue(); 90 + } 91 + 92 + private function describeInterface(array $info) { 93 + return pht( 94 + '%s:%s (%s)', 95 + $info['address'], 96 + $info['port'], 97 + $this->renderHandleLink($info['networkPHID'])); 43 98 } 44 99 45 100 }
+99
src/applications/almanac/storage/AlmanacInterface.php
··· 1 + <?php 2 + 3 + final class AlmanacInterface 4 + extends AlmanacDAO 5 + implements PhabricatorPolicyInterface { 6 + 7 + protected $devicePHID; 8 + protected $networkPHID; 9 + protected $address; 10 + protected $port; 11 + 12 + private $device = self::ATTACHABLE; 13 + private $network = self::ATTACHABLE; 14 + 15 + public static function initializeNewInterface() { 16 + return id(new AlmanacInterface()); 17 + } 18 + 19 + public function getConfiguration() { 20 + return array( 21 + self::CONFIG_AUX_PHID => true, 22 + self::CONFIG_COLUMN_SCHEMA => array( 23 + 'address' => 'text64', 24 + 'port' => 'uint32', 25 + ), 26 + self::CONFIG_KEY_SCHEMA => array( 27 + 'key_location' => array( 28 + 'columns' => array('networkPHID', 'address', 'port'), 29 + ), 30 + 'key_device' => array( 31 + 'columns' => array('devicePHID'), 32 + ), 33 + ), 34 + ) + parent::getConfiguration(); 35 + } 36 + 37 + public function generatePHID() { 38 + return PhabricatorPHID::generateNewPHID( 39 + AlmanacInterfacePHIDType::TYPECONST); 40 + } 41 + 42 + public function getDevice() { 43 + return $this->assertAttached($this->device); 44 + } 45 + 46 + public function attachDevice(AlmanacDevice $device) { 47 + $this->device = $device; 48 + return $this; 49 + } 50 + 51 + public function getNetwork() { 52 + return $this->assertAttached($this->network); 53 + } 54 + 55 + public function attachNetwork(AlmanacNetwork $device) { 56 + $this->device = $device; 57 + return $this; 58 + } 59 + 60 + public function toAddress() { 61 + return AlmanacAddress::newFromParts( 62 + $this->getNetworkPHID(), 63 + $this->getAddress(), 64 + $this->getPort()); 65 + } 66 + 67 + public function getAddressHash() { 68 + return $this->toAddress()->toHash(); 69 + } 70 + 71 + 72 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 73 + 74 + 75 + public function getCapabilities() { 76 + return array( 77 + PhabricatorPolicyCapability::CAN_VIEW, 78 + PhabricatorPolicyCapability::CAN_EDIT, 79 + ); 80 + } 81 + 82 + public function getPolicy($capability) { 83 + return $this->getDevice()->getPolicy($capability); 84 + } 85 + 86 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 87 + return $this->getDevice()->hasAutomaticCapability($capability, $viewer); 88 + } 89 + 90 + public function describeAutomaticCapability($capability) { 91 + return array( 92 + pht('An interface inherits the policies of the device it belongs to.'), 93 + pht( 94 + 'You must be able to view the network an interface resides on to '. 95 + 'view the interface.'), 96 + ); 97 + } 98 + 99 + }
+54
src/applications/almanac/util/AlmanacAddress.php
··· 1 + <?php 2 + 3 + final class AlmanacAddress extends Phobject { 4 + 5 + private $networkPHID; 6 + private $address; 7 + private $port; 8 + 9 + private function __construct() { 10 + // <private> 11 + } 12 + 13 + public function getNetworkPHID() { 14 + return $this->networkPHID; 15 + } 16 + 17 + public function getAddress() { 18 + return $this->address; 19 + } 20 + 21 + public function getPort() { 22 + return $this->port; 23 + } 24 + 25 + public static function newFromDictionary(array $dictionary) { 26 + return self::newFromParts( 27 + $dictionary['networkPHID'], 28 + $dictionary['address'], 29 + $dictionary['port']); 30 + } 31 + 32 + public static function newFromParts($network_phid, $address, $port) { 33 + $addr = new AlmanacAddress(); 34 + 35 + $addr->networkPHID = $network_phid; 36 + $addr->address = $address; 37 + $addr->port = (int)$port; 38 + 39 + return $addr; 40 + } 41 + 42 + public function toDictionary() { 43 + return array( 44 + 'networkPHID' => $this->getNetworkPHID(), 45 + 'address' => $this->getAddress(), 46 + 'port' => $this->getPort(), 47 + ); 48 + } 49 + 50 + public function toHash() { 51 + return PhabricatorHash::digestForIndex(json_encode($this->toDictionary())); 52 + } 53 + 54 + }
+69
src/applications/almanac/view/AlmanacInterfaceTableView.php
··· 1 + <?php 2 + 3 + final class AlmanacInterfaceTableView extends AphrontView { 4 + 5 + private $interfaces; 6 + private $handles; 7 + 8 + public function setHandles(array $handles) { 9 + $this->handles = $handles; 10 + return $this; 11 + } 12 + 13 + public function getHandles() { 14 + return $this->handles; 15 + } 16 + 17 + public function setInterfaces(array $interfaces) { 18 + $this->interfaces = $interfaces; 19 + return $this; 20 + } 21 + 22 + public function getInterfaces() { 23 + return $this->interfaces; 24 + } 25 + 26 + public function render() { 27 + $interfaces = $this->getInterfaces(); 28 + $handles = $this->getHandles(); 29 + $viewer = $this->getUser(); 30 + 31 + $rows = array(); 32 + foreach ($interfaces as $interface) { 33 + $rows[] = array( 34 + $interface->getID(), 35 + $handles[$interface->getNetworkPHID()]->renderLink(), 36 + $interface->getAddress(), 37 + $interface->getPort(), 38 + phutil_tag( 39 + 'a', 40 + array( 41 + 'class' => 'small grey button', 42 + 'href' => '/almanac/interface/edit/'.$interface->getID().'/', 43 + ), 44 + pht('Edit')), 45 + ); 46 + } 47 + 48 + $table = id(new AphrontTableView($rows)) 49 + ->setHeaders( 50 + array( 51 + pht('ID'), 52 + pht('Network'), 53 + pht('Address'), 54 + pht('Port'), 55 + null, 56 + )) 57 + ->setColumnClasses( 58 + array( 59 + '', 60 + 'wide', 61 + '', 62 + '', 63 + 'action', 64 + )); 65 + 66 + return $table; 67 + } 68 + 69 + }