@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 PhabricatorConduitConsoleController
4 extends PhabricatorConduitController {
5
6 public function shouldAllowPublic() {
7 return true;
8 }
9
10 public function handleRequest(AphrontRequest $request) {
11 $viewer = $this->getViewer();
12 $method_name = $request->getURIData('method');
13
14 $method = id(new PhabricatorConduitMethodQuery())
15 ->setViewer($viewer)
16 ->withMethods(array($method_name))
17 ->executeOne();
18 if (!$method) {
19 return new Aphront404Response();
20 }
21
22 $method->setViewer($viewer);
23
24 $call_uri = '/api/'.$method->getAPIMethodName();
25
26 $errors = array();
27
28 $form = id(new AphrontFormView())
29 ->setAction($call_uri)
30 ->setUser($request->getUser())
31 ->appendRemarkupInstructions(
32 pht(
33 'Enter parameters using **JSON**. For instance, to enter a '.
34 'list, type: `%s`',
35 '["apple", "banana", "cherry"]'));
36
37 $params = $method->getParamTypes();
38 foreach ($params as $param => $desc) {
39 $form->appendChild(
40 id(new AphrontFormTextControl())
41 ->setLabel($param)
42 ->setName("params[{$param}]")
43 ->setCaption($desc));
44 }
45
46 $must_login = !$viewer->isLoggedIn() &&
47 $method->shouldRequireAuthentication();
48 if ($must_login) {
49 $errors[] = pht(
50 'Login Required: This method requires authentication. You must '.
51 'log in before you can make calls to it.');
52 } else {
53 $form
54 ->appendChild(
55 id(new AphrontFormSelectControl())
56 ->setLabel(pht('Output Format'))
57 ->setName('output')
58 ->setOptions(
59 array(
60 'human' => pht('Human Readable'),
61 'json' => pht('JSON'),
62 )))
63 ->appendChild(
64 id(new AphrontFormSubmitControl())
65 ->addCancelButton($this->getApplicationURI())
66 ->setValue(pht('Call Method')));
67 }
68
69 $header = id(new PHUIHeaderView())
70 ->setUser($viewer)
71 ->setHeader($method->getAPIMethodName())
72 ->setHeaderIcon('fa-tty');
73
74 $form_box = id(new PHUIObjectBoxView())
75 ->setHeaderText(pht('Call Method'))
76 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
77 ->setForm($form);
78
79 $properties = $this->buildMethodProperties($method);
80
81 $info_box = id(new PHUIObjectBoxView())
82 ->setHeaderText(pht('API Method: %s', $method->getAPIMethodName()))
83 ->setFormErrors($errors)
84 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
85 ->appendChild($properties);
86
87 $crumbs = $this->buildApplicationCrumbs();
88 $crumbs->addTextCrumb($method->getAPIMethodName());
89 $crumbs->setBorder(true);
90
91 $documentation_pages = $method->getDocumentationPages($viewer);
92
93 $documentation_view = $this->newDocumentationView(
94 $method,
95 $documentation_pages);
96
97 $view = id(new PHUITwoColumnView())
98 ->setHeader($header)
99 ->setFooter(array(
100
101 id(new PhabricatorAnchorView())
102 ->setAnchorName('overview'),
103 $info_box,
104
105 id(new PhabricatorAnchorView())
106 ->setAnchorName('documentation'),
107 $documentation_view,
108
109 id(new PhabricatorAnchorView())
110 ->setAnchorName('call'),
111 $form_box,
112
113 id(new PhabricatorAnchorView())
114 ->setAnchorName('examples'),
115 $this->renderExampleBox($method, null),
116 ));
117
118 $title = $method->getAPIMethodName();
119
120 $nav = $this->newNavigationView($method, $documentation_pages);
121
122 return $this->newPage()
123 ->setTitle($title)
124 ->setCrumbs($crumbs)
125 ->setNavigation($nav)
126 ->appendChild($view);
127 }
128
129 /**
130 * @param ConduitAPIMethod $method
131 * @param array<ConduitAPIDocumentationPage> $documentation_pages
132 */
133 private function newDocumentationView(
134 ConduitAPIMethod $method,
135 array $documentation_pages) {
136 assert_instances_of(
137 $documentation_pages,
138 ConduitAPIDocumentationPage::class);
139
140 $viewer = $this->getViewer();
141
142 $description_properties = new PHUIPropertyListView();
143
144 $description_properties->addTextContent(
145 new PHUIRemarkupView($viewer, $method->getMethodDescription()));
146
147 $description_box = id(new PHUIObjectBoxView())
148 ->setHeaderText(pht('Method Description'))
149 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
150 ->appendChild($description_properties);
151
152 $view = array();
153 $view[] = $description_box;
154
155 foreach ($documentation_pages as $page) {
156 $view[] = $page->newView();
157 }
158
159 return $view;
160 }
161
162 /**
163 * @param ConduitAPIMethod $method
164 * @param array<ConduitAPIDocumentationPage> $documentation_pages
165 */
166 private function newNavigationView(
167 ConduitAPIMethod $method,
168 array $documentation_pages) {
169 assert_instances_of(
170 $documentation_pages,
171 ConduitAPIDocumentationPage::class);
172
173 $console_uri = urisprintf(
174 '/method/%s/',
175 $method->getAPIMethodName());
176 $console_uri = $this->getApplicationURI($console_uri);
177 $console_uri = new PhutilURI($console_uri);
178
179 $nav = id(new AphrontSideNavFilterView())
180 ->setBaseURI($console_uri);
181
182 $nav->selectFilter(null);
183
184 $nav->newLink('overview')
185 ->setHref('#overview')
186 ->setName(pht('Overview'))
187 ->setIcon('fa-list');
188
189 $nav->newLink('documentation')
190 ->setHref('#documentation')
191 ->setName(pht('Documentation'))
192 ->setIcon('fa-book');
193
194 foreach ($documentation_pages as $page) {
195 $nav->newLink($page->getAnchor())
196 ->setHref('#'.$page->getAnchor())
197 ->setName($page->getName())
198 ->setIcon($page->getIconIcon())
199 ->setIndented(true);
200 }
201
202 $nav->newLink('call')
203 ->setHref('#call')
204 ->setName(pht('Call Method'))
205 ->setIcon('fa-play');
206
207 $nav->newLink('examples')
208 ->setHref('#examples')
209 ->setName(pht('Examples'))
210 ->setIcon('fa-folder-open-o');
211
212 return $nav;
213 }
214
215 private function buildMethodProperties(ConduitAPIMethod $method) {
216 $viewer = $this->getViewer();
217
218 $view = new PHUIPropertyListView();
219
220 $status = $method->getMethodStatus();
221 $reason = $method->getMethodStatusDescription();
222
223 switch ($status) {
224 case ConduitAPIMethod::METHOD_STATUS_UNSTABLE:
225 $stability_icon = 'fa-exclamation-triangle yellow';
226 $stability_label = pht('Unstable Method');
227 $stability_info = nonempty(
228 $reason,
229 pht(
230 'This method is new and unstable. Its interface is subject '.
231 'to change.'));
232 break;
233 case ConduitAPIMethod::METHOD_STATUS_DEPRECATED:
234 $stability_icon = 'fa-exclamation-triangle red';
235 $stability_label = pht('Deprecated Method');
236 $stability_info = nonempty($reason, pht('This method is deprecated.'));
237 break;
238 case ConduitAPIMethod::METHOD_STATUS_FROZEN:
239 $stability_icon = 'fa-archive grey';
240 $stability_label = pht('Frozen Method');
241 $stability_info = nonempty(
242 $reason,
243 pht('This method is frozen and will eventually be deprecated.'));
244 break;
245 default:
246 $stability_label = null;
247 break;
248 }
249
250 if ($stability_label) {
251 $view->addProperty(
252 pht('Stability'),
253 array(
254 id(new PHUIIconView())->setIcon($stability_icon),
255 ' ',
256 phutil_tag('strong', array(), $stability_label.':'),
257 ' ',
258 $stability_info,
259 ));
260 }
261
262 $view->addProperty(
263 pht('Summary'),
264 $method->getMethodSummary());
265
266 $view->addProperty(
267 pht('Returns'),
268 $method->getReturnType());
269
270 $error_types = $method->getErrorTypes();
271 $error_types['ERR-CONDUIT-CORE'] = pht('See error message for details.');
272 $error_description = array();
273 foreach ($error_types as $error => $meaning) {
274 $error_description[] = hsprintf(
275 '<li><strong>%s:</strong> %s</li>',
276 $error,
277 $meaning);
278 }
279 $error_description = phutil_tag('ul', array(), $error_description);
280
281 $view->addProperty(
282 pht('Errors'),
283 $error_description);
284
285 $scope = $method->getRequiredScope();
286 switch ($scope) {
287 case ConduitAPIMethod::SCOPE_ALWAYS:
288 $oauth_icon = 'fa-globe green';
289 $oauth_description = pht(
290 'OAuth clients may always call this method.');
291 break;
292 case ConduitAPIMethod::SCOPE_NEVER:
293 $oauth_icon = 'fa-ban red';
294 $oauth_description = pht(
295 'OAuth clients may never call this method.');
296 break;
297 default:
298 $oauth_icon = 'fa-unlock-alt blue';
299 $oauth_description = pht(
300 'OAuth clients may call this method after requesting access to '.
301 'the "%s" scope.',
302 $scope);
303 break;
304 }
305
306 $view->addProperty(
307 pht('OAuth Scope'),
308 array(
309 id(new PHUIIconView())->setIcon($oauth_icon),
310 ' ',
311 $oauth_description,
312 ));
313
314 return $view;
315 }
316
317
318}