@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<?php
2
3final class AlmanacDeviceViewController
4 extends AlmanacDeviceController {
5
6 public function shouldAllowPublic() {
7 return true;
8 }
9
10 public function handleRequest(AphrontRequest $request) {
11 $viewer = $request->getViewer();
12
13 $name = $request->getURIData('name');
14
15 $device = id(new AlmanacDeviceQuery())
16 ->setViewer($viewer)
17 ->withNames(array($name))
18 ->needProperties(true)
19 ->executeOne();
20 if (!$device) {
21 return new Aphront404Response();
22 }
23
24 $title = pht('Device %s', $device->getName());
25
26 $curtain = $this->buildCurtain($device);
27
28 $header = id(new PHUIHeaderView())
29 ->setUser($viewer)
30 ->setHeader($device->getName())
31 ->setPolicyObject($device)
32 ->setHeaderIcon('fa-server');
33
34 $status = $device->getStatusObject();
35 if ($status->hasStatusTag()) {
36 $header->setStatus(
37 $status->getStatusTagIcon(),
38 $status->getStatusTagColor(),
39 $status->getName());
40 }
41
42 $issue = null;
43 if ($device->isClusterDevice()) {
44 $issue = $this->addClusterMessage(
45 pht('This device is bound to a cluster service.'),
46 pht(
47 'This device is bound to a cluster service. You do not have '.
48 'permission to manage cluster services, so the device can not '.
49 'be edited.'));
50 }
51
52 $interfaces = $this->buildInterfaceList($device);
53
54 $crumbs = $this->buildApplicationCrumbs();
55 $crumbs->addTextCrumb($device->getName());
56 $crumbs->setBorder(true);
57
58 $timeline = $this->buildTransactionTimeline(
59 $device,
60 new AlmanacDeviceTransactionQuery());
61 $timeline->setShouldTerminate(true);
62
63 $view = id(new PHUITwoColumnView())
64 ->setHeader($header)
65 ->setCurtain($curtain)
66 ->setMainColumn(array(
67 $issue,
68 $interfaces,
69 $this->buildAlmanacPropertiesTable($device),
70 $this->buildSSHKeysTable($device),
71 $this->buildServicesTable($device),
72 $timeline,
73 ));
74
75 return $this->newPage()
76 ->setTitle($title)
77 ->setCrumbs($crumbs)
78 ->appendChild(
79 array(
80 $view,
81 ));
82 }
83
84 private function buildCurtain(AlmanacDevice $device) {
85 $viewer = $this->getViewer();
86
87 $can_edit = PhabricatorPolicyFilter::hasCapability(
88 $viewer,
89 $device,
90 PhabricatorPolicyCapability::CAN_EDIT);
91
92 $id = $device->getID();
93 $edit_uri = $this->getApplicationURI("device/edit/{$id}/");
94
95 $curtain = $this->newCurtainView($device);
96
97 $curtain->addAction(
98 id(new PhabricatorActionView())
99 ->setIcon('fa-pencil')
100 ->setName(pht('Edit Device'))
101 ->setHref($edit_uri)
102 ->setWorkflow(!$can_edit)
103 ->setDisabled(!$can_edit));
104
105 return $curtain;
106 }
107
108 private function buildInterfaceList(AlmanacDevice $device) {
109 $viewer = $this->getViewer();
110 $id = $device->getID();
111
112 $can_edit = PhabricatorPolicyFilter::hasCapability(
113 $viewer,
114 $device,
115 PhabricatorPolicyCapability::CAN_EDIT);
116
117 $interfaces = id(new AlmanacInterfaceQuery())
118 ->setViewer($viewer)
119 ->withDevicePHIDs(array($device->getPHID()))
120 ->execute();
121
122 $table = id(new AlmanacInterfaceTableView())
123 ->setUser($viewer)
124 ->setInterfaces($interfaces)
125 ->setCanEdit($can_edit);
126
127 $header = id(new PHUIHeaderView())
128 ->setHeader(pht('Device Interfaces'))
129 ->addActionLink(
130 id(new PHUIButtonView())
131 ->setTag('a')
132 ->setHref($this->getApplicationURI("interface/edit/?deviceID={$id}"))
133 ->setWorkflow(!$can_edit)
134 ->setDisabled(!$can_edit)
135 ->setText(pht('Add Interface'))
136 ->setIcon('fa-plus'));
137
138 return id(new PHUIObjectBoxView())
139 ->setHeader($header)
140 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
141 ->setTable($table);
142 }
143
144 private function buildSSHKeysTable(AlmanacDevice $device) {
145 $viewer = $this->getViewer();
146 $id = $device->getID();
147 $device_phid = $device->getPHID();
148
149 $can_edit = PhabricatorPolicyFilter::hasCapability(
150 $viewer,
151 $device,
152 PhabricatorPolicyCapability::CAN_EDIT);
153
154 $keys = id(new PhabricatorAuthSSHKeyQuery())
155 ->setViewer($viewer)
156 ->withObjectPHIDs(array($device_phid))
157 ->withIsActive(true)
158 ->execute();
159
160 $table = id(new PhabricatorAuthSSHKeyTableView())
161 ->setUser($viewer)
162 ->setKeys($keys)
163 ->setCanEdit($can_edit)
164 ->setShowID(true)
165 ->setShowTrusted(true)
166 ->setNoDataString(pht('This device has no associated SSH public keys.'));
167
168 $menu_button = PhabricatorAuthSSHKeyTableView::newKeyActionsMenu(
169 $viewer,
170 $device);
171
172 $header = id(new PHUIHeaderView())
173 ->setHeader(pht('SSH Public Keys'))
174 ->addActionLink($menu_button);
175
176 return id(new PHUIObjectBoxView())
177 ->setHeader($header)
178 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
179 ->setTable($table);
180 }
181
182 private function buildServicesTable(AlmanacDevice $device) {
183 $viewer = $this->getViewer();
184
185 // NOTE: We're loading all services so we can show hidden, locked services.
186 // In general, we let you know about all the things the device is bound to,
187 // even if you don't have permission to see their details. This is similar
188 // to exposing the existence of edges in other applications, with the
189 // addition of always letting you see that locks exist.
190
191 $services = id(new AlmanacServiceQuery())
192 ->setViewer(PhabricatorUser::getOmnipotentUser())
193 ->withDevicePHIDs(array($device->getPHID()))
194 ->execute();
195
196 $handles = $viewer->loadHandles(mpull($services, 'getPHID'));
197
198 $icon_cluster = id(new PHUIIconView())
199 ->setIcon('fa-sitemap');
200
201 $rows = array();
202 foreach ($services as $service) {
203 $rows[] = array(
204 ($service->isClusterService()
205 ? $icon_cluster
206 : null),
207 $handles->renderHandle($service->getPHID()),
208 );
209 }
210
211 $table = id(new AphrontTableView($rows))
212 ->setNoDataString(pht('No services are bound to this device.'))
213 ->setHeaders(
214 array(
215 null,
216 pht('Service'),
217 ))
218 ->setColumnClasses(
219 array(
220 null,
221 'wide pri',
222 ));
223
224 return id(new PHUIObjectBoxView())
225 ->setHeaderText(pht('Bound Services'))
226 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
227 ->setTable($table);
228 }
229
230
231}