Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/conduit/call/ConduitCall.php
12256 views
1
<?php
2
3
/**
4
* Run a conduit method in-process, without requiring HTTP requests. Usage:
5
*
6
* $call = new ConduitCall('method.name', array('param' => 'value'));
7
* $call->setUser($user);
8
* $result = $call->execute();
9
*
10
*/
11
final class ConduitCall extends Phobject {
12
13
private $method;
14
private $handler;
15
private $request;
16
private $user;
17
18
public function __construct($method, array $params, $strictly_typed = true) {
19
$this->method = $method;
20
$this->handler = $this->buildMethodHandler($method);
21
22
$param_types = $this->handler->getParamTypes();
23
24
foreach ($param_types as $key => $spec) {
25
if (ConduitAPIMethod::getParameterMetadataKey($key) !== null) {
26
throw new ConduitException(
27
pht(
28
'API Method "%s" defines a disallowed parameter, "%s". This '.
29
'parameter name is reserved.',
30
$method,
31
$key));
32
}
33
}
34
35
$invalid_params = array_diff_key($params, $param_types);
36
if ($invalid_params) {
37
throw new ConduitException(
38
pht(
39
'API Method "%s" does not define these parameters: %s.',
40
$method,
41
"'".implode("', '", array_keys($invalid_params))."'"));
42
}
43
44
$this->request = new ConduitAPIRequest($params, $strictly_typed);
45
}
46
47
public function getAPIRequest() {
48
return $this->request;
49
}
50
51
public function setUser(PhabricatorUser $user) {
52
$this->user = $user;
53
return $this;
54
}
55
56
public function getUser() {
57
return $this->user;
58
}
59
60
public function shouldRequireAuthentication() {
61
return $this->handler->shouldRequireAuthentication();
62
}
63
64
public function shouldAllowUnguardedWrites() {
65
return $this->handler->shouldAllowUnguardedWrites();
66
}
67
68
public function getErrorDescription($code) {
69
return $this->handler->getErrorDescription($code);
70
}
71
72
public function execute() {
73
$profiler = PhutilServiceProfiler::getInstance();
74
$call_id = $profiler->beginServiceCall(
75
array(
76
'type' => 'conduit',
77
'method' => $this->method,
78
));
79
80
try {
81
$result = $this->executeMethod();
82
} catch (Exception $ex) {
83
$profiler->endServiceCall($call_id, array());
84
throw $ex;
85
}
86
87
$profiler->endServiceCall($call_id, array());
88
return $result;
89
}
90
91
private function executeMethod() {
92
$user = $this->getUser();
93
if (!$user) {
94
$user = new PhabricatorUser();
95
}
96
97
$this->request->setUser($user);
98
99
if (!$this->shouldRequireAuthentication()) {
100
// No auth requirement here.
101
} else {
102
103
$allow_public = $this->handler->shouldAllowPublic() &&
104
PhabricatorEnv::getEnvConfig('policy.allow-public');
105
if (!$allow_public) {
106
if (!$user->isLoggedIn() && !$user->isOmnipotent()) {
107
// TODO: As per below, this should get centralized and cleaned up.
108
throw new ConduitException('ERR-INVALID-AUTH');
109
}
110
}
111
112
// TODO: This would be slightly cleaner by just using a Query, but the
113
// Conduit auth workflow requires the Call and User be built separately.
114
// Just do it this way for the moment.
115
$application = $this->handler->getApplication();
116
if ($application) {
117
$can_view = PhabricatorPolicyFilter::hasCapability(
118
$user,
119
$application,
120
PhabricatorPolicyCapability::CAN_VIEW);
121
122
if (!$can_view) {
123
throw new ConduitException(
124
pht(
125
'You do not have access to the application which provides this '.
126
'API method.'));
127
}
128
}
129
}
130
131
return $this->handler->executeMethod($this->request);
132
}
133
134
protected function buildMethodHandler($method_name) {
135
$method = ConduitAPIMethod::getConduitMethod($method_name);
136
137
if (!$method) {
138
throw new ConduitMethodDoesNotExistException($method_name);
139
}
140
141
$application = $method->getApplication();
142
if ($application && !$application->isInstalled()) {
143
$app_name = $application->getName();
144
throw new ConduitApplicationNotInstalledException($method, $app_name);
145
}
146
147
return $method;
148
}
149
150
public function getMethodImplementation() {
151
return $this->handler;
152
}
153
154
155
}
156
157