getViewer(); $name = $request->getURIData('name'); $device = id(new AlmanacDeviceQuery()) ->setViewer($viewer) ->withNames(array($name)) ->executeOne(); if (!$device) { return new Aphront404Response(); } // We rebuild locks on a device when viewing the detail page, so they // automatically get corrected if they fall out of sync. $device->rebuildDeviceLocks(); $title = pht('Device %s', $device->getName()); $property_list = $this->buildPropertyList($device); $action_list = $this->buildActionList($device); $property_list->setActionList($action_list); $header = id(new PHUIHeaderView()) ->setUser($viewer) ->setHeader($device->getName()) ->setPolicyObject($device); $box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addPropertyList($property_list); if ($device->getIsLocked()) { $this->addLockMessage( $box, pht( 'This device is bound to a locked service, so it can not be '. 'edited.')); } $interfaces = $this->buildInterfaceList($device); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($device->getName()); $timeline = $this->buildTransactionTimeline( $device, new AlmanacDeviceTransactionQuery()); $timeline->setShouldTerminate(true); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->appendChild( array( $box, $interfaces, $this->buildAlmanacPropertiesTable($device), $this->buildSSHKeysTable($device), $this->buildServicesTable($device), $timeline, )); } private function buildPropertyList(AlmanacDevice $device) { $viewer = $this->getViewer(); $properties = id(new PHUIPropertyListView()) ->setUser($viewer) ->setObject($device); return $properties; } private function buildActionList(AlmanacDevice $device) { $viewer = $this->getViewer(); $id = $device->getID(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $device, PhabricatorPolicyCapability::CAN_EDIT); $actions = id(new PhabricatorActionListView()) ->setUser($viewer); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setName(pht('Edit Device')) ->setHref($this->getApplicationURI("device/edit/{$id}/")) ->setWorkflow(!$can_edit) ->setDisabled(!$can_edit)); return $actions; } private function buildInterfaceList(AlmanacDevice $device) { $viewer = $this->getViewer(); $id = $device->getID(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $device, PhabricatorPolicyCapability::CAN_EDIT); $interfaces = id(new AlmanacInterfaceQuery()) ->setViewer($viewer) ->withDevicePHIDs(array($device->getPHID())) ->execute(); $table = id(new AlmanacInterfaceTableView()) ->setUser($viewer) ->setInterfaces($interfaces) ->setCanEdit($can_edit); $header = id(new PHUIHeaderView()) ->setHeader(pht('Device Interfaces')) ->addActionLink( id(new PHUIButtonView()) ->setTag('a') ->setHref($this->getApplicationURI("interface/edit/?deviceID={$id}")) ->setWorkflow(!$can_edit) ->setDisabled(!$can_edit) ->setText(pht('Add Interface')) ->setIcon( id(new PHUIIconView()) ->setIconFont('fa-plus'))); return id(new PHUIObjectBoxView()) ->setHeader($header) ->setTable($table); } private function buildSSHKeysTable(AlmanacDevice $device) { $viewer = $this->getViewer(); $id = $device->getID(); $device_phid = $device->getPHID(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $device, PhabricatorPolicyCapability::CAN_EDIT); $keys = id(new PhabricatorAuthSSHKeyQuery()) ->setViewer($viewer) ->withObjectPHIDs(array($device_phid)) ->execute(); $table = id(new PhabricatorAuthSSHKeyTableView()) ->setUser($viewer) ->setKeys($keys) ->setCanEdit($can_edit) ->setShowID(true) ->setShowTrusted(true) ->setNoDataString(pht('This device has no associated SSH public keys.')); try { PhabricatorSSHKeyGenerator::assertCanGenerateKeypair(); $can_generate = true; } catch (Exception $ex) { $can_generate = false; } $generate_uri = '/auth/sshkey/generate/?objectPHID='.$device_phid; $upload_uri = '/auth/sshkey/upload/?objectPHID='.$device_phid; $header = id(new PHUIHeaderView()) ->setHeader(pht('SSH Public Keys')) ->addActionLink( id(new PHUIButtonView()) ->setTag('a') ->setHref($generate_uri) ->setWorkflow(true) ->setDisabled(!$can_edit || !$can_generate) ->setText(pht('Generate Keypair')) ->setIcon( id(new PHUIIconView()) ->setIconFont('fa-lock'))) ->addActionLink( id(new PHUIButtonView()) ->setTag('a') ->setHref($upload_uri) ->setWorkflow(true) ->setDisabled(!$can_edit) ->setText(pht('Upload Public Key')) ->setIcon( id(new PHUIIconView()) ->setIconFont('fa-upload'))); return id(new PHUIObjectBoxView()) ->setHeader($header) ->setTable($table); } private function buildServicesTable(AlmanacDevice $device) { $viewer = $this->getViewer(); // NOTE: We're loading all services so we can show hidden, locked services. // In general, we let you know about all the things the device is bound to, // even if you don't have permission to see their details. This is similar // to exposing the existence of edges in other applications, with the // addition of always letting you see that locks exist. $services = id(new AlmanacServiceQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withDevicePHIDs(array($device->getPHID())) ->execute(); $handles = $viewer->loadHandles(mpull($services, 'getPHID')); $icon_lock = id(new PHUIIconView()) ->setIconFont('fa-lock'); $rows = array(); foreach ($services as $service) { $rows[] = array( ($service->getIsLocked() ? $icon_lock : null), $handles->renderHandle($service->getPHID()), ); } $table = id(new AphrontTableView($rows)) ->setNoDataString(pht('No services are bound to this device.')) ->setHeaders( array( null, pht('Service'), )) ->setColumnClasses( array( null, 'wide pri', )); return id(new PHUIObjectBoxView()) ->setHeaderText(pht('Bound Services')) ->setTable($table); } }