Page MenuHomestyx hydra

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/src/applications/almanac/conduit/AlmanacQueryDevicesConduitAPIMethod.php b/src/applications/almanac/conduit/AlmanacQueryDevicesConduitAPIMethod.php
index 8225ddd1b0..b0a593a381 100644
--- a/src/applications/almanac/conduit/AlmanacQueryDevicesConduitAPIMethod.php
+++ b/src/applications/almanac/conduit/AlmanacQueryDevicesConduitAPIMethod.php
@@ -1,67 +1,63 @@
<?php
final class AlmanacQueryDevicesConduitAPIMethod
extends AlmanacConduitAPIMethod {
public function getAPIMethodName() {
return 'almanac.querydevices';
}
public function getMethodDescription() {
return pht('Query Almanac devices.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<id>',
'phids' => 'optional list<phid>',
'names' => 'optional list<phid>',
) + self::getPagerParamTypes();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<wild>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$query = id(new AlmanacDeviceQuery())
->setViewer($viewer);
$ids = $request->getValue('ids');
if ($ids !== null) {
$query->withIDs($ids);
}
$phids = $request->getValue('phids');
if ($phids !== null) {
$query->withPHIDs($phids);
}
$names = $request->getValue('names');
if ($names !== null) {
$query->withNames($names);
}
$pager = $this->newPager($request);
$devices = $query->executeWithCursorPager($pager);
$data = array();
foreach ($devices as $device) {
$data[] = $this->getDeviceDictionary($device);
}
$results = array(
'data' => $data,
);
return $this->addPagerResults($results, $pager);
}
}
diff --git a/src/applications/almanac/conduit/AlmanacQueryServicesConduitAPIMethod.php b/src/applications/almanac/conduit/AlmanacQueryServicesConduitAPIMethod.php
index 4cd019fed3..81e59d072f 100644
--- a/src/applications/almanac/conduit/AlmanacQueryServicesConduitAPIMethod.php
+++ b/src/applications/almanac/conduit/AlmanacQueryServicesConduitAPIMethod.php
@@ -1,90 +1,86 @@
<?php
final class AlmanacQueryServicesConduitAPIMethod
extends AlmanacConduitAPIMethod {
public function getAPIMethodName() {
return 'almanac.queryservices';
}
public function getMethodDescription() {
return pht('Query Almanac services.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<id>',
'phids' => 'optional list<phid>',
'names' => 'optional list<phid>',
'devicePHIDs' => 'optional list<phid>',
'serviceClasses' => 'optional list<string>',
) + self::getPagerParamTypes();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<wild>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$query = id(new AlmanacServiceQuery())
->setViewer($viewer)
->needBindings(true);
$ids = $request->getValue('ids');
if ($ids !== null) {
$query->withIDs($ids);
}
$phids = $request->getValue('phids');
if ($phids !== null) {
$query->withPHIDs($phids);
}
$names = $request->getValue('names');
if ($names !== null) {
$query->withNames($names);
}
$classes = $request->getValue('serviceClasses');
if ($classes !== null) {
$query->withServiceClasses($classes);
}
$device_phids = $request->getValue('devicePHIDs');
if ($device_phids !== null) {
$query->withDevicePHIDs($device_phids);
}
$pager = $this->newPager($request);
$services = $query->executeWithCursorPager($pager);
$data = array();
foreach ($services as $service) {
$phid = $service->getPHID();
$service_bindings = $service->getBindings();
$service_bindings = array_values($service_bindings);
foreach ($service_bindings as $key => $service_binding) {
$service_bindings[$key] = $this->getBindingDictionary($service_binding);
}
$data[] = $this->getServiceDictionary($service) + array(
'bindings' => $service_bindings,
);
}
$results = array(
'data' => $data,
);
return $this->addPagerResults($results, $pager);
}
}
diff --git a/src/applications/arcanist/conduit/ArcanistProjectInfoConduitAPIMethod.php b/src/applications/arcanist/conduit/ArcanistProjectInfoConduitAPIMethod.php
index aad4650ce6..677c4985aa 100644
--- a/src/applications/arcanist/conduit/ArcanistProjectInfoConduitAPIMethod.php
+++ b/src/applications/arcanist/conduit/ArcanistProjectInfoConduitAPIMethod.php
@@ -1,70 +1,70 @@
<?php
final class ArcanistProjectInfoConduitAPIMethod
extends ArcanistConduitAPIMethod {
public function getAPIMethodName() {
return 'arcanist.projectinfo';
}
public function getMethodDescription() {
return 'Get information about Arcanist projects.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'name' => 'required string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-BAD-ARCANIST-PROJECT' => 'No such project exists.',
);
}
protected function execute(ConduitAPIRequest $request) {
$name = $request->getValue('name');
$project = id(new PhabricatorRepositoryArcanistProject())->loadOneWhere(
'name = %s',
$name);
if (!$project) {
throw new ConduitException('ERR-BAD-ARCANIST-PROJECT');
}
$repository = null;
if ($project->getRepositoryID()) {
$repository = id(new PhabricatorRepositoryQuery())
->setViewer($request->getUser())
->withIDs(array($project->getRepositoryID()))
->executeOne();
}
$repository_phid = null;
$tracked = false;
$encoding = null;
$dictionary = array();
if ($repository) {
$repository_phid = $repository->getPHID();
$tracked = $repository->isTracked();
$encoding = $repository->getDetail('encoding');
$dictionary = $repository->toDictionary();
}
return array(
'name' => $project->getName(),
'phid' => $project->getPHID(),
'repositoryPHID' => $repository_phid,
'tracked' => $tracked,
'encoding' => $encoding,
'repository' => $dictionary,
);
}
}
diff --git a/src/applications/audit/conduit/AuditQueryConduitAPIMethod.php b/src/applications/audit/conduit/AuditQueryConduitAPIMethod.php
index 9b24b6866b..d5a02810f8 100644
--- a/src/applications/audit/conduit/AuditQueryConduitAPIMethod.php
+++ b/src/applications/audit/conduit/AuditQueryConduitAPIMethod.php
@@ -1,96 +1,91 @@
<?php
final class AuditQueryConduitAPIMethod extends AuditConduitAPIMethod {
public function getAPIMethodName() {
return 'audit.query';
}
public function getMethodDescription() {
return 'Query audit requests.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$statuses = array(
DiffusionCommitQuery::AUDIT_STATUS_ANY,
DiffusionCommitQuery::AUDIT_STATUS_OPEN,
DiffusionCommitQuery::AUDIT_STATUS_CONCERN,
DiffusionCommitQuery::AUDIT_STATUS_ACCEPTED,
DiffusionCommitQuery::AUDIT_STATUS_PARTIAL,
);
$status_const = $this->formatStringConstants($statuses);
return array(
'auditorPHIDs' => 'optional list<phid>',
'commitPHIDs' => 'optional list<phid>',
'status' => ('optional '.$status_const.
' (default = "audit-status-any")'),
'offset' => 'optional int',
'limit' => 'optional int (default = 100)',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$query = id(new DiffusionCommitQuery())
->setViewer($request->getUser());
$auditor_phids = $request->getValue('auditorPHIDs', array());
if ($auditor_phids) {
$query->withAuditorPHIDs($auditor_phids);
}
$commit_phids = $request->getValue('commitPHIDs', array());
if ($commit_phids) {
$query->withPHIDs($commit_phids);
}
$status = $request->getValue(
'status',
DiffusionCommitQuery::AUDIT_STATUS_ANY);
$query->withAuditStatus($status);
// NOTE: These affect the number of commits identified, which is sort of
// reasonable but means the method may return an arbitrary number of
// actual audit requests.
$query->setOffset($request->getValue('offset', 0));
$query->setLimit($request->getValue('limit', 100));
$commits = $query->execute();
$auditor_map = array_fuse($auditor_phids);
$results = array();
foreach ($commits as $commit) {
$requests = $commit->getAudits();
foreach ($requests as $request) {
// If this audit isn't triggered for one of the requested PHIDs,
// skip it.
if ($auditor_map && empty($auditor_map[$request->getAuditorPHID()])) {
continue;
}
$results[] = array(
'id' => $request->getID(),
'commitPHID' => $request->getCommitPHID(),
'auditorPHID' => $request->getAuditorPHID(),
'reasons' => $request->getAuditReasons(),
'status' => $request->getAuditStatus(),
);
}
}
return $results;
}
}
diff --git a/src/applications/auth/conduit/PhabricatorAuthQueryPublicKeysConduitAPIMethod.php b/src/applications/auth/conduit/PhabricatorAuthQueryPublicKeysConduitAPIMethod.php
index a2e3d55d21..e7d036aee4 100644
--- a/src/applications/auth/conduit/PhabricatorAuthQueryPublicKeysConduitAPIMethod.php
+++ b/src/applications/auth/conduit/PhabricatorAuthQueryPublicKeysConduitAPIMethod.php
@@ -1,77 +1,73 @@
<?php
final class PhabricatorAuthQueryPublicKeysConduitAPIMethod
extends PhabricatorAuthConduitAPIMethod {
public function getAPIMethodName() {
return 'auth.querypublickeys';
}
public function getMethodDescription() {
return pht('Query public keys.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<id>',
'objectPHIDs' => 'optional list<phid>',
'keys' => 'optional list<string>',
) + self::getPagerParamTypes();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'result-set';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$query = id(new PhabricatorAuthSSHKeyQuery())
->setViewer($viewer);
$ids = $request->getValue('ids');
if ($ids !== null) {
$query->withIDs($ids);
}
$object_phids = $request->getValue('objectPHIDs');
if ($object_phids !== null) {
$query->withObjectPHIDs($object_phids);
}
$keys = $request->getValue('keys');
if ($keys !== null) {
$key_objects = array();
foreach ($keys as $key) {
$key_objects[] = PhabricatorAuthSSHPublicKey::newFromRawKey($key);
}
$query->withKeys($key_objects);
}
$pager = $this->newPager($request);
$public_keys = $query->executeWithCursorPager($pager);
$data = array();
foreach ($public_keys as $public_key) {
$data[] = array(
'id' => $public_key->getID(),
'name' => $public_key->getName(),
'objectPHID' => $public_key->getObjectPHID(),
'isTrusted' => (bool)$public_key->getIsTrusted(),
'key' => $public_key->getEntireKey(),
);
}
$results = array(
'data' => $data,
);
return $this->addPagerResults($results, $pager);
}
}
diff --git a/src/applications/chatlog/conduit/ChatLogQueryConduitAPIMethod.php b/src/applications/chatlog/conduit/ChatLogQueryConduitAPIMethod.php
index 2259d6c4db..8270ced921 100644
--- a/src/applications/chatlog/conduit/ChatLogQueryConduitAPIMethod.php
+++ b/src/applications/chatlog/conduit/ChatLogQueryConduitAPIMethod.php
@@ -1,63 +1,59 @@
<?php
final class ChatLogQueryConduitAPIMethod extends ChatLogConduitAPIMethod {
public function getAPIMethodName() {
return 'chatlog.query';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return 'Retrieve chatter.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'channels' => 'optional list<string>',
'limit' => 'optional int (default = 100)',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty list<dict>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$query = new PhabricatorChatLogQuery();
$channel_ids = $request->getValue('channelIDs');
if ($channel_ids) {
$query->withChannelIDs($channel_ids);
}
$limit = $request->getValue('limit');
if (!$limit) {
$limit = 100;
}
$query->setLimit($limit);
$logs = $query->execute();
$results = array();
foreach ($logs as $log) {
$results[] = array(
'channelID' => $log->getChannelID(),
'epoch' => $log->getEpoch(),
'author' => $log->getAuthor(),
'type' => $log->getType(),
'message' => $log->getMessage(),
'loggedByPHID' => $log->getLoggedByPHID(),
);
}
return $results;
}
}
diff --git a/src/applications/chatlog/conduit/ChatLogRecordConduitAPIMethod.php b/src/applications/chatlog/conduit/ChatLogRecordConduitAPIMethod.php
index 4c7a8d5cff..ca94b91dcc 100644
--- a/src/applications/chatlog/conduit/ChatLogRecordConduitAPIMethod.php
+++ b/src/applications/chatlog/conduit/ChatLogRecordConduitAPIMethod.php
@@ -1,76 +1,72 @@
<?php
final class ChatLogRecordConduitAPIMethod extends ChatLogConduitAPIMethod {
public function getAPIMethodName() {
return 'chatlog.record';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return 'Record chatter.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'logs' => 'required list<dict>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<id>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$logs = $request->getValue('logs');
if (!is_array($logs)) {
$logs = array();
}
$template = new PhabricatorChatLogEvent();
$template->setLoggedByPHID($request->getUser()->getPHID());
$objs = array();
foreach ($logs as $log) {
$channel_name = idx($log, 'channel');
$service_name = idx($log, 'serviceName');
$service_type = idx($log, 'serviceType');
$channel = id(new PhabricatorChatLogChannel())->loadOneWhere(
'channelName = %s AND serviceName = %s AND serviceType = %s',
$channel_name,
$service_name,
$service_type);
if (!$channel) {
$channel = id(new PhabricatorChatLogChannel())
->setChannelName($channel_name)
->setserviceName($service_name)
->setServiceType($service_type)
->setViewPolicy(PhabricatorPolicies::POLICY_USER)
->setEditPolicy(PhabricatorPolicies::POLICY_USER)
->save();
}
$obj = clone $template;
$obj->setChannelID($channel->getID());
$obj->setType(idx($log, 'type'));
$obj->setAuthor(idx($log, 'author'));
$obj->setEpoch(idx($log, 'epoch'));
$obj->setMessage(idx($log, 'message'));
$obj->save();
$objs[] = $obj;
}
return array_values(mpull($objs, 'getID'));
}
}
diff --git a/src/applications/conduit/call/ConduitCall.php b/src/applications/conduit/call/ConduitCall.php
index 9215e4bc15..aa55d1b895 100644
--- a/src/applications/conduit/call/ConduitCall.php
+++ b/src/applications/conduit/call/ConduitCall.php
@@ -1,154 +1,154 @@
<?php
/**
* Run a conduit method in-process, without requiring HTTP requests. Usage:
*
* $call = new ConduitCall('method.name', array('param' => 'value'));
* $call->setUser($user);
* $result = $call->execute();
*
*/
final class ConduitCall {
private $method;
private $request;
private $user;
public function __construct($method, array $params) {
- $this->method = $method;
- $this->handler = $this->buildMethodHandler($method);
+ $this->method = $method;
+ $this->handler = $this->buildMethodHandler($method);
- $param_types = $this->handler->defineParamTypes();
+ $param_types = $this->handler->getParamTypes();
foreach ($param_types as $key => $spec) {
if (ConduitAPIMethod::getParameterMetadataKey($key) !== null) {
throw new ConduitException(
pht(
'API Method "%s" defines a disallowed parameter, "%s". This '.
'parameter name is reserved.',
$method,
$key));
}
}
$invalid_params = array_diff_key($params, $param_types);
if ($invalid_params) {
throw new ConduitException(
pht(
'API Method "%s" does not define these parameters: %s.',
$method,
"'".implode("', '", array_keys($invalid_params))."'"));
}
$this->request = new ConduitAPIRequest($params);
}
public function getAPIRequest() {
return $this->request;
}
public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
public function getUser() {
return $this->user;
}
public function shouldRequireAuthentication() {
return $this->handler->shouldRequireAuthentication();
}
public function shouldAllowUnguardedWrites() {
return $this->handler->shouldAllowUnguardedWrites();
}
public function getRequiredScope() {
return $this->handler->getRequiredScope();
}
public function getErrorDescription($code) {
return $this->handler->getErrorDescription($code);
}
public function execute() {
$profiler = PhutilServiceProfiler::getInstance();
$call_id = $profiler->beginServiceCall(
array(
'type' => 'conduit',
'method' => $this->method,
));
try {
$result = $this->executeMethod();
} catch (Exception $ex) {
$profiler->endServiceCall($call_id, array());
throw $ex;
}
$profiler->endServiceCall($call_id, array());
return $result;
}
private function executeMethod() {
$user = $this->getUser();
if (!$user) {
$user = new PhabricatorUser();
}
$this->request->setUser($user);
if (!$this->shouldRequireAuthentication()) {
// No auth requirement here.
} else {
$allow_public = $this->handler->shouldAllowPublic() &&
PhabricatorEnv::getEnvConfig('policy.allow-public');
if (!$allow_public) {
if (!$user->isLoggedIn() && !$user->isOmnipotent()) {
// TODO: As per below, this should get centralized and cleaned up.
throw new ConduitException('ERR-INVALID-AUTH');
}
}
// TODO: This would be slightly cleaner by just using a Query, but the
// Conduit auth workflow requires the Call and User be built separately.
// Just do it this way for the moment.
$application = $this->handler->getApplication();
if ($application) {
$can_view = PhabricatorPolicyFilter::hasCapability(
$user,
$application,
PhabricatorPolicyCapability::CAN_VIEW);
if (!$can_view) {
throw new ConduitException(
pht(
'You do not have access to the application which provides this '.
'API method.'));
}
}
}
return $this->handler->executeMethod($this->request);
}
protected function buildMethodHandler($method_name) {
$method = ConduitAPIMethod::getConduitMethod($method_name);
if (!$method) {
throw new ConduitMethodDoesNotExistException($method_name);
}
$application = $method->getApplication();
if ($application && !$application->isInstalled()) {
$app_name = $application->getName();
throw new ConduitApplicationNotInstalledException($method, $app_name);
}
return $method;
}
}
diff --git a/src/applications/conduit/controller/PhabricatorConduitConsoleController.php b/src/applications/conduit/controller/PhabricatorConduitConsoleController.php
index aa541bdd06..1e0c7eb276 100644
--- a/src/applications/conduit/controller/PhabricatorConduitConsoleController.php
+++ b/src/applications/conduit/controller/PhabricatorConduitConsoleController.php
@@ -1,137 +1,137 @@
<?php
final class PhabricatorConduitConsoleController
extends PhabricatorConduitController {
private $method;
public function shouldAllowPublic() {
return true;
}
public function willProcessRequest(array $data) {
$this->method = $data['method'];
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$method = id(new PhabricatorConduitMethodQuery())
->setViewer($viewer)
->withMethods(array($this->method))
->executeOne();
if (!$method) {
return new Aphront404Response();
}
$can_call_method = false;
$status = $method->getMethodStatus();
$reason = $method->getMethodStatusDescription();
$errors = array();
switch ($status) {
case ConduitAPIMethod::METHOD_STATUS_DEPRECATED:
$reason = nonempty($reason, pht('This method is deprecated.'));
$errors[] = pht('Deprecated Method: %s', $reason);
break;
case ConduitAPIMethod::METHOD_STATUS_UNSTABLE:
$reason = nonempty(
$reason,
pht(
'This method is new and unstable. Its interface is subject '.
'to change.'));
$errors[] = pht('Unstable Method: %s', $reason);
break;
}
- $error_types = $method->defineErrorTypes();
+ $error_types = $method->getErrorTypes();
$error_types['ERR-CONDUIT-CORE'] = pht('See error message for details.');
$error_description = array();
foreach ($error_types as $error => $meaning) {
$error_description[] = hsprintf(
'<li><strong>%s:</strong> %s</li>',
$error,
$meaning);
}
$error_description = phutil_tag('ul', array(), $error_description);
$form = new AphrontFormView();
$form
->setUser($request->getUser())
->setAction('/api/'.$this->method)
->appendChild(
id(new AphrontFormStaticControl())
->setLabel('Description')
->setValue($method->getMethodDescription()))
->appendChild(
id(new AphrontFormStaticControl())
->setLabel('Returns')
- ->setValue($method->defineReturnType()))
+ ->setValue($method->getReturnType()))
->appendChild(
id(new AphrontFormMarkupControl())
->setLabel('Errors')
->setValue($error_description))
->appendChild(hsprintf(
'<p class="aphront-form-instructions">Enter parameters using '.
'<strong>JSON</strong>. For instance, to enter a list, type: '.
'<tt>["apple", "banana", "cherry"]</tt>'));
- $params = $method->defineParamTypes();
+ $params = $method->getParamTypes();
foreach ($params as $param => $desc) {
$form->appendChild(
id(new AphrontFormTextControl())
->setLabel($param)
->setName("params[{$param}]")
->setCaption($desc));
}
$must_login = !$viewer->isLoggedIn() &&
$method->shouldRequireAuthentication();
if ($must_login) {
$errors[] = pht(
'Login Required: This method requires authentication. You must '.
'log in before you can make calls to it.');
} else {
$form
->appendChild(
id(new AphrontFormSelectControl())
->setLabel('Output Format')
->setName('output')
->setOptions(
array(
'human' => 'Human Readable',
'json' => 'JSON',
)))
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton($this->getApplicationURI())
->setValue(pht('Call Method')));
}
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setHeader($method->getAPIMethodName());
$form_box = id(new PHUIObjectBoxView())
->setHeader($header)
->setFormErrors($errors)
->setForm($form);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($method->getAPIMethodName());
return $this->buildApplicationPage(
array(
$crumbs,
$form_box,
),
array(
'title' => $method->getAPIMethodName(),
));
}
}
diff --git a/src/applications/conduit/method/ConduitAPIMethod.php b/src/applications/conduit/method/ConduitAPIMethod.php
index 3e28d6899e..f964684d71 100644
--- a/src/applications/conduit/method/ConduitAPIMethod.php
+++ b/src/applications/conduit/method/ConduitAPIMethod.php
@@ -1,308 +1,325 @@
<?php
/**
* @task status Method Status
* @task pager Paging Results
*/
abstract class ConduitAPIMethod
extends Phobject
implements PhabricatorPolicyInterface {
const METHOD_STATUS_STABLE = 'stable';
const METHOD_STATUS_UNSTABLE = 'unstable';
const METHOD_STATUS_DEPRECATED = 'deprecated';
abstract public function getMethodDescription();
- abstract public function defineParamTypes();
- abstract public function defineReturnType();
- abstract public function defineErrorTypes();
+ abstract protected function defineParamTypes();
+ abstract protected function defineReturnType();
+
+ protected function defineErrorTypes() {
+ return array();
+ }
+
abstract protected function execute(ConduitAPIRequest $request);
+
public function __construct() {}
+ public function getParamTypes() {
+ return $this->defineParamTypes();
+ }
+
+ public function getReturnType() {
+ return $this->defineReturnType();
+ }
+
+ public function getErrorTypes() {
+ return $this->defineErrorTypes();
+ }
+
/**
* This is mostly for compatibility with
* @{class:PhabricatorCursorPagedPolicyAwareQuery}.
*/
public function getID() {
return $this->getAPIMethodName();
}
/**
* Get the status for this method (e.g., stable, unstable or deprecated).
* Should return a METHOD_STATUS_* constant. By default, methods are
* "stable".
*
* @return const METHOD_STATUS_* constant.
* @task status
*/
public function getMethodStatus() {
return self::METHOD_STATUS_STABLE;
}
/**
* Optional description to supplement the method status. In particular, if
* a method is deprecated, you can return a string here describing the reason
* for deprecation and stable alternatives.
*
* @return string|null Description of the method status, if available.
* @task status
*/
public function getMethodStatusDescription() {
return null;
}
public function getErrorDescription($error_code) {
- return idx($this->defineErrorTypes(), $error_code, 'Unknown Error');
+ return idx($this->getErrorTypes(), $error_code, 'Unknown Error');
}
public function getRequiredScope() {
// by default, conduit methods are not accessible via OAuth
return PhabricatorOAuthServerScope::SCOPE_NOT_ACCESSIBLE;
}
public function executeMethod(ConduitAPIRequest $request) {
return $this->execute($request);
}
public abstract function getAPIMethodName();
/**
* Return a key which sorts methods by application name, then method status,
* then method name.
*/
public function getSortOrder() {
$name = $this->getAPIMethodName();
$map = array(
ConduitAPIMethod::METHOD_STATUS_STABLE => 0,
ConduitAPIMethod::METHOD_STATUS_UNSTABLE => 1,
ConduitAPIMethod::METHOD_STATUS_DEPRECATED => 2,
);
$ord = idx($map, $this->getMethodStatus(), 0);
list($head, $tail) = explode('.', $name, 2);
return "{$head}.{$ord}.{$tail}";
}
public function getApplicationName() {
return head(explode('.', $this->getAPIMethodName(), 2));
}
public static function getConduitMethod($method_name) {
static $method_map = null;
if ($method_map === null) {
$methods = id(new PhutilSymbolLoader())
->setAncestorClass(__CLASS__)
->loadObjects();
foreach ($methods as $method) {
$name = $method->getAPIMethodName();
if (empty($method_map[$name])) {
$method_map[$name] = $method;
continue;
}
$orig_class = get_class($method_map[$name]);
$this_class = get_class($method);
throw new Exception(
"Two Conduit API method classes ({$orig_class}, {$this_class}) ".
"both have the same method name ({$name}). API methods ".
"must have unique method names.");
}
}
return idx($method_map, $method_name);
}
public function shouldRequireAuthentication() {
return true;
}
public function shouldAllowPublic() {
return false;
}
public function shouldAllowUnguardedWrites() {
return false;
}
/**
* Optionally, return a @{class:PhabricatorApplication} which this call is
* part of. The call will be disabled when the application is uninstalled.
*
* @return PhabricatorApplication|null Related application.
*/
public function getApplication() {
return null;
}
protected function formatStringConstants($constants) {
foreach ($constants as $key => $value) {
$constants[$key] = '"'.$value.'"';
}
$constants = implode(', ', $constants);
return 'string-constant<'.$constants.'>';
}
public static function getParameterMetadataKey($key) {
if (strncmp($key, 'api.', 4) === 0) {
// All keys passed beginning with "api." are always metadata keys.
return substr($key, 4);
} else {
switch ($key) {
// These are real keys which always belong to request metadata.
case 'access_token':
case 'scope':
case 'output':
// This is not a real metadata key; it is included here only to
// prevent Conduit methods from defining it.
case '__conduit__':
// This is prevented globally as a blanket defense against OAuth
// redirection attacks. It is included here to stop Conduit methods
// from defining it.
case 'code':
// This is not a real metadata key, but the presence of this
// parameter triggers an alternate request decoding pathway.
case 'params':
return $key;
}
}
return null;
}
/* -( Paging Results )----------------------------------------------------- */
/**
* @task pager
*/
protected function getPagerParamTypes() {
return array(
'before' => 'optional string',
'after' => 'optional string',
'limit' => 'optional int (default = 100)',
);
}
/**
* @task pager
*/
protected function newPager(ConduitAPIRequest $request) {
$limit = $request->getValue('limit', 100);
$limit = min(1000, $limit);
$limit = max(1, $limit);
$pager = id(new AphrontCursorPagerView())
->setPageSize($limit);
$before_id = $request->getValue('before');
if ($before_id !== null) {
$pager->setBeforeID($before_id);
}
$after_id = $request->getValue('after');
if ($after_id !== null) {
$pager->setAfterID($after_id);
}
return $pager;
}
/**
* @task pager
*/
protected function addPagerResults(
array $results,
AphrontCursorPagerView $pager) {
$results['cursor'] = array(
'limit' => $pager->getPageSize(),
'after' => $pager->getNextPageID(),
'before' => $pager->getPrevPageID(),
);
return $results;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getPHID() {
return null;
}
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
);
}
public function getPolicy($capability) {
// Application methods get application visibility; other methods get open
// visibility.
$application = $this->getApplication();
if ($application) {
return $application->getPolicy($capability);
}
return PhabricatorPolicies::getMostOpenPolicy();
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
if (!$this->shouldRequireAuthentication()) {
// Make unauthenticated methods universally visible.
return true;
}
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
protected function hasApplicationCapability(
$capability,
PhabricatorUser $viewer) {
$application = $this->getApplication();
if (!$application) {
return false;
}
return PhabricatorPolicyFilter::hasCapability(
$viewer,
$application,
$capability);
}
protected function requireApplicationCapability(
$capability,
PhabricatorUser $viewer) {
$application = $this->getApplication();
if (!$application) {
return;
}
PhabricatorPolicyFilter::requireCapability(
$viewer,
$this->getApplication(),
$capability);
}
}
diff --git a/src/applications/conduit/method/ConduitConnectConduitAPIMethod.php b/src/applications/conduit/method/ConduitConnectConduitAPIMethod.php
index 1654214cb7..12f08f8636 100644
--- a/src/applications/conduit/method/ConduitConnectConduitAPIMethod.php
+++ b/src/applications/conduit/method/ConduitConnectConduitAPIMethod.php
@@ -1,159 +1,159 @@
<?php
final class ConduitConnectConduitAPIMethod extends ConduitAPIMethod {
public function getAPIMethodName() {
return 'conduit.connect';
}
public function shouldRequireAuthentication() {
return false;
}
public function shouldAllowUnguardedWrites() {
return true;
}
public function getMethodDescription() {
return 'Connect a session-based client.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'client' => 'required string',
'clientVersion' => 'required int',
'clientDescription' => 'optional string',
'user' => 'optional string',
'authToken' => 'optional int',
'authSignature' => 'optional string',
'host' => 'deprecated',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict<string, any>';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-BAD-VERSION' =>
'Client/server version mismatch. Upgrade your server or downgrade '.
'your client.',
'NEW-ARC-VERSION' =>
'Client/server version mismatch. Upgrade your client.',
'ERR-UNKNOWN-CLIENT' =>
'Client is unknown.',
'ERR-INVALID-USER' =>
'The username you are attempting to authenticate with is not valid.',
'ERR-INVALID-CERTIFICATE' =>
'Your authentication certificate for this server is invalid.',
'ERR-INVALID-TOKEN' =>
"The challenge token you are authenticating with is outside of the ".
"allowed time range. Either your system clock is out of whack or ".
"you're executing a replay attack.",
'ERR-NO-CERTIFICATE' => 'This server requires authentication.',
);
}
protected function execute(ConduitAPIRequest $request) {
$client = $request->getValue('client');
$client_version = (int)$request->getValue('clientVersion');
$client_description = (string)$request->getValue('clientDescription');
$client_description = id(new PhutilUTF8StringTruncator())
->setMaximumBytes(255)
->truncateString($client_description);
$username = (string)$request->getValue('user');
// Log the connection, regardless of the outcome of checks below.
$connection = new PhabricatorConduitConnectionLog();
$connection->setClient($client);
$connection->setClientVersion($client_version);
$connection->setClientDescription($client_description);
$connection->setUsername($username);
$connection->save();
switch ($client) {
case 'arc':
$server_version = 6;
$supported_versions = array(
$server_version => true,
// Client version 5 introduced "user.query" call
4 => true,
// Client version 6 introduced "diffusion.getlintmessages" call
5 => true,
);
if (empty($supported_versions[$client_version])) {
if ($server_version < $client_version) {
$ex = new ConduitException('ERR-BAD-VERSION');
$ex->setErrorDescription(
"Your 'arc' client version is '{$client_version}', which ".
"is newer than the server version, '{$server_version}'. ".
"Upgrade your Phabricator install.");
} else {
$ex = new ConduitException('NEW-ARC-VERSION');
$ex->setErrorDescription(
"A new version of arc is available! You need to upgrade ".
"to connect to this server (you are running version ".
"{$client_version}, the server is running version ".
"{$server_version}).");
}
throw $ex;
}
break;
default:
// Allow new clients by default.
break;
}
$token = $request->getValue('authToken');
$signature = $request->getValue('authSignature');
$user = id(new PhabricatorUser())->loadOneWhere('username = %s', $username);
if (!$user) {
throw new ConduitException('ERR-INVALID-USER');
}
$session_key = null;
if ($token && $signature) {
$threshold = 60 * 15;
$now = time();
if (abs($token - $now) > $threshold) {
throw id(new ConduitException('ERR-INVALID-TOKEN'))
->setErrorDescription(
pht(
'The request you submitted is signed with a timestamp, but that '.
'timestamp is not within %s of the current time. The '.
'signed timestamp is %s (%s), and the current server time is '.
'%s (%s). This is a difference of %s seconds, but the '.
'timestamp must differ from the server time by no more than '.
'%s seconds. Your client or server clock may not be set '.
'correctly.',
phutil_format_relative_time($threshold),
$token,
date('r', $token),
$now,
date('r', $now),
($token - $now),
$threshold));
}
$valid = sha1($token.$user->getConduitCertificate());
if ($valid != $signature) {
throw new ConduitException('ERR-INVALID-CERTIFICATE');
}
$session_key = id(new PhabricatorAuthSessionEngine())->establishSession(
PhabricatorAuthSession::TYPE_CONDUIT,
$user->getPHID(),
$partial = false);
} else {
throw new ConduitException('ERR-NO-CERTIFICATE');
}
return array(
'connectionID' => $connection->getID(),
'sessionKey' => $session_key,
'userPHID' => $user->getPHID(),
);
}
}
diff --git a/src/applications/conduit/method/ConduitGetCapabilitiesConduitAPIMethod.php b/src/applications/conduit/method/ConduitGetCapabilitiesConduitAPIMethod.php
index ddbca233df..44acf3e0d3 100644
--- a/src/applications/conduit/method/ConduitGetCapabilitiesConduitAPIMethod.php
+++ b/src/applications/conduit/method/ConduitGetCapabilitiesConduitAPIMethod.php
@@ -1,60 +1,56 @@
<?php
final class ConduitGetCapabilitiesConduitAPIMethod extends ConduitAPIMethod {
public function getAPIMethodName() {
return 'conduit.getcapabilities';
}
public function shouldRequireAuthentication() {
return false;
}
public function getMethodDescription() {
return pht(
'List capabilities, wire formats, and authentication protocols '.
'available on this server.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict<string, any>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$authentication = array(
'token',
'asymmetric',
'session',
'sessionless',
);
$oauth_app = 'PhabricatorOAuthServerApplication';
if (PhabricatorApplication::isClassInstalled($oauth_app)) {
$authentication[] = 'oauth';
}
return array(
'authentication' => $authentication,
'signatures' => array(
'consign',
),
'input' => array(
'json',
'urlencoded',
),
'output' => array(
'json',
'human',
),
);
}
}
diff --git a/src/applications/conduit/method/ConduitGetCertificateConduitAPIMethod.php b/src/applications/conduit/method/ConduitGetCertificateConduitAPIMethod.php
index d57c1030cc..be14610796 100644
--- a/src/applications/conduit/method/ConduitGetCertificateConduitAPIMethod.php
+++ b/src/applications/conduit/method/ConduitGetCertificateConduitAPIMethod.php
@@ -1,92 +1,92 @@
<?php
final class ConduitGetCertificateConduitAPIMethod extends ConduitAPIMethod {
public function getAPIMethodName() {
return 'conduit.getcertificate';
}
public function shouldRequireAuthentication() {
return false;
}
public function shouldAllowUnguardedWrites() {
// This method performs logging and is on the authentication pathway.
return true;
}
public function getMethodDescription() {
return 'Retrieve certificate information for a user.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'token' => 'required string',
'host' => 'required string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict<string, any>';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-BAD-TOKEN' => 'Token does not exist or has expired.',
'ERR-RATE-LIMIT' =>
'You have made too many invalid token requests recently. Wait before '.
'making more.',
);
}
protected function execute(ConduitAPIRequest $request) {
$failed_attempts = PhabricatorUserLog::loadRecentEventsFromThisIP(
PhabricatorUserLog::ACTION_CONDUIT_CERTIFICATE_FAILURE,
60 * 5);
if (count($failed_attempts) > 5) {
$this->logFailure($request);
throw new ConduitException('ERR-RATE-LIMIT');
}
$token = $request->getValue('token');
$info = id(new PhabricatorConduitCertificateToken())->loadOneWhere(
'token = %s',
trim($token));
if (!$info || $info->getDateCreated() < time() - (60 * 15)) {
$this->logFailure($request, $info);
throw new ConduitException('ERR-BAD-TOKEN');
} else {
$log = PhabricatorUserLog::initializeNewLog(
$request->getUser(),
$info->getUserPHID(),
PhabricatorUserLog::ACTION_CONDUIT_CERTIFICATE)
->save();
}
$user = id(new PhabricatorUser())->loadOneWhere(
'phid = %s',
$info->getUserPHID());
if (!$user) {
throw new Exception('Certificate token points to an invalid user!');
}
return array(
'username' => $user->getUserName(),
'certificate' => $user->getConduitCertificate(),
);
}
private function logFailure(
ConduitAPIRequest $request,
PhabricatorConduitCertificateToken $info = null) {
$log = PhabricatorUserLog::initializeNewLog(
$request->getUser(),
$info ? $info->getUserPHID() : '-',
PhabricatorUserLog::ACTION_CONDUIT_CERTIFICATE_FAILURE)
->save();
}
}
diff --git a/src/applications/conduit/method/ConduitPingConduitAPIMethod.php b/src/applications/conduit/method/ConduitPingConduitAPIMethod.php
index 7e1ece57eb..f3c502defa 100644
--- a/src/applications/conduit/method/ConduitPingConduitAPIMethod.php
+++ b/src/applications/conduit/method/ConduitPingConduitAPIMethod.php
@@ -1,33 +1,29 @@
<?php
final class ConduitPingConduitAPIMethod extends ConduitAPIMethod {
public function getAPIMethodName() {
return 'conduit.ping';
}
public function shouldRequireAuthentication() {
return false;
}
public function getMethodDescription() {
return 'Basic ping for monitoring or a health-check.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'string';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
return php_uname('n');
}
}
diff --git a/src/applications/conduit/method/ConduitQueryConduitAPIMethod.php b/src/applications/conduit/method/ConduitQueryConduitAPIMethod.php
index 6973bad9fa..f5162a04fc 100644
--- a/src/applications/conduit/method/ConduitQueryConduitAPIMethod.php
+++ b/src/applications/conduit/method/ConduitQueryConduitAPIMethod.php
@@ -1,43 +1,39 @@
<?php
final class ConduitQueryConduitAPIMethod extends ConduitAPIMethod {
public function getAPIMethodName() {
return 'conduit.query';
}
public function getMethodDescription() {
return 'Returns the parameters of the Conduit methods.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict<dict>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$classes = id(new PhutilSymbolLoader())
->setAncestorClass('ConduitAPIMethod')
->setType('class')
->loadObjects();
$names_to_params = array();
foreach ($classes as $class) {
$names_to_params[$class->getAPIMethodName()] = array(
'description' => $class->getMethodDescription(),
- 'params' => $class->defineParamTypes(),
- 'return' => $class->defineReturnType(),
+ 'params' => $class->getParamTypes(),
+ 'return' => $class->getReturnType(),
);
}
return $names_to_params;
}
}
diff --git a/src/applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php b/src/applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php
index 81138831d0..d58b11ffa5 100644
--- a/src/applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php
+++ b/src/applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php
@@ -1,67 +1,67 @@
<?php
final class ConpherenceCreateThreadConduitAPIMethod
extends ConpherenceConduitAPIMethod {
public function getAPIMethodName() {
return 'conpherence.createthread';
}
public function getMethodDescription() {
return pht('Create a new conpherence thread.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'title' => 'optional string',
'message' => 'required string',
'participantPHIDs' => 'required list<phids>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_EMPTY_PARTICIPANT_PHIDS' => pht(
'You must specify participant phids.'),
'ERR_EMPTY_MESSAGE' => pht(
'You must specify a message.'),
);
}
protected function execute(ConduitAPIRequest $request) {
$participant_phids = $request->getValue('participantPHIDs', array());
$message = $request->getValue('message');
$title = $request->getValue('title');
list($errors, $conpherence) = ConpherenceEditor::createThread(
$request->getUser(),
$participant_phids,
$title,
$message,
PhabricatorContentSource::newFromConduitRequest($request));
if ($errors) {
foreach ($errors as $error_code) {
switch ($error_code) {
case ConpherenceEditor::ERROR_EMPTY_MESSAGE:
throw new ConduitException('ERR_EMPTY_MESSAGE');
break;
case ConpherenceEditor::ERROR_EMPTY_PARTICIPANTS:
throw new ConduitException('ERR_EMPTY_PARTICIPANT_PHIDS');
break;
}
}
}
return array(
'conpherenceID' => $conpherence->getID(),
'conpherencePHID' => $conpherence->getPHID(),
'conpherenceURI' => $this->getConpherenceURI($conpherence),
);
}
}
diff --git a/src/applications/conpherence/conduit/ConpherenceQueryThreadConduitAPIMethod.php b/src/applications/conpherence/conduit/ConpherenceQueryThreadConduitAPIMethod.php
index 2fa3dc6f27..986e8e520c 100644
--- a/src/applications/conpherence/conduit/ConpherenceQueryThreadConduitAPIMethod.php
+++ b/src/applications/conpherence/conduit/ConpherenceQueryThreadConduitAPIMethod.php
@@ -1,87 +1,83 @@
<?php
final class ConpherenceQueryThreadConduitAPIMethod
extends ConpherenceConduitAPIMethod {
public function getAPIMethodName() {
return 'conpherence.querythread';
}
public function getMethodDescription() {
return pht(
'Query for conpherence threads for the logged in user. '.
'You can query by ids or phids for specific conpherence threads. '.
'Otherwise, specify limit and offset to query the most recently '.
'updated conpherences for the logged in user.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional array<int>',
'phids' => 'optional array<phids>',
'limit' => 'optional int',
'offset' => 'optional int',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser();
$ids = $request->getValue('ids', array());
$phids = $request->getValue('phids', array());
$limit = $request->getValue('limit');
$offset = $request->getValue('offset');
$query = id(new ConpherenceThreadQuery())
->setViewer($user)
->needParticipantCache(true)
->needFilePHIDs(true);
if ($ids) {
$conpherences = $query
->withIDs($ids)
->setLimit($limit)
->setOffset($offset)
->execute();
} else if ($phids) {
$conpherences = $query
->withPHIDs($phids)
->setLimit($limit)
->setOffset($offset)
->execute();
} else {
$participation = id(new ConpherenceParticipantQuery())
->withParticipantPHIDs(array($user->getPHID()))
->setLimit($limit)
->setOffset($offset)
->execute();
$conpherence_phids = array_keys($participation);
$query->withPHIDs($conpherence_phids);
$conpherences = $query->execute();
$conpherences = array_select_keys($conpherences, $conpherence_phids);
}
$data = array();
foreach ($conpherences as $conpherence) {
$id = $conpherence->getID();
$data[$id] = array(
'conpherenceID' => $id,
'conpherencePHID' => $conpherence->getPHID(),
'conpherenceTitle' => $conpherence->getTitle(),
'messageCount' => $conpherence->getMessageCount(),
'recentParticipantPHIDs' => $conpherence->getRecentParticipantPHIDs(),
'filePHIDs' => $conpherence->getFilePHIDs(),
'conpherenceURI' => $this->getConpherenceURI($conpherence),
);
}
return $data;
}
}
diff --git a/src/applications/conpherence/conduit/ConpherenceQueryTransactionConduitAPIMethod.php b/src/applications/conpherence/conduit/ConpherenceQueryTransactionConduitAPIMethod.php
index a7d30c5a45..958748a68e 100644
--- a/src/applications/conpherence/conduit/ConpherenceQueryTransactionConduitAPIMethod.php
+++ b/src/applications/conpherence/conduit/ConpherenceQueryTransactionConduitAPIMethod.php
@@ -1,97 +1,97 @@
<?php
final class ConpherenceQueryTransactionConduitAPIMethod
extends ConpherenceConduitAPIMethod {
public function getAPIMethodName() {
return 'conpherence.querytransaction';
}
public function getMethodDescription() {
return pht(
'Query for transactions for the logged in user within a specific '.
'conpherence thread. You can specify the thread by id or phid. '.
'Otherwise, specify limit and offset to query the most recent '.
'transactions within the conpherence for the logged in user.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'threadID' => 'optional int',
'threadPHID' => 'optional phid',
'limit' => 'optional int',
'offset' => 'optional int',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_USAGE_NO_THREAD_ID' => pht(
'You must specify a thread id or thread phid to query transactions '.
'from.'),
);
}
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser();
$thread_id = $request->getValue('threadID');
$thread_phid = $request->getValue('threadPHID');
$limit = $request->getValue('limit');
$offset = $request->getValue('offset');
$query = id(new ConpherenceThreadQuery())
->setViewer($user);
if ($thread_id) {
$query->withIDs(array($thread_id));
} else if ($thread_phid) {
$query->withPHIDs(array($thread_phid));
} else {
throw new ConduitException('ERR_USAGE_NO_THREAD_ID');
}
$conpherence = $query->executeOne();
$query = id(new ConpherenceTransactionQuery())
->setViewer($user)
->withObjectPHIDs(array($conpherence->getPHID()))
->setLimit($limit)
->setOffset($offset);
$transactions = $query->execute();
$data = array();
foreach ($transactions as $transaction) {
$comment = null;
$comment_obj = $transaction->getComment();
if ($comment_obj) {
$comment = $comment_obj->getContent();
}
$title = null;
$title_obj = $transaction->getTitle();
if ($title_obj) {
$title = $title_obj->getHTMLContent();
}
$id = $transaction->getID();
$data[$id] = array(
'transactionID' => $id,
'transactionType' => $transaction->getTransactionType(),
'transactionTitle' => $title,
'transactionComment' => $comment,
'transactionOldValue' => $transaction->getOldValue(),
'transactionNewValue' => $transaction->getNewValue(),
'transactionMetadata' => $transaction->getMetadata(),
'authorPHID' => $transaction->getAuthorPHID(),
'dateCreated' => $transaction->getDateCreated(),
'conpherenceID' => $conpherence->getID(),
'conpherencePHID' => $conpherence->getPHID(),
);
}
return $data;
}
}
diff --git a/src/applications/conpherence/conduit/ConpherenceUpdateThreadConduitAPIMethod.php b/src/applications/conpherence/conduit/ConpherenceUpdateThreadConduitAPIMethod.php
index 1e98011b83..e183d44699 100644
--- a/src/applications/conpherence/conduit/ConpherenceUpdateThreadConduitAPIMethod.php
+++ b/src/applications/conpherence/conduit/ConpherenceUpdateThreadConduitAPIMethod.php
@@ -1,109 +1,109 @@
<?php
final class ConpherenceUpdateThreadConduitAPIMethod
extends ConpherenceConduitAPIMethod {
public function getAPIMethodName() {
return 'conpherence.updatethread';
}
public function getMethodDescription() {
return pht('Update an existing conpherence thread.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'id' => 'optional int',
'phid' => 'optional phid',
'title' => 'optional string',
'message' => 'optional string',
'addParticipantPHIDs' => 'optional list<phids>',
'removeParticipantPHID' => 'optional phid',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'bool';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_USAGE_NO_THREAD_ID' => pht(
'You must specify a thread id or thread phid to query transactions '.
'from.'),
'ERR_USAGE_THREAD_NOT_FOUND' => pht(
'Thread does not exist or logged in user can not see it.'),
'ERR_USAGE_ONLY_SELF_REMOVE' => pht(
'Only a user can remove themselves from a thread.'),
'ERR_USAGE_NO_UPDATES' => pht(
'You must specify data that actually updates the conpherence.'),
);
}
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser();
$id = $request->getValue('id');
$phid = $request->getValue('phid');
$query = id(new ConpherenceThreadQuery())
->setViewer($user)
->needFilePHIDs(true);
if ($id) {
$query->withIDs(array($id));
} else if ($phid) {
$query->withPHIDs(array($phid));
} else {
throw new ConduitException('ERR_USAGE_NO_THREAD_ID');
}
$conpherence = $query->executeOne();
if (!$conpherence) {
throw new ConduitException('ERR_USAGE_THREAD_NOT_FOUND');
}
$source = PhabricatorContentSource::newFromConduitRequest($request);
$editor = id(new ConpherenceEditor())
->setContentSource($source)
->setActor($user);
$xactions = array();
$add_participant_phids = $request->getValue('addParticipantPHIDs', array());
$remove_participant_phid = $request->getValue('removeParticipantPHID');
$message = $request->getValue('message');
$title = $request->getValue('title');
if ($add_participant_phids) {
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(
ConpherenceTransactionType::TYPE_PARTICIPANTS)
->setNewValue(array('+' => $add_participant_phids));
}
if ($remove_participant_phid) {
if ($remove_participant_phid != $user->getPHID()) {
throw new ConduitException('ERR_USAGE_ONLY_SELF_REMOVE');
}
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(
ConpherenceTransactionType::TYPE_PARTICIPANTS)
->setNewValue(array('-' => array($remove_participant_phid)));
}
if ($title) {
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransactionType::TYPE_TITLE)
->setNewValue($title);
}
if ($message) {
$xactions = array_merge(
$xactions,
$editor->generateTransactionsFromText(
$user,
$conpherence,
$message));
}
try {
$xactions = $editor->applyTransactions($conpherence, $xactions);
} catch (PhabricatorApplicationTransactionNoEffectException $ex) {
throw new ConduitException('ERR_USAGE_NO_UPDATES');
}
return true;
}
}
diff --git a/src/applications/differential/conduit/DifferentialCloseConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialCloseConduitAPIMethod.php
index 8d1ffd90a3..58fed6cf6e 100644
--- a/src/applications/differential/conduit/DifferentialCloseConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialCloseConduitAPIMethod.php
@@ -1,63 +1,63 @@
<?php
final class DifferentialCloseConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.close';
}
public function getMethodDescription() {
return pht('Close a Differential revision.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'revisionID' => 'required int',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_NOT_FOUND' => 'Revision was not found.',
);
}
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$id = $request->getValue('revisionID');
$revision = id(new DifferentialRevisionQuery())
->withIDs(array($id))
->setViewer($viewer)
->needReviewerStatus(true)
->executeOne();
if (!$revision) {
throw new ConduitException('ERR_NOT_FOUND');
}
$xactions = array();
$xactions[] = id(new DifferentialTransaction())
->setTransactionType(DifferentialTransaction::TYPE_ACTION)
->setNewValue(DifferentialAction::ACTION_CLOSE);
$content_source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_CONDUIT,
array());
$editor = id(new DifferentialTransactionEditor())
->setActor($viewer)
->setContentSourceFromConduitRequest($request)
->setContinueOnMissingFields(true)
->setContinueOnNoEffect(true);
$editor->applyTransactions($revision, $xactions);
return;
}
}
diff --git a/src/applications/differential/conduit/DifferentialCreateCommentConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialCreateCommentConduitAPIMethod.php
index b1c145b809..fe1d57857d 100644
--- a/src/applications/differential/conduit/DifferentialCreateCommentConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialCreateCommentConduitAPIMethod.php
@@ -1,92 +1,92 @@
<?php
final class DifferentialCreateCommentConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.createcomment';
}
public function getMethodDescription() {
return pht('Add a comment to a Differential revision.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'revision_id' => 'required revisionid',
'message' => 'optional string',
'action' => 'optional string',
'silent' => 'optional bool',
'attach_inlines' => 'optional bool',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BAD_REVISION' => 'Bad revision ID.',
);
}
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$revision = id(new DifferentialRevisionQuery())
->setViewer($viewer)
->withIDs(array($request->getValue('revision_id')))
->needReviewerStatus(true)
->needReviewerAuthority(true)
->executeOne();
if (!$revision) {
throw new ConduitException('ERR_BAD_REVISION');
}
$xactions = array();
$action = $request->getValue('action');
if ($action && ($action != 'comment') && ($action != 'none')) {
$xactions[] = id(new DifferentialTransaction())
->setTransactionType(DifferentialTransaction::TYPE_ACTION)
->setNewValue($action);
}
$content = $request->getValue('message');
if (strlen($content)) {
$xactions[] = id(new DifferentialTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(new DifferentialTransactionComment())
->setContent($content));
}
if ($request->getValue('attach_inlines')) {
$type_inline = DifferentialTransaction::TYPE_INLINE;
$inlines = DifferentialTransactionQuery::loadUnsubmittedInlineComments(
$viewer,
$revision);
foreach ($inlines as $inline) {
$xactions[] = id(new DifferentialTransaction())
->setTransactionType($type_inline)
->attachComment($inline);
}
}
$editor = id(new DifferentialTransactionEditor())
->setActor($viewer)
->setDisableEmail($request->getValue('silent'))
->setContentSourceFromConduitRequest($request)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true);
$editor->applyTransactions($revision, $xactions);
return array(
'revisionid' => $revision->getID(),
'uri' => PhabricatorEnv::getURI('/D'.$revision->getID()),
);
}
}
diff --git a/src/applications/differential/conduit/DifferentialCreateDiffConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialCreateDiffConduitAPIMethod.php
index 232fd71d59..6db5bc6cb4 100644
--- a/src/applications/differential/conduit/DifferentialCreateDiffConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialCreateDiffConduitAPIMethod.php
@@ -1,189 +1,184 @@
<?php
final class DifferentialCreateDiffConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.creatediff';
}
public function getMethodDescription() {
return 'Create a new Differential diff.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$vcs_const = $this->formatStringConstants(
array(
'svn',
'git',
'hg',
));
$status_const = $this->formatStringConstants(
array(
'none',
'skip',
'okay',
'warn',
'fail',
'postponed',
));
return array(
'changes' => 'required list<dict>',
'sourceMachine' => 'required string',
'sourcePath' => 'required string',
'branch' => 'required string',
'bookmark' => 'optional string',
'sourceControlSystem' => 'required '.$vcs_const,
'sourceControlPath' => 'required string',
'sourceControlBaseRevision' => 'required string',
'creationMethod' => 'optional string',
'arcanistProject' => 'optional string',
'lintStatus' => 'required '.$status_const,
'unitStatus' => 'required '.$status_const,
'repositoryPHID' => 'optional phid',
'parentRevisionID' => 'deprecated',
'authorPHID' => 'deprecated',
'repositoryUUID' => 'deprecated',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$change_data = $request->getValue('changes');
$changes = array();
foreach ($change_data as $dict) {
$changes[] = ArcanistDiffChange::newFromDictionary($dict);
}
$diff = DifferentialDiff::newFromRawChanges($viewer, $changes);
// TODO: Remove repository UUID eventually; for now continue writing
// the UUID. Note that we'll overwrite it below if we identify a
// repository, and `arc` no longer sends it. This stuff is retained for
// backward compatibility.
$repository_uuid = $request->getValue('repositoryUUID');
$repository_phid = $request->getValue('repositoryPHID');
if ($repository_phid) {
$repository = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->withPHIDs(array($repository_phid))
->executeOne();
if ($repository) {
$repository_phid = $repository->getPHID();
$repository_uuid = $repository->getUUID();
}
}
$project_name = $request->getValue('arcanistProject');
$project_phid = null;
if ($project_name) {
$arcanist_project = id(new PhabricatorRepositoryArcanistProject())
->loadOneWhere(
'name = %s',
$project_name);
if (!$arcanist_project) {
$arcanist_project = new PhabricatorRepositoryArcanistProject();
$arcanist_project->setName($project_name);
$arcanist_project->save();
}
$project_phid = $arcanist_project->getPHID();
}
switch ($request->getValue('lintStatus')) {
case 'skip':
$lint_status = DifferentialLintStatus::LINT_SKIP;
break;
case 'okay':
$lint_status = DifferentialLintStatus::LINT_OKAY;
break;
case 'warn':
$lint_status = DifferentialLintStatus::LINT_WARN;
break;
case 'fail':
$lint_status = DifferentialLintStatus::LINT_FAIL;
break;
case 'postponed':
$lint_status = DifferentialLintStatus::LINT_POSTPONED;
break;
case 'none':
default:
$lint_status = DifferentialLintStatus::LINT_NONE;
break;
}
switch ($request->getValue('unitStatus')) {
case 'skip':
$unit_status = DifferentialUnitStatus::UNIT_SKIP;
break;
case 'okay':
$unit_status = DifferentialUnitStatus::UNIT_OKAY;
break;
case 'warn':
$unit_status = DifferentialUnitStatus::UNIT_WARN;
break;
case 'fail':
$unit_status = DifferentialUnitStatus::UNIT_FAIL;
break;
case 'postponed':
$unit_status = DifferentialUnitStatus::UNIT_POSTPONED;
break;
case 'none':
default:
$unit_status = DifferentialUnitStatus::UNIT_NONE;
break;
}
$diff_data_dict = array(
'sourcePath' => $request->getValue('sourcePath'),
'sourceMachine' => $request->getValue('sourceMachine'),
'branch' => $request->getValue('branch'),
'creationMethod' => $request->getValue('creationMethod'),
'authorPHID' => $viewer->getPHID(),
'bookmark' => $request->getValue('bookmark'),
'repositoryUUID' => $repository_uuid,
'repositoryPHID' => $repository_phid,
'sourceControlSystem' => $request->getValue('sourceControlSystem'),
'sourceControlPath' => $request->getValue('sourceControlPath'),
'sourceControlBaseRevision' =>
$request->getValue('sourceControlBaseRevision'),
'arcanistProjectPHID' => $project_phid,
'lintStatus' => $lint_status,
'unitStatus' => $unit_status,
);
$xactions = array(id(new DifferentialTransaction())
->setTransactionType(DifferentialDiffTransaction::TYPE_DIFF_CREATE)
->setNewValue($diff_data_dict),
);
id(new DifferentialDiffEditor())
->setActor($viewer)
->setContentSourceFromConduitRequest($request)
->setContinueOnNoEffect(true)
->applyTransactions($diff, $xactions);
$path = '/differential/diff/'.$diff->getID().'/';
$uri = PhabricatorEnv::getURI($path);
return array(
'diffid' => $diff->getID(),
'uri' => $uri,
);
}
}
diff --git a/src/applications/differential/conduit/DifferentialCreateInlineConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialCreateInlineConduitAPIMethod.php
index 67e4c68a60..98a567b0b8 100644
--- a/src/applications/differential/conduit/DifferentialCreateInlineConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialCreateInlineConduitAPIMethod.php
@@ -1,109 +1,109 @@
<?php
final class DifferentialCreateInlineConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.createinline';
}
public function getMethodDescription() {
return 'Add an inline comment to a Differential revision.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'revisionID' => 'optional revisionid',
'diffID' => 'optional diffid',
'filePath' => 'required string',
'isNewFile' => 'required bool',
'lineNumber' => 'required int',
'lineLength' => 'optional int',
'content' => 'required string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-BAD-REVISION' => 'Bad revision ID.',
'ERR-BAD-DIFF' => 'Bad diff ID, or diff does not belong to revision.',
'ERR-NEED-DIFF' => 'Neither revision ID nor diff ID was provided.',
'ERR-NEED-FILE' => 'A file path was not provided.',
'ERR-BAD-FILE' => "Requested file doesn't exist in this revision.",
);
}
protected function execute(ConduitAPIRequest $request) {
$rid = $request->getValue('revisionID');
$did = $request->getValue('diffID');
if ($rid) {
// Given both a revision and a diff, check that they match.
// Given only a revision, find the active diff.
$revision = id(new DifferentialRevisionQuery())
->setViewer($request->getUser())
->withIDs(array($rid))
->executeOne();
if (!$revision) {
throw new ConduitException('ERR-BAD-REVISION');
}
if (!$did) { // did not!
$diff = $revision->loadActiveDiff();
$did = $diff->getID();
} else { // did too!
$diff = id(new DifferentialDiff())->load($did);
if (!$diff || $diff->getRevisionID() != $rid) {
throw new ConduitException('ERR-BAD-DIFF');
}
}
} else if ($did) {
// Given only a diff, find the parent revision.
$diff = id(new DifferentialDiff())->load($did);
if (!$diff) {
throw new ConduitException('ERR-BAD-DIFF');
}
$rid = $diff->getRevisionID();
} else {
// Given neither, bail.
throw new ConduitException('ERR-NEED-DIFF');
}
$file = $request->getValue('filePath');
if (!$file) {
throw new ConduitException('ERR-NEED-FILE');
}
$changes = id(new DifferentialChangeset())->loadAllWhere(
'diffID = %d',
$did);
$cid = null;
foreach ($changes as $id => $change) {
if ($file == $change->getFilename()) {
$cid = $id;
}
}
if ($cid == null) {
throw new ConduitException('ERR-BAD-FILE');
}
$inline = id(new DifferentialInlineComment())
->setRevisionID($rid)
->setChangesetID($cid)
->setAuthorPHID($request->getUser()->getPHID())
->setContent($request->getValue('content'))
->setIsNewFile($request->getValue('isNewFile'))
->setLineNumber($request->getValue('lineNumber'))
->setLineLength($request->getValue('lineLength', 0))
->save();
// Load everything again, just to be safe.
$changeset = id(new DifferentialChangeset())
->load($inline->getChangesetID());
return $this->buildInlineInfoDictionary($inline, $changeset);
}
}
diff --git a/src/applications/differential/conduit/DifferentialCreateRawDiffConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialCreateRawDiffConduitAPIMethod.php
index c7596fa04b..e8dd29f86a 100644
--- a/src/applications/differential/conduit/DifferentialCreateRawDiffConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialCreateRawDiffConduitAPIMethod.php
@@ -1,80 +1,75 @@
<?php
final class DifferentialCreateRawDiffConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.createrawdiff';
}
public function getMethodDescription() {
return pht('Create a new Differential diff from a raw diff source.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'diff' => 'required string',
'repositoryPHID' => 'optional string',
'viewPolicy' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$raw_diff = $request->getValue('diff');
$repository_phid = $request->getValue('repositoryPHID');
if ($repository_phid) {
$repository = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->withPHIDs(array($repository_phid))
->executeOne();
if (!$repository) {
throw new Exception(
pht('No such repository "%s"!', $repository_phid));
}
}
$parser = new ArcanistDiffParser();
$changes = $parser->parseDiff($raw_diff);
$diff = DifferentialDiff::newFromRawChanges($viewer, $changes);
$diff_data_dict = array(
'creationMethod' => 'web',
'authorPHID' => $viewer->getPHID(),
'repositoryPHID' => $repository_phid,
'lintStatus' => DifferentialLintStatus::LINT_SKIP,
'unitStatus' => DifferentialUnitStatus::UNIT_SKIP,
);
$xactions = array(id(new DifferentialTransaction())
->setTransactionType(DifferentialDiffTransaction::TYPE_DIFF_CREATE)
->setNewValue($diff_data_dict),
);
if ($request->getValue('viewPolicy')) {
$xactions[] = id(new DifferentialTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
->setNewValue($request->getValue('viewPolicy'));
}
id(new DifferentialDiffEditor())
->setActor($viewer)
->setContentSourceFromConduitRequest($request)
->setContinueOnNoEffect(true)
->setLookupRepository(false) // respect user choice
->applyTransactions($diff, $xactions);
return $this->buildDiffInfoDictionary($diff);
}
}
diff --git a/src/applications/differential/conduit/DifferentialCreateRevisionConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialCreateRevisionConduitAPIMethod.php
index 786b0694d3..de0c3e02d5 100644
--- a/src/applications/differential/conduit/DifferentialCreateRevisionConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialCreateRevisionConduitAPIMethod.php
@@ -1,61 +1,61 @@
<?php
final class DifferentialCreateRevisionConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.createrevision';
}
public function getMethodDescription() {
return pht('Create a new Differential revision.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
// TODO: Arcanist passes this; prevent fatals after D4191 until Conduit
// version 7 or newer.
'user' => 'ignored',
'diffid' => 'required diffid',
'fields' => 'required dict',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BAD_DIFF' => 'Bad diff ID.',
);
}
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$diff = id(new DifferentialDiffQuery())
->setViewer($viewer)
->withIDs(array($request->getValue('diffid')))
->executeOne();
if (!$diff) {
throw new ConduitException('ERR_BAD_DIFF');
}
$revision = DifferentialRevision::initializeNewRevision($viewer);
$revision->attachReviewerStatus(array());
$this->applyFieldEdit(
$request,
$revision,
$diff,
$request->getValue('fields', array()),
$message = null);
return array(
'revisionid' => $revision->getID(),
'uri' => PhabricatorEnv::getURI('/D'.$revision->getID()),
);
}
}
diff --git a/src/applications/differential/conduit/DifferentialFindConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialFindConduitAPIMethod.php
index 585d60df37..56cb0f08da 100644
--- a/src/applications/differential/conduit/DifferentialFindConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialFindConduitAPIMethod.php
@@ -1,106 +1,101 @@
<?php
final class DifferentialFindConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.find';
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodStatusDescription() {
return "Replaced by 'differential.query'.";
}
public function getMethodDescription() {
return 'Query Differential revisions which match certain criteria.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$types = array(
'open',
'committable',
'revision-ids',
'phids',
);
return array(
'query' => 'required '.$this->formatStringConstants($types),
'guids' => 'required nonempty list<guids>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty list<dict>';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$type = $request->getValue('query');
$guids = $request->getValue('guids');
$results = array();
if (!$guids) {
return $results;
}
$query = id(new DifferentialRevisionQuery())
->setViewer($request->getUser());
switch ($type) {
case 'open':
$query
->withStatus(DifferentialRevisionQuery::STATUS_OPEN)
->withAuthors($guids);
break;
case 'committable':
$query
->withStatus(DifferentialRevisionQuery::STATUS_ACCEPTED)
->withAuthors($guids);
break;
case 'revision-ids':
$query
->withIDs($guids);
break;
case 'owned':
$query->withAuthors($guids);
break;
case 'phids':
$query
->withPHIDs($guids);
break;
}
$revisions = $query->execute();
foreach ($revisions as $revision) {
$diff = $revision->loadActiveDiff();
if (!$diff) {
continue;
}
$id = $revision->getID();
$results[] = array(
'id' => $id,
'phid' => $revision->getPHID(),
'name' => $revision->getTitle(),
'uri' => PhabricatorEnv::getProductionURI('/D'.$id),
'dateCreated' => $revision->getDateCreated(),
'authorPHID' => $revision->getAuthorPHID(),
'statusName' =>
ArcanistDifferentialRevisionStatus::getNameForRevisionStatus(
$revision->getStatus()),
'sourcePath' => $diff->getSourcePath(),
);
}
return $results;
}
}
diff --git a/src/applications/differential/conduit/DifferentialFinishPostponedLintersConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialFinishPostponedLintersConduitAPIMethod.php
index 8cd4f87ea3..093f06e117 100644
--- a/src/applications/differential/conduit/DifferentialFinishPostponedLintersConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialFinishPostponedLintersConduitAPIMethod.php
@@ -1,118 +1,118 @@
<?php
final class DifferentialFinishPostponedLintersConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.finishpostponedlinters';
}
public function getMethodDescription() {
return 'Update diff with new lint messages and mark postponed '.
'linters as finished.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'diffID' => 'required diffID',
'linters' => 'required dict',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-BAD-DIFF' => 'Bad diff ID.',
'ERR-BAD-LINTER' => 'No postponed linter by the given name',
'ERR-NO-LINT' => 'No postponed lint field available in diff',
);
}
protected function execute(ConduitAPIRequest $request) {
$diff_id = $request->getValue('diffID');
$linter_map = $request->getValue('linters');
$diff = id(new DifferentialDiffQuery())
->setViewer($request->getUser())
->withIDs(array($diff_id))
->executeOne();
if (!$diff) {
throw new ConduitException('ERR-BAD-DIFF');
}
// Extract the finished linters and messages from the linter map.
$finished_linters = array_keys($linter_map);
$new_messages = array();
foreach ($linter_map as $linter => $messages) {
$new_messages = array_merge($new_messages, $messages);
}
// Load the postponed linters attached to this diff.
$postponed_linters_property = id(
new DifferentialDiffProperty())->loadOneWhere(
'diffID = %d AND name = %s',
$diff_id,
'arc:lint-postponed');
if ($postponed_linters_property) {
$postponed_linters = $postponed_linters_property->getData();
} else {
$postponed_linters = array();
}
foreach ($finished_linters as $linter) {
if (!in_array($linter, $postponed_linters)) {
throw new ConduitException('ERR-BAD-LINTER');
}
}
foreach ($postponed_linters as $idx => $linter) {
if (in_array($linter, $finished_linters)) {
unset($postponed_linters[$idx]);
}
}
// Load the lint messages currenty attached to the diff. If this
// diff property doesn't exist, create it.
$messages_property = id(new DifferentialDiffProperty())->loadOneWhere(
'diffID = %d AND name = %s',
$diff_id,
'arc:lint');
if ($messages_property) {
$messages = $messages_property->getData();
} else {
$messages = array();
}
// Add new lint messages, removing duplicates.
foreach ($new_messages as $new_message) {
if (!in_array($new_message, $messages)) {
$messages[] = $new_message;
}
}
// Use setdiffproperty to update the postponed linters and messages,
// as these will also update the lint status correctly.
$call = new ConduitCall(
'differential.setdiffproperty',
array(
'diff_id' => $diff_id,
'name' => 'arc:lint',
'data' => json_encode($messages),
));
$call->setUser($request->getUser());
$call->execute();
$call = new ConduitCall(
'differential.setdiffproperty',
array(
'diff_id' => $diff_id,
'name' => 'arc:lint-postponed',
'data' => json_encode($postponed_linters),
));
$call->setUser($request->getUser());
$call->execute();
}
}
diff --git a/src/applications/differential/conduit/DifferentialGetAllDiffsConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialGetAllDiffsConduitAPIMethod.php
index 0f2e091d4c..c4e2d35215 100644
--- a/src/applications/differential/conduit/DifferentialGetAllDiffsConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialGetAllDiffsConduitAPIMethod.php
@@ -1,60 +1,56 @@
<?php
final class DifferentialGetAllDiffsConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.getalldiffs';
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodStatusDescription() {
return pht(
'This method has been deprecated in favor of differential.querydiffs.');
}
public function getMethodDescription() {
return 'Load all diffs for given revisions from Differential.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'revision_ids' => 'required list<int>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$results = array();
$revision_ids = $request->getValue('revision_ids');
if (!$revision_ids) {
return $results;
}
$diffs = id(new DifferentialDiffQuery())
->setViewer($request->getUser())
->withRevisionIDs($revision_ids)
->execute();
foreach ($diffs as $diff) {
$results[] = array(
'revision_id' => $diff->getRevisionID(),
'diff_id' => $diff->getID(),
);
}
return $results;
}
}
diff --git a/src/applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php
index afadce3397..8d7e71c030 100644
--- a/src/applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php
@@ -1,198 +1,198 @@
<?php
final class DifferentialGetCommitMessageConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.getcommitmessage';
}
public function getMethodDescription() {
return 'Retrieve Differential commit messages or message templates.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$edit_types = array('edit', 'create');
return array(
'revision_id' => 'optional revision_id',
'fields' => 'optional dict<string, wild>',
'edit' => 'optional '.$this->formatStringConstants($edit_types),
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty string';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_NOT_FOUND' => 'Revision was not found.',
);
}
protected function execute(ConduitAPIRequest $request) {
$id = $request->getValue('revision_id');
$viewer = $request->getUser();
if ($id) {
$revision = id(new DifferentialRevisionQuery())
->withIDs(array($id))
->setViewer($viewer)
->needReviewerStatus(true)
->needActiveDiffs(true)
->executeOne();
if (!$revision) {
throw new ConduitException('ERR_NOT_FOUND');
}
} else {
$revision = DifferentialRevision::initializeNewRevision($viewer);
$revision->attachReviewerStatus(array());
$revision->attachActiveDiff(null);
}
$is_edit = $request->getValue('edit');
$is_create = ($is_edit == 'create');
$field_list = PhabricatorCustomField::getObjectFields(
$revision,
($is_edit
? DifferentialCustomField::ROLE_COMMITMESSAGEEDIT
: DifferentialCustomField::ROLE_COMMITMESSAGE));
$field_list
->setViewer($viewer)
->readFieldsFromStorage($revision);
$field_map = mpull($field_list->getFields(), null, 'getFieldKeyForConduit');
if ($is_edit) {
$fields = $request->getValue('fields', array());
foreach ($fields as $field => $value) {
$custom_field = idx($field_map, $field);
if (!$custom_field) {
// Just ignore this, these workflows don't make strong distictions
// about field editability on the client side.
continue;
}
if ($is_create ||
$custom_field->shouldOverwriteWhenCommitMessageIsEdited()) {
$custom_field->readValueFromCommitMessage($value);
}
}
}
$phids = array();
foreach ($field_list->getFields() as $key => $field) {
$field_phids = $field->getRequiredHandlePHIDsForCommitMessage();
if (!is_array($field_phids)) {
throw new Exception(
pht(
'Custom field "%s" was expected to return an array of handle '.
'PHIDs required for commit message rendering, but returned "%s" '.
'instead.',
$field->getFieldKey(),
gettype($field_phids)));
}
$phids[$key] = $field_phids;
}
$all_phids = array_mergev($phids);
if ($all_phids) {
$all_handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs($all_phids)
->execute();
} else {
$all_handles = array();
}
$key_title = id(new DifferentialTitleField())->getFieldKey();
$default_title = DifferentialTitleField::getDefaultTitle();
$commit_message = array();
foreach ($field_list->getFields() as $key => $field) {
$handles = array_select_keys($all_handles, $phids[$key]);
$label = $field->renderCommitMessageLabel();
$value = $field->renderCommitMessageValue($handles);
if (!is_string($value) && !is_null($value)) {
throw new Exception(
pht(
'Custom field "%s" was expected to render a string or null value, '.
'but rendered a "%s" instead.',
$field->getFieldKey(),
gettype($value)));
}
$is_title = ($key == $key_title);
if (!strlen($value)) {
if ($is_title) {
$commit_message[] = $default_title;
} else {
if ($is_edit && $field->shouldAppearInCommitMessageTemplate()) {
$commit_message[] = $label.': ';
}
}
} else {
if ($is_title) {
$commit_message[] = $value;
} else {
$value = str_replace(
array("\r\n", "\r"),
array("\n", "\n"),
$value);
if (strpos($value, "\n") !== false || substr($value, 0, 2) === ' ') {
$commit_message[] = "{$label}:\n{$value}";
} else {
$commit_message[] = "{$label}: {$value}";
}
}
}
}
if ($is_edit) {
$tip = $this->getProTip($field_list);
if ($tip !== null) {
$commit_message[] = "\n".$tip;
}
}
$commit_message = implode("\n\n", $commit_message);
return $commit_message;
}
private function getProTip() {
// Any field can provide tips, whether it normally appears on commit
// messages or not.
$field_list = PhabricatorCustomField::getObjectFields(
new DifferentialRevision(),
PhabricatorCustomField::ROLE_DEFAULT);
$tips = array();
foreach ($field_list->getFields() as $key => $field) {
$tips[] = $field->getProTips();
}
$tips = array_mergev($tips);
if (!$tips) {
return null;
}
shuffle($tips);
$tip = pht('Tip: %s', head($tips));
$tip = wordwrap($tip, 78, "\n", true);
$lines = explode("\n", $tip);
foreach ($lines as $key => $line) {
$lines[$key] = '# '.$line;
}
return implode("\n", $lines);
}
}
diff --git a/src/applications/differential/conduit/DifferentialGetCommitPathsConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialGetCommitPathsConduitAPIMethod.php
index 0a1a644888..a025cd4983 100644
--- a/src/applications/differential/conduit/DifferentialGetCommitPathsConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialGetCommitPathsConduitAPIMethod.php
@@ -1,56 +1,56 @@
<?php
final class DifferentialGetCommitPathsConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.getcommitpaths';
}
public function getMethodDescription() {
return 'Query which paths should be included when committing a '.
'Differential revision.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'revision_id' => 'required int',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty list<string>';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_NOT_FOUND' => 'No such revision exists.',
);
}
protected function execute(ConduitAPIRequest $request) {
$id = $request->getValue('revision_id');
$revision = id(new DifferentialRevisionQuery())
->setViewer($request->getUser())
->withIDs(array($id))
->executeOne();
if (!$revision) {
throw new ConduitException('ERR_NOT_FOUND');
}
$paths = array();
$diff = id(new DifferentialDiff())->loadOneWhere(
'revisionID = %d ORDER BY id DESC limit 1',
$revision->getID());
$diff->attachChangesets($diff->loadChangesets());
foreach ($diff->getChangesets() as $changeset) {
$paths[] = $changeset->getFilename();
}
return $paths;
}
}
diff --git a/src/applications/differential/conduit/DifferentialGetDiffConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialGetDiffConduitAPIMethod.php
index 65611e8c5b..4770821f78 100644
--- a/src/applications/differential/conduit/DifferentialGetDiffConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialGetDiffConduitAPIMethod.php
@@ -1,81 +1,81 @@
<?php
final class DifferentialGetDiffConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.getdiff';
}
public function shouldAllowPublic() {
return true;
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodStatusDescription() {
return pht(
'This method has been deprecated in favor of differential.querydiffs.');
}
public function getMethodDescription() {
return pht('Load the content of a diff from Differential by revision id '.
'or diff id.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'revision_id' => 'optional id',
'diff_id' => 'optional id',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BAD_DIFF' => 'No such diff exists.',
);
}
protected function execute(ConduitAPIRequest $request) {
$diff_id = $request->getValue('diff_id');
// If we have a revision ID, we need the most recent diff. Figure that out
// without loading all the attached data.
$revision_id = $request->getValue('revision_id');
if ($revision_id) {
$diffs = id(new DifferentialDiffQuery())
->setViewer($request->getUser())
->withRevisionIDs(array($revision_id))
->execute();
if ($diffs) {
$diff_id = head($diffs)->getID();
} else {
throw new ConduitException('ERR_BAD_DIFF');
}
}
$diff = null;
if ($diff_id) {
$diff = id(new DifferentialDiffQuery())
->setViewer($request->getUser())
->withIDs(array($diff_id))
->needChangesets(true)
->needArcanistProjects(true)
->executeOne();
}
if (!$diff) {
throw new ConduitException('ERR_BAD_DIFF');
}
return $diff->getDiffDict();
}
}
diff --git a/src/applications/differential/conduit/DifferentialGetRawDiffConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialGetRawDiffConduitAPIMethod.php
index 0181d1eb08..e5b6f25a82 100644
--- a/src/applications/differential/conduit/DifferentialGetRawDiffConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialGetRawDiffConduitAPIMethod.php
@@ -1,53 +1,53 @@
<?php
final class DifferentialGetRawDiffConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.getrawdiff';
}
public function getMethodDescription() {
return pht('Retrieve a raw diff');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'diffID' => 'required diffID',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty string';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_NOT_FOUND' => pht('Diff not found.'),
);
}
protected function execute(ConduitAPIRequest $request) {
$diff_id = $request->getValue('diffID');
$viewer = $request->getUser();
$diff = id(new DifferentialDiffQuery())
->withIDs(array($diff_id))
->setViewer($viewer)
->needChangesets(true)
->executeOne();
if (!$diff) {
throw new ConduitException('ERR_NOT_FOUND');
}
$renderer = id(new DifferentialRawDiffRenderer())
->setChangesets($diff->getChangesets())
->setViewer($viewer)
->setFormat('git');
return $renderer->buildPatch();
}
}
diff --git a/src/applications/differential/conduit/DifferentialGetRevisionCommentsConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialGetRevisionCommentsConduitAPIMethod.php
index c470da0681..6a6770d3e8 100644
--- a/src/applications/differential/conduit/DifferentialGetRevisionCommentsConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialGetRevisionCommentsConduitAPIMethod.php
@@ -1,94 +1,89 @@
<?php
final class DifferentialGetRevisionCommentsConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.getrevisioncomments';
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodStatusDescription() {
return pht('Obsolete and doomed, see T2222.');
}
public function getMethodDescription() {
return 'Retrieve Differential Revision Comments.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'required list<int>',
'inlines' => 'optional bool (deprecated)',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty list<dict<string, wild>>';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$results = array();
$revision_ids = $request->getValue('ids');
if (!$revision_ids) {
return $results;
}
$revisions = id(new DifferentialRevisionQuery())
->setViewer($viewer)
->withIDs($revision_ids)
->execute();
if (!$revisions) {
return $results;
}
$xactions = id(new DifferentialTransactionQuery())
->setViewer($viewer)
->withObjectPHIDs(mpull($revisions, 'getPHID'))
->execute();
$revisions = mpull($revisions, null, 'getPHID');
foreach ($xactions as $xaction) {
$revision = idx($revisions, $xaction->getObjectPHID());
if (!$revision) {
continue;
}
$type = $xaction->getTransactionType();
if ($type == DifferentialTransaction::TYPE_ACTION) {
$action = $xaction->getNewValue();
} else if ($type == PhabricatorTransactions::TYPE_COMMENT) {
$action = 'comment';
} else {
$action = 'none';
}
$result = array(
'revisionID' => $revision->getID(),
'action' => $action,
'authorPHID' => $xaction->getAuthorPHID(),
'dateCreated' => $xaction->getDateCreated(),
'content' => ($xaction->hasComment()
? $xaction->getComment()->getContent()
: null),
);
$results[$revision->getID()][] = $result;
}
return $results;
}
}
diff --git a/src/applications/differential/conduit/DifferentialGetRevisionConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialGetRevisionConduitAPIMethod.php
index df0dfa5c9d..db0aeae83f 100644
--- a/src/applications/differential/conduit/DifferentialGetRevisionConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialGetRevisionConduitAPIMethod.php
@@ -1,103 +1,103 @@
<?php
final class DifferentialGetRevisionConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.getrevision';
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodStatusDescription() {
return "Replaced by 'differential.query'.";
}
public function getMethodDescription() {
return 'Load the content of a revision from Differential.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'revision_id' => 'required id',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BAD_REVISION' => 'No such revision exists.',
);
}
protected function execute(ConduitAPIRequest $request) {
$diff = null;
$revision_id = $request->getValue('revision_id');
$revision = id(new DifferentialRevisionQuery())
->withIDs(array($revision_id))
->setViewer($request->getUser())
->needRelationships(true)
->needReviewerStatus(true)
->executeOne();
if (!$revision) {
throw new ConduitException('ERR_BAD_REVISION');
}
$reviewer_phids = array_values($revision->getReviewers());
$diffs = id(new DifferentialDiffQuery())
->setViewer($request->getUser())
->withRevisionIDs(array($revision_id))
->needChangesets(true)
->needArcanistProjects(true)
->execute();
$diff_dicts = mpull($diffs, 'getDiffDict');
$commit_dicts = array();
$commit_phids = $revision->loadCommitPHIDs();
$handles = id(new PhabricatorHandleQuery())
->setViewer($request->getUser())
->withPHIDs($commit_phids)
->execute();
foreach ($commit_phids as $commit_phid) {
$commit_dicts[] = array(
'fullname' => $handles[$commit_phid]->getFullName(),
'dateCommitted' => $handles[$commit_phid]->getTimestamp(),
);
}
$field_data = $this->loadCustomFieldsForRevisions(
$request->getUser(),
array($revision));
$dict = array(
'id' => $revision->getID(),
'phid' => $revision->getPHID(),
'authorPHID' => $revision->getAuthorPHID(),
'uri' => PhabricatorEnv::getURI('/D'.$revision->getID()),
'title' => $revision->getTitle(),
'status' => $revision->getStatus(),
'statusName' =>
ArcanistDifferentialRevisionStatus::getNameForRevisionStatus(
$revision->getStatus()),
'summary' => $revision->getSummary(),
'testPlan' => $revision->getTestPlan(),
'lineCount' => $revision->getLineCount(),
'reviewerPHIDs' => $reviewer_phids,
'diffs' => $diff_dicts,
'commits' => $commit_dicts,
'auxiliary' => idx($field_data, $revision->getPHID(), array()),
);
return $dict;
}
}
diff --git a/src/applications/differential/conduit/DifferentialParseCommitMessageConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialParseCommitMessageConduitAPIMethod.php
index 388fa364e0..107d22d2a9 100644
--- a/src/applications/differential/conduit/DifferentialParseCommitMessageConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialParseCommitMessageConduitAPIMethod.php
@@ -1,146 +1,142 @@
<?php
final class DifferentialParseCommitMessageConduitAPIMethod
extends DifferentialConduitAPIMethod {
private $errors;
public function getAPIMethodName() {
return 'differential.parsecommitmessage';
}
public function getMethodDescription() {
return pht('Parse commit messages for Differential fields.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'corpus' => 'required string',
'partial' => 'optional bool',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$corpus = $request->getValue('corpus');
$is_partial = $request->getValue('partial');
$revision = new DifferentialRevision();
$field_list = PhabricatorCustomField::getObjectFields(
$revision,
DifferentialCustomField::ROLE_COMMITMESSAGE);
$field_list->setViewer($viewer);
$field_map = mpull($field_list->getFields(), null, 'getFieldKeyForConduit');
$this->errors = array();
$label_map = $this->buildLabelMap($field_list);
$corpus_map = $this->parseCommitMessage($corpus, $label_map);
$values = array();
foreach ($corpus_map as $field_key => $text_value) {
$field = idx($field_map, $field_key);
if (!$field) {
throw new Exception(
pht(
'Parser emitted text value for field key "%s", but no such '.
'field exists.',
$field_key));
}
try {
$values[$field_key] = $field->parseValueFromCommitMessage($text_value);
} catch (DifferentialFieldParseException $ex) {
$this->errors[] = pht(
'Error parsing field "%s": %s',
$field->renderCommitMessageLabel(),
$ex->getMessage());
}
}
if (!$is_partial) {
foreach ($field_map as $key => $field) {
try {
$field->validateCommitMessageValue(idx($values, $key));
} catch (DifferentialFieldValidationException $ex) {
$this->errors[] = pht(
'Invalid or missing field "%s": %s',
$field->renderCommitMessageLabel(),
$ex->getMessage());
}
}
}
// grab some extra information about the Differential Revision: field...
$revision_id_field = new DifferentialRevisionIDField();
$revision_id_value = idx(
$corpus_map,
$revision_id_field->getFieldKeyForConduit());
$revision_id_valid_domain = PhabricatorEnv::getProductionURI('');
return array(
'errors' => $this->errors,
'fields' => $values,
'revisionIDFieldInfo' => array(
'value' => $revision_id_value,
'validDomain' => $revision_id_valid_domain,
),
);
}
private function buildLabelMap(PhabricatorCustomFieldList $field_list) {
$label_map = array();
foreach ($field_list->getFields() as $key => $field) {
$labels = $field->getCommitMessageLabels();
$key = $field->getFieldKeyForConduit();
foreach ($labels as $label) {
$normal_label = DifferentialCommitMessageParser::normalizeFieldLabel(
$label);
if (!empty($label_map[$normal_label])) {
throw new Exception(
pht(
'Field label "%s" is parsed by two custom fields: "%s" and '.
'"%s". Each label must be parsed by only one field.',
$label,
$key,
$label_map[$normal_label]));
}
$label_map[$normal_label] = $key;
}
}
return $label_map;
}
private function parseCommitMessage($corpus, array $label_map) {
$key_title = id(new DifferentialTitleField())->getFieldKeyForConduit();
$key_summary = id(new DifferentialSummaryField())->getFieldKeyForConduit();
$parser = id(new DifferentialCommitMessageParser())
->setLabelMap($label_map)
->setTitleKey($key_title)
->setSummaryKey($key_summary);
$result = $parser->parseCorpus($corpus);
foreach ($parser->getErrors() as $error) {
$this->errors[] = $error;
}
return $result;
}
}
diff --git a/src/applications/differential/conduit/DifferentialQueryConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialQueryConduitAPIMethod.php
index 1d4882447d..04af9ff234 100644
--- a/src/applications/differential/conduit/DifferentialQueryConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialQueryConduitAPIMethod.php
@@ -1,247 +1,247 @@
<?php
final class DifferentialQueryConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.query';
}
public function getMethodDescription() {
return 'Query Differential revisions which match certain criteria.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$hash_types = ArcanistDifferentialRevisionHash::getTypes();
$hash_const = $this->formatStringConstants($hash_types);
$status_types = array(
DifferentialRevisionQuery::STATUS_ANY,
DifferentialRevisionQuery::STATUS_OPEN,
DifferentialRevisionQuery::STATUS_ACCEPTED,
DifferentialRevisionQuery::STATUS_CLOSED,
);
$status_const = $this->formatStringConstants($status_types);
$order_types = array(
DifferentialRevisionQuery::ORDER_MODIFIED,
DifferentialRevisionQuery::ORDER_CREATED,
);
$order_const = $this->formatStringConstants($order_types);
return array(
'authors' => 'optional list<phid>',
'ccs' => 'optional list<phid>',
'reviewers' => 'optional list<phid>',
'paths' => 'optional list<pair<callsign, path>>',
'commitHashes' => 'optional list<pair<'.$hash_const.', string>>',
'status' => 'optional '.$status_const,
'order' => 'optional '.$order_const,
'limit' => 'optional uint',
'offset' => 'optional uint',
'ids' => 'optional list<uint>',
'phids' => 'optional list<phid>',
'subscribers' => 'optional list<phid>',
'responsibleUsers' => 'optional list<phid>',
'branches' => 'optional list<string>',
'arcanistProjects' => 'optional list<string>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-INVALID-PARAMETER' => 'Missing or malformed parameter.',
);
}
protected function execute(ConduitAPIRequest $request) {
$authors = $request->getValue('authors');
$ccs = $request->getValue('ccs');
$reviewers = $request->getValue('reviewers');
$status = $request->getValue('status');
$order = $request->getValue('order');
$path_pairs = $request->getValue('paths');
$commit_hashes = $request->getValue('commitHashes');
$limit = $request->getValue('limit');
$offset = $request->getValue('offset');
$ids = $request->getValue('ids');
$phids = $request->getValue('phids');
$subscribers = $request->getValue('subscribers');
$responsible_users = $request->getValue('responsibleUsers');
$branches = $request->getValue('branches');
$arc_projects = $request->getValue('arcanistProjects');
$query = id(new DifferentialRevisionQuery())
->setViewer($request->getUser());
if ($authors) {
$query->withAuthors($authors);
}
if ($ccs) {
$query->withCCs($ccs);
}
if ($reviewers) {
$query->withReviewers($reviewers);
}
if ($path_pairs) {
$paths = array();
foreach ($path_pairs as $pair) {
list($callsign, $path) = $pair;
$paths[] = $path;
}
$path_map = id(new DiffusionPathIDQuery($paths))->loadPathIDs();
if (count($path_map) != count($paths)) {
$unknown_paths = array();
foreach ($paths as $p) {
if (!idx($path_map, $p)) {
$unknown_paths[] = $p;
}
}
throw id(new ConduitException('ERR-INVALID-PARAMETER'))
->setErrorDescription(
'Unknown paths: '.implode(', ', $unknown_paths));
}
$repos = array();
foreach ($path_pairs as $pair) {
list($callsign, $path) = $pair;
if (!idx($repos, $callsign)) {
$repos[$callsign] = id(new PhabricatorRepositoryQuery())
->setViewer($request->getUser())
->withCallsigns(array($callsign))
->executeOne();
if (!$repos[$callsign]) {
throw id(new ConduitException('ERR-INVALID-PARAMETER'))
->setErrorDescription(
'Unknown repo callsign: '.$callsign);
}
}
$repo = $repos[$callsign];
$query->withPath($repo->getID(), idx($path_map, $path));
}
}
if ($commit_hashes) {
$hash_types = ArcanistDifferentialRevisionHash::getTypes();
foreach ($commit_hashes as $info) {
list($type, $hash) = $info;
if (empty($type) ||
!in_array($type, $hash_types) ||
empty($hash)) {
throw new ConduitException('ERR-INVALID-PARAMETER');
}
}
$query->withCommitHashes($commit_hashes);
}
if ($status) {
$query->withStatus($status);
}
if ($order) {
$query->setOrder($order);
}
if ($limit) {
$query->setLimit($limit);
}
if ($offset) {
$query->setOffset($offset);
}
if ($ids) {
$query->withIDs($ids);
}
if ($phids) {
$query->withPHIDs($phids);
}
if ($responsible_users) {
$query->withResponsibleUsers($responsible_users);
}
if ($subscribers) {
$query->withCCs($subscribers);
}
if ($branches) {
$query->withBranches($branches);
}
if ($arc_projects) {
// This is sort of special-cased, but don't make arc do an extra round
// trip.
$projects = id(new PhabricatorRepositoryArcanistProject())
->loadAllWhere(
'name in (%Ls)',
$arc_projects);
if (!$projects) {
return array();
}
$query->withArcanistProjectPHIDs(mpull($projects, 'getPHID'));
}
$query->needRelationships(true);
$query->needCommitPHIDs(true);
$query->needDiffIDs(true);
$query->needActiveDiffs(true);
$query->needHashes(true);
$revisions = $query->execute();
$field_data = $this->loadCustomFieldsForRevisions(
$request->getUser(),
$revisions);
$results = array();
foreach ($revisions as $revision) {
$diff = $revision->getActiveDiff();
if (!$diff) {
continue;
}
$id = $revision->getID();
$phid = $revision->getPHID();
$result = array(
'id' => $id,
'phid' => $phid,
'title' => $revision->getTitle(),
'uri' => PhabricatorEnv::getProductionURI('/D'.$id),
'dateCreated' => $revision->getDateCreated(),
'dateModified' => $revision->getDateModified(),
'authorPHID' => $revision->getAuthorPHID(),
'status' => $revision->getStatus(),
'statusName' =>
ArcanistDifferentialRevisionStatus::getNameForRevisionStatus(
$revision->getStatus()),
'branch' => $diff->getBranch(),
'summary' => $revision->getSummary(),
'testPlan' => $revision->getTestPlan(),
'lineCount' => $revision->getLineCount(),
'activeDiffPHID' => $diff->getPHID(),
'diffs' => $revision->getDiffIDs(),
'commits' => $revision->getCommitPHIDs(),
'reviewers' => array_values($revision->getReviewers()),
'ccs' => array_values($revision->getCCPHIDs()),
'hashes' => $revision->getHashes(),
'auxiliary' => idx($field_data, $phid, array()),
'arcanistProjectPHID' => $diff->getArcanistProjectPHID(),
'repositoryPHID' => $diff->getRepositoryPHID(),
);
// TODO: This is a hacky way to put permissions on this field until we
// have first-class support, see T838.
if ($revision->getAuthorPHID() == $request->getUser()->getPHID()) {
$result['sourcePath'] = $diff->getSourcePath();
}
$results[] = $result;
}
return $results;
}
}
diff --git a/src/applications/differential/conduit/DifferentialQueryDiffsConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialQueryDiffsConduitAPIMethod.php
index 398a3176a2..630f07da2b 100644
--- a/src/applications/differential/conduit/DifferentialQueryDiffsConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialQueryDiffsConduitAPIMethod.php
@@ -1,47 +1,43 @@
<?php
final class DifferentialQueryDiffsConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.querydiffs';
}
public function getMethodDescription() {
return pht('Query differential diffs which match certain criteria.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<uint>',
'revisionIDs' => 'optional list<uint>',
);
}
- public function defineErrorTypes() {
- return array();
- }
-
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
protected function execute(ConduitAPIRequest $request) {
$ids = $request->getValue('ids', array());
$revision_ids = $request->getValue('revisionIDs', array());
$diffs = array();
if ($ids || $revision_ids) {
$diffs = id(new DifferentialDiffQuery())
->setViewer($request->getUser())
->withIDs($ids)
->withRevisionIDs($revision_ids)
->needChangesets(true)
->needArcanistProjects(true)
->execute();
}
return mpull($diffs, 'getDiffDict', 'getID');
}
}
diff --git a/src/applications/differential/conduit/DifferentialSetDiffPropertyConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialSetDiffPropertyConduitAPIMethod.php
index d392ce374d..d79be1363d 100644
--- a/src/applications/differential/conduit/DifferentialSetDiffPropertyConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialSetDiffPropertyConduitAPIMethod.php
@@ -1,115 +1,115 @@
<?php
final class DifferentialSetDiffPropertyConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.setdiffproperty';
}
public function getMethodDescription() {
return 'Attach properties to Differential diffs.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'diff_id' => 'required diff_id',
'name' => 'required string',
'data' => 'required string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_NOT_FOUND' => 'Diff was not found.',
);
}
private static function updateLintStatus($diff_id) {
$diff = id(new DifferentialDiff())->load($diff_id);
if (!$diff) {
throw new ConduitException('ERR_NOT_FOUND');
}
// Load the postponed linters attached to this diff.
$postponed_linters_property = id(
new DifferentialDiffProperty())->loadOneWhere(
'diffID = %d AND name = %s',
$diff_id,
'arc:lint-postponed');
if ($postponed_linters_property) {
$postponed_linters = $postponed_linters_property->getData();
} else {
$postponed_linters = array();
}
// Load the lint messages currenty attached to the diff
$messages_property = id(new DifferentialDiffProperty())->loadOneWhere(
'diffID = %d AND name = %s',
$diff_id,
'arc:lint');
if ($messages_property) {
$results = $messages_property->getData();
} else {
$results = array();
}
$has_error = false;
$has_warning = false;
foreach ($results as $result) {
if ($result['severity'] === ArcanistLintSeverity::SEVERITY_ERROR) {
$has_error = true;
break;
} else if ($result['severity'] ===
ArcanistLintSeverity::SEVERITY_WARNING) {
$has_warning = true;
}
}
if ($has_error) {
$diff->setLintStatus(DifferentialLintStatus::LINT_FAIL);
} else if ($has_warning) {
$diff->setLintStatus(DifferentialLintStatus::LINT_WARN);
} else if (!empty($postponed_linters)) {
$diff->setLintStatus(DifferentialLintStatus::LINT_POSTPONED);
} else if ($diff->getLintStatus() != DifferentialLintStatus::LINT_SKIP) {
$diff->setLintStatus(DifferentialLintStatus::LINT_OKAY);
}
$diff->save();
}
protected function execute(ConduitAPIRequest $request) {
$diff_id = $request->getValue('diff_id');
$name = $request->getValue('name');
$data = json_decode($request->getValue('data'), true);
self::updateDiffProperty($diff_id, $name, $data);
if ($name === 'arc:lint' || $name == 'arc:lint-postponed') {
self::updateLintStatus($diff_id);
}
return;
}
private static function updateDiffProperty($diff_id, $name, $data) {
$property = id(new DifferentialDiffProperty())->loadOneWhere(
'diffID = %d AND name = %s',
$diff_id,
$name);
if (!$property) {
$property = new DifferentialDiffProperty();
$property->setDiffID($diff_id);
$property->setName($name);
}
$property->setData($data);
$property->save();
return $property;
}
}
diff --git a/src/applications/differential/conduit/DifferentialUpdateRevisionConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialUpdateRevisionConduitAPIMethod.php
index 6a328814fb..e8a34fd133 100644
--- a/src/applications/differential/conduit/DifferentialUpdateRevisionConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialUpdateRevisionConduitAPIMethod.php
@@ -1,79 +1,79 @@
<?php
final class DifferentialUpdateRevisionConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.updaterevision';
}
public function getMethodDescription() {
return pht('Update a Differential revision.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'id' => 'required revisionid',
'diffid' => 'required diffid',
'fields' => 'required dict',
'message' => 'required string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BAD_DIFF' => 'Bad diff ID.',
'ERR_BAD_REVISION' => 'Bad revision ID.',
'ERR_WRONG_USER' => 'You are not the author of this revision.',
'ERR_CLOSED' => 'This revision has already been closed.',
);
}
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$diff = id(new DifferentialDiffQuery())
->setViewer($viewer)
->withIDs(array($request->getValue('diffid')))
->executeOne();
if (!$diff) {
throw new ConduitException('ERR_BAD_DIFF');
}
$revision = id(new DifferentialRevisionQuery())
->setViewer($request->getUser())
->withIDs(array($request->getValue('id')))
->needReviewerStatus(true)
->needActiveDiffs(true)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$revision) {
throw new ConduitException('ERR_BAD_REVISION');
}
if ($revision->getStatus() == ArcanistDifferentialRevisionStatus::CLOSED) {
throw new ConduitException('ERR_CLOSED');
}
$this->applyFieldEdit(
$request,
$revision,
$diff,
$request->getValue('fields', array()),
$request->getValue('message'));
return array(
'revisionid' => $revision->getID(),
'uri' => PhabricatorEnv::getURI('/D'.$revision->getID()),
);
}
}
diff --git a/src/applications/differential/conduit/DifferentialUpdateUnitResultsConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialUpdateUnitResultsConduitAPIMethod.php
index 90dc59761a..0f0c14a6b8 100644
--- a/src/applications/differential/conduit/DifferentialUpdateUnitResultsConduitAPIMethod.php
+++ b/src/applications/differential/conduit/DifferentialUpdateUnitResultsConduitAPIMethod.php
@@ -1,155 +1,155 @@
<?php
final class DifferentialUpdateUnitResultsConduitAPIMethod
extends DifferentialConduitAPIMethod {
public function getAPIMethodName() {
return 'differential.updateunitresults';
}
public function getMethodDescription() {
return 'Update arc unit results for a postponed test.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'diff_id' => 'required diff_id',
'file' => 'required string',
'name' => 'required string',
'link' => 'optional string',
'result' => 'required string',
'message' => 'required string',
'coverage' => 'optional map<string, string>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BAD_DIFF' => 'Bad diff ID.',
'ERR_NO_RESULTS' => 'Could not find the postponed test',
);
}
protected function execute(ConduitAPIRequest $request) {
$diff_id = $request->getValue('diff_id');
if (!$diff_id) {
throw new ConduitException('ERR_BAD_DIFF');
}
$file = $request->getValue('file');
$name = $request->getValue('name');
$link = $request->getValue('link');
$message = $request->getValue('message');
$result = $request->getValue('result');
$coverage = $request->getValue('coverage', array());
$diff_property = id(new DifferentialDiffProperty())->loadOneWhere(
'diffID = %d AND name = %s',
$diff_id,
'arc:unit');
if (!$diff_property) {
throw new ConduitException('ERR_NO_RESULTS');
}
$diff = id(new DifferentialDiffQuery())
->setViewer($request->getUser())
->withIDs(array($diff_id))
->executeOne();
$unit_results = $diff_property->getData();
$postponed_count = 0;
$unit_status = null;
// If the test result already exists, then update it with
// the new info.
foreach ($unit_results as &$unit_result) {
if ($unit_result['name'] === $name ||
$unit_result['name'] === $file ||
$unit_result['name'] === $diff->getSourcePath().$file) {
$unit_result['name'] = $name;
$unit_result['link'] = $link;
$unit_result['file'] = $file;
$unit_result['result'] = $result;
$unit_result['userdata'] = $message;
$unit_result['coverage'] = $coverage;
$unit_status = $result;
break;
}
}
unset($unit_result);
// If the test result doesn't exist, just add it.
if (!$unit_status) {
$unit_result = array();
$unit_result['file'] = $file;
$unit_result['name'] = $name;
$unit_result['link'] = $link;
$unit_result['result'] = $result;
$unit_result['userdata'] = $message;
$unit_result['coverage'] = $coverage;
$unit_status = $result;
$unit_results[] = $unit_result;
}
unset($unit_result);
$diff_property->setData($unit_results);
$diff_property->save();
// Map external unit test status to internal overall diff status
$status_codes =
array(
DifferentialUnitTestResult::RESULT_PASS =>
DifferentialUnitStatus::UNIT_OKAY,
DifferentialUnitTestResult::RESULT_UNSOUND =>
DifferentialUnitStatus::UNIT_WARN,
DifferentialUnitTestResult::RESULT_FAIL =>
DifferentialUnitStatus::UNIT_FAIL,
DifferentialUnitTestResult::RESULT_BROKEN =>
DifferentialUnitStatus::UNIT_FAIL,
DifferentialUnitTestResult::RESULT_SKIP =>
DifferentialUnitStatus::UNIT_OKAY,
DifferentialUnitTestResult::RESULT_POSTPONED =>
DifferentialUnitStatus::UNIT_POSTPONED,
);
// These are the relative priorities for the unit test results
$status_codes_priority =
array(
DifferentialUnitStatus::UNIT_OKAY => 1,
DifferentialUnitStatus::UNIT_WARN => 2,
DifferentialUnitStatus::UNIT_POSTPONED => 3,
DifferentialUnitStatus::UNIT_FAIL => 4,
);
// Walk the now-current list of status codes to find the overall diff
// status
$final_diff_status = DifferentialUnitStatus::UNIT_NONE;
foreach ($unit_results as $unit_result) {
// Convert the text result into a diff unit status value
$status_code = idx($status_codes,
$unit_result['result'],
DifferentialUnitStatus::UNIT_NONE);
// Convert the unit status into a relative value
$diff_status_priority = idx($status_codes_priority, $status_code, 0);
// If the relative value of this result is "more bad" than previous
// results, use it as the new final diff status
if ($diff_status_priority > idx($status_codes_priority,
$final_diff_status, 0)) {
$final_diff_status = $status_code;
}
}
// Update our unit test result status with the final value
$diff->setUnitStatus($final_diff_status);
$diff->save();
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php
index d0c4d9c484..1271088b1b 100644
--- a/src/applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php
@@ -1,114 +1,114 @@
<?php
final class DiffusionBranchQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.branchquery';
}
public function getMethodDescription() {
return pht('Determine what branches exist for a repository.');
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
protected function defineCustomParamTypes() {
return array(
'limit' => 'optional int',
'offset' => 'optional int',
'contains' => 'optional string',
);
}
protected function getGitResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$contains = $request->getValue('contains');
if (strlen($contains)) {
// NOTE: We can't use DiffusionLowLevelGitRefQuery here because
// `git for-each-ref` does not support `--contains`.
if ($repository->isWorkingCopyBare()) {
list($stdout) = $repository->execxLocalCommand(
'branch --verbose --no-abbrev --contains %s --',
$contains);
$ref_map = DiffusionGitBranch::parseLocalBranchOutput(
$stdout);
} else {
list($stdout) = $repository->execxLocalCommand(
'branch -r --verbose --no-abbrev --contains %s --',
$contains);
$ref_map = DiffusionGitBranch::parseRemoteBranchOutput(
$stdout,
DiffusionGitBranch::DEFAULT_GIT_REMOTE);
}
$refs = array();
foreach ($ref_map as $ref => $commit) {
$refs[] = id(new DiffusionRepositoryRef())
->setShortName($ref)
->setCommitIdentifier($commit);
}
} else {
$refs = id(new DiffusionLowLevelGitRefQuery())
->setRepository($repository)
->withIsOriginBranch(true)
->execute();
}
return $this->processBranchRefs($request, $refs);
}
protected function getMercurialResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$query = id(new DiffusionLowLevelMercurialBranchesQuery())
->setRepository($repository);
$contains = $request->getValue('contains');
if (strlen($contains)) {
$query->withContainsCommit($contains);
}
$refs = $query->execute();
return $this->processBranchRefs($request, $refs);
}
protected function getSVNResult(ConduitAPIRequest $request) {
// Since SVN doesn't have meaningful branches, just return nothing for all
// queries.
return array();
}
private function processBranchRefs(ConduitAPIRequest $request, array $refs) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$offset = $request->getValue('offset');
$limit = $request->getValue('limit');
foreach ($refs as $key => $ref) {
if (!$repository->shouldTrackBranch($ref->getShortName())) {
unset($refs[$key]);
}
}
// NOTE: We can't apply the offset or limit until here, because we may have
// filtered untrackable branches out of the result set.
if ($offset) {
$refs = array_slice($refs, $offset);
}
if ($limit) {
$refs = array_slice($refs, 0, $limit);
}
return mpull($refs, 'toDictionary');
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionBrowseQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionBrowseQueryConduitAPIMethod.php
index ab20f13d02..f8854ac0f2 100644
--- a/src/applications/diffusion/conduit/DiffusionBrowseQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionBrowseQueryConduitAPIMethod.php
@@ -1,469 +1,469 @@
<?php
final class DiffusionBrowseQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.browsequery';
}
public function getMethodDescription() {
return
'File(s) information for a repository at an (optional) path and '.
'(optional) commit.';
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'array';
}
protected function defineCustomParamTypes() {
return array(
'path' => 'optional string',
'commit' => 'optional string',
'needValidityOnly' => 'optional bool',
);
}
protected function getResult(ConduitAPIRequest $request) {
$result = parent::getResult($request);
return $result->toDictionary();
}
protected function getGitResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$path = $request->getValue('path');
$commit = $request->getValue('commit');
$result = $this->getEmptyResultSet();
if ($path == '') {
// Fast path to improve the performance of the repository view; we know
// the root is always a tree at any commit and always exists.
$stdout = 'tree';
} else {
try {
list($stdout) = $repository->execxLocalCommand(
'cat-file -t %s:%s',
$commit,
$path);
} catch (CommandException $e) {
$stderr = $e->getStdErr();
if (preg_match('/^fatal: Not a valid object name/', $stderr)) {
// Grab two logs, since the first one is when the object was deleted.
list($stdout) = $repository->execxLocalCommand(
'log -n2 --format="%%H" %s -- %s',
$commit,
$path);
$stdout = trim($stdout);
if ($stdout) {
$commits = explode("\n", $stdout);
$result
->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_DELETED)
->setDeletedAtCommit(idx($commits, 0))
->setExistedAtCommit(idx($commits, 1));
return $result;
}
$result->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_NONEXISTENT);
return $result;
} else {
throw $e;
}
}
}
if (trim($stdout) == 'blob') {
$result->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_FILE);
return $result;
}
$result->setIsValidResults(true);
if ($this->shouldOnlyTestValidity($request)) {
return $result;
}
list($stdout) = $repository->execxLocalCommand(
'ls-tree -z -l %s:%s',
$commit,
$path);
$submodules = array();
if (strlen($path)) {
$prefix = rtrim($path, '/').'/';
} else {
$prefix = '';
}
$results = array();
foreach (explode("\0", rtrim($stdout)) as $line) {
// NOTE: Limit to 5 components so we parse filenames with spaces in them
// correctly.
// NOTE: The output uses a mixture of tabs and one-or-more spaces to
// delimit fields.
$parts = preg_split('/\s+/', $line, 5);
if (count($parts) < 5) {
throw new Exception(
pht(
'Expected "<mode> <type> <hash> <size>\t<name>", for ls-tree of '.
'"%s:%s", got: %s',
$commit,
$path,
$line));
}
list($mode, $type, $hash, $size, $name) = $parts;
$path_result = new DiffusionRepositoryPath();
if ($type == 'tree') {
$file_type = DifferentialChangeType::FILE_DIRECTORY;
} else if ($type == 'commit') {
$file_type = DifferentialChangeType::FILE_SUBMODULE;
$submodules[] = $path_result;
} else {
$mode = intval($mode, 8);
if (($mode & 0120000) == 0120000) {
$file_type = DifferentialChangeType::FILE_SYMLINK;
} else {
$file_type = DifferentialChangeType::FILE_NORMAL;
}
}
$path_result->setFullPath($prefix.$name);
$path_result->setPath($name);
$path_result->setHash($hash);
$path_result->setFileType($file_type);
$path_result->setFileSize($size);
$results[] = $path_result;
}
// If we identified submodules, lookup the module info at this commit to
// find their source URIs.
if ($submodules) {
// NOTE: We need to read the file out of git and write it to a temporary
// location because "git config -f" doesn't accept a "commit:path"-style
// argument.
// NOTE: This file may not exist, e.g. because the commit author removed
// it when they added the submodule. See T1448. If it's not present, just
// show the submodule without enriching it. If ".gitmodules" was removed
// it seems to partially break submodules, but the repository as a whole
// continues to work fine and we've seen at least two cases of this in
// the wild.
list($err, $contents) = $repository->execLocalCommand(
'cat-file blob %s:.gitmodules',
$commit);
if (!$err) {
$tmp = new TempFile();
Filesystem::writeFile($tmp, $contents);
list($module_info) = $repository->execxLocalCommand(
'config -l -f %s',
$tmp);
$dict = array();
$lines = explode("\n", trim($module_info));
foreach ($lines as $line) {
list($key, $value) = explode('=', $line, 2);
$parts = explode('.', $key);
$dict[$key] = $value;
}
foreach ($submodules as $path) {
$full_path = $path->getFullPath();
$key = 'submodule.'.$full_path.'.url';
if (isset($dict[$key])) {
$path->setExternalURI($dict[$key]);
}
}
}
}
return $result->setPaths($results);
}
protected function getMercurialResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$path = $request->getValue('path');
$commit = $request->getValue('commit');
$result = $this->getEmptyResultSet();
$entire_manifest = id(new DiffusionLowLevelMercurialPathsQuery())
->setRepository($repository)
->withCommit($commit)
->withPath($path)
->execute();
$results = array();
$match_against = trim($path, '/');
$match_len = strlen($match_against);
// For the root, don't trim. For other paths, trim the "/" after we match.
// We need this because Mercurial's canonical paths have no leading "/",
// but ours do.
$trim_len = $match_len ? $match_len + 1 : 0;
foreach ($entire_manifest as $path) {
if (strncmp($path, $match_against, $match_len)) {
continue;
}
if (!strlen($path)) {
continue;
}
$remainder = substr($path, $trim_len);
if (!strlen($remainder)) {
// There is a file with this exact name in the manifest, so clearly
// it's a file.
$result->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_FILE);
return $result;
}
$parts = explode('/', $remainder);
if (count($parts) == 1) {
$type = DifferentialChangeType::FILE_NORMAL;
} else {
$type = DifferentialChangeType::FILE_DIRECTORY;
}
$results[reset($parts)] = $type;
}
foreach ($results as $key => $type) {
$path_result = new DiffusionRepositoryPath();
$path_result->setPath($key);
$path_result->setFileType($type);
$path_result->setFullPath(ltrim($match_against.'/', '/').$key);
$results[$key] = $path_result;
}
$valid_results = true;
if (empty($results)) {
// TODO: Detect "deleted" by issuing "hg log"?
$result->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_NONEXISTENT);
$valid_results = false;
}
return $result
->setPaths($results)
->setIsValidResults($valid_results);
}
protected function getSVNResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$path = $request->getValue('path');
$commit = $request->getValue('commit');
$result = $this->getEmptyResultSet();
$subpath = $repository->getDetail('svn-subpath');
if ($subpath && strncmp($subpath, $path, strlen($subpath))) {
// If we have a subpath and the path isn't a child of it, it (almost
// certainly) won't exist since we don't track commits which affect
// it. (Even if it exists, return a consistent result.)
$result->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_UNTRACKED_PARENT);
return $result;
}
$conn_r = $repository->establishConnection('r');
$parent_path = DiffusionPathIDQuery::getParentPath($path);
$path_query = new DiffusionPathIDQuery(
array(
$path,
$parent_path,
));
$path_map = $path_query->loadPathIDs();
$path_id = $path_map[$path];
$parent_path_id = $path_map[$parent_path];
if (empty($path_id)) {
$result->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_NONEXISTENT);
return $result;
}
if ($commit) {
$slice_clause = 'AND svnCommit <= '.(int)$commit;
} else {
$slice_clause = '';
}
$index = queryfx_all(
$conn_r,
'SELECT pathID, max(svnCommit) maxCommit FROM %T WHERE
repositoryID = %d AND parentID = %d
%Q GROUP BY pathID',
PhabricatorRepository::TABLE_FILESYSTEM,
$repository->getID(),
$path_id,
$slice_clause);
if (!$index) {
if ($path == '/') {
$result->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_EMPTY);
} else {
// NOTE: The parent path ID is included so this query can take
// advantage of the table's primary key; it is uniquely determined by
// the pathID but if we don't do the lookup ourselves MySQL doesn't have
// the information it needs to avoid a table scan.
$reasons = queryfx_all(
$conn_r,
'SELECT * FROM %T WHERE repositoryID = %d
AND parentID = %d
AND pathID = %d
%Q ORDER BY svnCommit DESC LIMIT 2',
PhabricatorRepository::TABLE_FILESYSTEM,
$repository->getID(),
$parent_path_id,
$path_id,
$slice_clause);
$reason = reset($reasons);
if (!$reason) {
$result->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_NONEXISTENT);
} else {
$file_type = $reason['fileType'];
if (empty($reason['existed'])) {
$result->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_DELETED);
$result->setDeletedAtCommit($reason['svnCommit']);
if (!empty($reasons[1])) {
$result->setExistedAtCommit($reasons[1]['svnCommit']);
}
} else if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
$result->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_EMPTY);
} else {
$result->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_FILE);
}
}
}
return $result;
}
$result->setIsValidResults(true);
if ($this->shouldOnlyTestValidity($request)) {
return $result;
}
$sql = array();
foreach ($index as $row) {
$sql[] =
'(pathID = '.(int)$row['pathID'].' AND '.
'svnCommit = '.(int)$row['maxCommit'].')';
}
$browse = queryfx_all(
$conn_r,
'SELECT *, p.path pathName
FROM %T f JOIN %T p ON f.pathID = p.id
WHERE repositoryID = %d
AND parentID = %d
AND existed = 1
AND (%Q)
ORDER BY pathName',
PhabricatorRepository::TABLE_FILESYSTEM,
PhabricatorRepository::TABLE_PATH,
$repository->getID(),
$path_id,
implode(' OR ', $sql));
$loadable_commits = array();
foreach ($browse as $key => $file) {
// We need to strip out directories because we don't store last-modified
// in the filesystem table.
if ($file['fileType'] != DifferentialChangeType::FILE_DIRECTORY) {
$loadable_commits[] = $file['svnCommit'];
$browse[$key]['hasCommit'] = true;
}
}
$commits = array();
$commit_data = array();
if ($loadable_commits) {
// NOTE: Even though these are integers, use '%Ls' because MySQL doesn't
// use the second part of the key otherwise!
$commits = id(new PhabricatorRepositoryCommit())->loadAllWhere(
'repositoryID = %d AND commitIdentifier IN (%Ls)',
$repository->getID(),
$loadable_commits);
$commits = mpull($commits, null, 'getCommitIdentifier');
if ($commits) {
$commit_data = id(new PhabricatorRepositoryCommitData())->loadAllWhere(
'commitID in (%Ld)',
mpull($commits, 'getID'));
$commit_data = mpull($commit_data, null, 'getCommitID');
} else {
$commit_data = array();
}
}
$path_normal = DiffusionPathIDQuery::normalizePath($path);
$results = array();
foreach ($browse as $file) {
$full_path = $file['pathName'];
$file_path = ltrim(substr($full_path, strlen($path_normal)), '/');
$full_path = ltrim($full_path, '/');
$result_path = new DiffusionRepositoryPath();
$result_path->setPath($file_path);
$result_path->setFullPath($full_path);
// $result_path->setHash($hash);
$result_path->setFileType($file['fileType']);
// $result_path->setFileSize($size);
if (!empty($file['hasCommit'])) {
$commit = idx($commits, $file['svnCommit']);
if ($commit) {
$data = idx($commit_data, $commit->getID());
$result_path->setLastModifiedCommit($commit);
$result_path->setLastCommitData($data);
}
}
$results[] = $result_path;
}
if (empty($results)) {
$result->setReasonForEmptyResultSet(
DiffusionBrowseResultSet::REASON_IS_EMPTY);
}
return $result->setPaths($results);
}
private function getEmptyResultSet() {
return id(new DiffusionBrowseResultSet())
->setPaths(array())
->setReasonForEmptyResultSet(null)
->setIsValidResults(false);
}
private function shouldOnlyTestValidity(ConduitAPIRequest $request) {
return $request->getValue('needValidityOnly', false);
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionCommitParentsQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionCommitParentsQueryConduitAPIMethod.php
index c6a3220747..28b08a2c6d 100644
--- a/src/applications/diffusion/conduit/DiffusionCommitParentsQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionCommitParentsQueryConduitAPIMethod.php
@@ -1,34 +1,34 @@
<?php
final class DiffusionCommitParentsQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.commitparentsquery';
}
public function getMethodDescription() {
return pht(
"Get the commit identifiers for a commit's parent or parents.");
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<string>';
}
protected function defineCustomParamTypes() {
return array(
'commit' => 'required string',
);
}
protected function getResult(ConduitAPIRequest $request) {
$repository = $this->getRepository($request);
return id(new DiffusionLowLevelParentsQuery())
->setRepository($repository)
->withIdentifier($request->getValue('commit'))
->execute();
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionCreateCommentConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionCreateCommentConduitAPIMethod.php
index e0e3927f93..8d978e3f25 100644
--- a/src/applications/diffusion/conduit/DiffusionCreateCommentConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionCreateCommentConduitAPIMethod.php
@@ -1,100 +1,100 @@
<?php
final class DiffusionCreateCommentConduitAPIMethod
extends DiffusionConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.createcomment';
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodDescription() {
return 'Add a comment to a Diffusion commit. By specifying an action of '.
'"concern", "accept", "resign", or "close", auditing actions can '.
'be triggered. Defaults to "comment".';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'phid' => 'required string',
'action' => 'optional string',
'message' => 'required string',
'silent' => 'optional bool',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'bool';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BAD_COMMIT' => 'No commit found with that PHID',
'ERR_BAD_ACTION' => 'Invalid action type',
'ERR_MISSING_MESSAGE' => 'Message is required',
);
}
protected function execute(ConduitAPIRequest $request) {
$commit_phid = $request->getValue('phid');
$commit = id(new DiffusionCommitQuery())
->setViewer($request->getUser())
->withPHIDs(array($commit_phid))
->needAuditRequests(true)
->executeOne();
if (!$commit) {
throw new ConduitException('ERR_BAD_COMMIT');
}
$message = trim($request->getValue('message'));
if (!$message) {
throw new ConduitException('ERR_MISSING_MESSAGE');
}
$action = $request->getValue('action');
if (!$action) {
$action = PhabricatorAuditActionConstants::COMMENT;
}
// Disallow ADD_CCS, ADD_AUDITORS forever.
if (!in_array($action, array(
PhabricatorAuditActionConstants::CONCERN,
PhabricatorAuditActionConstants::ACCEPT,
PhabricatorAuditActionConstants::COMMENT,
PhabricatorAuditActionConstants::RESIGN,
PhabricatorAuditActionConstants::CLOSE,
))) {
throw new ConduitException('ERR_BAD_ACTION');
}
$xactions = array();
if ($action != PhabricatorAuditActionConstants::COMMENT) {
$xactions[] = id(new PhabricatorAuditTransaction())
->setTransactionType(PhabricatorAuditActionConstants::ACTION)
->setNewValue($action);
}
if (strlen($message)) {
$xactions[] = id(new PhabricatorAuditTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(new PhabricatorAuditTransactionComment())
->setCommitPHID($commit->getPHID())
->setContent($message));
}
id(new PhabricatorAuditEditor())
->setActor($request->getUser())
->setContentSourceFromConduitRequest($request)
->setDisableEmail($request->getValue('silent'))
->setContinueOnMissingFields(true)
->applyTransactions($commit, $xactions);
return true;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionDiffQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionDiffQueryConduitAPIMethod.php
index 4dc2a2bac9..0ec00bc762 100644
--- a/src/applications/diffusion/conduit/DiffusionDiffQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionDiffQueryConduitAPIMethod.php
@@ -1,239 +1,239 @@
<?php
final class DiffusionDiffQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
private $effectiveCommit;
public function getAPIMethodName() {
return 'diffusion.diffquery';
}
public function getMethodDescription() {
return
'Get diff information from a repository for a specific path at an '.
'(optional) commit.';
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'array';
}
protected function defineCustomParamTypes() {
return array(
'path' => 'required string',
'commit' => 'optional string',
);
}
protected function getResult(ConduitAPIRequest $request) {
$result = parent::getResult($request);
return array(
'changes' => mpull($result, 'toDictionary'),
'effectiveCommit' => $this->getEffectiveCommit($request),
);
}
protected function getGitResult(ConduitAPIRequest $request) {
return $this->getGitOrMercurialResult($request);
}
protected function getMercurialResult(ConduitAPIRequest $request) {
return $this->getGitOrMercurialResult($request);
}
/**
* NOTE: We have to work particularly hard for SVN as compared to other VCS.
* That's okay but means this shares little code with the other VCS.
*/
protected function getSVNResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$effective_commit = $this->getEffectiveCommit($request);
if (!$effective_commit) {
return $this->getEmptyResult();
}
$drequest = clone $drequest;
$drequest->updateSymbolicCommit($effective_commit);
$path_change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
$drequest);
$path_changes = $path_change_query->loadChanges();
$path = null;
foreach ($path_changes as $change) {
if ($change->getPath() == $drequest->getPath()) {
$path = $change;
}
}
if (!$path) {
return $this->getEmptyResult();
}
$change_type = $path->getChangeType();
switch ($change_type) {
case DifferentialChangeType::TYPE_MULTICOPY:
case DifferentialChangeType::TYPE_DELETE:
if ($path->getTargetPath()) {
$old = array(
$path->getTargetPath(),
$path->getTargetCommitIdentifier(),
);
} else {
$old = array($path->getPath(), $path->getCommitIdentifier() - 1);
}
$old_name = $path->getPath();
$new_name = '';
$new = null;
break;
case DifferentialChangeType::TYPE_ADD:
$old = null;
$new = array($path->getPath(), $path->getCommitIdentifier());
$old_name = '';
$new_name = $path->getPath();
break;
case DifferentialChangeType::TYPE_MOVE_HERE:
case DifferentialChangeType::TYPE_COPY_HERE:
$old = array(
$path->getTargetPath(),
$path->getTargetCommitIdentifier(),
);
$new = array($path->getPath(), $path->getCommitIdentifier());
$old_name = $path->getTargetPath();
$new_name = $path->getPath();
break;
case DifferentialChangeType::TYPE_MOVE_AWAY:
$old = array(
$path->getPath(),
$path->getCommitIdentifier() - 1,
);
$old_name = $path->getPath();
$new_name = null;
$new = null;
break;
default:
$old = array($path->getPath(), $path->getCommitIdentifier() - 1);
$new = array($path->getPath(), $path->getCommitIdentifier());
$old_name = $path->getPath();
$new_name = $path->getPath();
break;
}
$futures = array(
'old' => $this->buildSVNContentFuture($old),
'new' => $this->buildSVNContentFuture($new),
);
$futures = array_filter($futures);
foreach (new FutureIterator($futures) as $key => $future) {
$stdout = '';
try {
list($stdout) = $future->resolvex();
} catch (CommandException $e) {
if ($path->getFileType() != DifferentialChangeType::FILE_DIRECTORY) {
throw $e;
}
}
$futures[$key] = $stdout;
}
$old_data = idx($futures, 'old', '');
$new_data = idx($futures, 'new', '');
$engine = new PhabricatorDifferenceEngine();
$engine->setOldName($old_name);
$engine->setNewName($new_name);
$raw_diff = $engine->generateRawDiffFromFileContent($old_data, $new_data);
$arcanist_changes = DiffusionPathChange::convertToArcanistChanges(
$path_changes);
$parser = $this->getDefaultParser();
$parser->setChanges($arcanist_changes);
$parser->forcePath($path->getPath());
$changes = $parser->parseDiff($raw_diff);
$change = $changes[$path->getPath()];
return array($change);
}
private function getEffectiveCommit(ConduitAPIRequest $request) {
if ($this->effectiveCommit === null) {
$drequest = $this->getDiffusionRequest();
$path = $drequest->getPath();
$result = DiffusionQuery::callConduitWithDiffusionRequest(
$request->getUser(),
$drequest,
'diffusion.lastmodifiedquery',
array(
'paths' => array($path => $drequest->getStableCommit()),
));
$this->effectiveCommit = idx($result, $path);
}
return $this->effectiveCommit;
}
private function buildSVNContentFuture($spec) {
if (!$spec) {
return null;
}
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
list($ref, $rev) = $spec;
return $repository->getRemoteCommandFuture(
'cat %s',
$repository->getSubversionPathURI($ref, $rev));
}
private function getGitOrMercurialResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$effective_commit = $this->getEffectiveCommit($request);
if (!$effective_commit) {
return $this->getEmptyResult(1);
}
$raw_query = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest)
->setAnchorCommit($effective_commit);
$raw_diff = $raw_query->loadRawDiff();
if (!$raw_diff) {
return $this->getEmptyResult(2);
}
$parser = $this->getDefaultParser();
$changes = $parser->parseDiff($raw_diff);
return $changes;
}
private function getDefaultParser() {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$parser = new ArcanistDiffParser();
$try_encoding = $repository->getDetail('encoding');
if ($try_encoding) {
$parser->setTryEncoding($try_encoding);
}
$parser->setDetectBinaryFiles(true);
return $parser;
}
private function getEmptyResult() {
return array();
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php
index 9728c2f1f5..d0d5453a34 100644
--- a/src/applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php
@@ -1,57 +1,57 @@
<?php
final class DiffusionExistsQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.existsquery';
}
public function getMethodDescription() {
return 'Determine if code exists in a version control system.';
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'bool';
}
protected function defineCustomParamTypes() {
return array(
'commit' => 'required string',
);
}
protected function getGitResult(ConduitAPIRequest $request) {
$repository = $this->getDiffusionRequest()->getRepository();
$commit = $request->getValue('commit');
list($err, $merge_base) = $repository->execLocalCommand(
'cat-file -t %s',
$commit);
return !$err;
}
protected function getSVNResult(ConduitAPIRequest $request) {
$repository = $this->getDiffusionRequest()->getRepository();
$commit = $request->getValue('commit');
list($info) = $repository->execxRemoteCommand(
'info %s',
$repository->getRemoteURI());
$exists = false;
$matches = null;
if (preg_match('/^Revision: (\d+)$/m', $info, $matches)) {
$base_revision = $matches[1];
$exists = $base_revision >= $commit;
}
return $exists;
}
protected function getMercurialResult(ConduitAPIRequest $request) {
$repository = $this->getDiffusionRequest()->getRepository();
$commit = $request->getValue('commit');
list($err, $stdout) = $repository->execLocalCommand(
'id --rev %s',
$commit);
return !$err;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionFileContentQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionFileContentQueryConduitAPIMethod.php
index 0afd3bcb25..9204a84bbc 100644
--- a/src/applications/diffusion/conduit/DiffusionFileContentQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionFileContentQueryConduitAPIMethod.php
@@ -1,47 +1,47 @@
<?php
final class DiffusionFileContentQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.filecontentquery';
}
public function getMethodDescription() {
return 'Retrieve file content from a repository.';
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'array';
}
protected function defineCustomParamTypes() {
return array(
'path' => 'required string',
'commit' => 'required string',
'needsBlame' => 'optional bool',
);
}
protected function getResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$needs_blame = $request->getValue('needsBlame');
$file_query = DiffusionFileContentQuery::newFromDiffusionRequest(
$drequest);
$file_query
->setViewer($request->getUser())
->setNeedsBlame($needs_blame);
$file_content = $file_query->loadFileContent();
if ($needs_blame) {
list($text_list, $rev_list, $blame_dict) = $file_query->getBlameData();
} else {
$text_list = $rev_list = $blame_dict = array();
}
$file_content
->setBlameDict($blame_dict)
->setRevList($rev_list)
->setTextList($text_list);
return $file_content->toDictionary();
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionFindSymbolsConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionFindSymbolsConduitAPIMethod.php
index 34575ae99d..da4025bc05 100644
--- a/src/applications/diffusion/conduit/DiffusionFindSymbolsConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionFindSymbolsConduitAPIMethod.php
@@ -1,86 +1,81 @@
<?php
final class DiffusionFindSymbolsConduitAPIMethod
extends DiffusionConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.findsymbols';
}
public function getMethodDescription() {
return 'Retrieve Diffusion symbol information.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'name' => 'optional string',
'namePrefix' => 'optional string',
'context' => 'optional string',
'language' => 'optional string',
'type' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty list<dict>';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$name = $request->getValue('name');
$name_prefix = $request->getValue('namePrefix');
$context = $request->getValue('context');
$language = $request->getValue('language');
$type = $request->getValue('type');
$query = id(new DiffusionSymbolQuery())
->setViewer($request->getUser());
if ($name !== null) {
$query->setName($name);
}
if ($name_prefix !== null) {
$query->setNamePrefix($name_prefix);
}
if ($context !== null) {
$query->setContext($context);
}
if ($language !== null) {
$query->setLanguage($language);
}
if ($type !== null) {
$query->setType($type);
}
$query->needPaths(true);
$query->needArcanistProjects(true);
$query->needRepositories(true);
$results = $query->execute();
$response = array();
foreach ($results as $result) {
$uri = $result->getURI();
if ($uri) {
$uri = PhabricatorEnv::getProductionURI($uri);
}
$response[] = array(
'name' => $result->getSymbolName(),
'context' => $result->getSymbolContext(),
'type' => $result->getSymbolType(),
'language' => $result->getSymbolLanguage(),
'path' => $result->getPath(),
'line' => $result->getLineNumber(),
'uri' => $uri,
);
}
return $response;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionGetCommitsConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionGetCommitsConduitAPIMethod.php
index e6cfd9730d..cdc89807cd 100644
--- a/src/applications/diffusion/conduit/DiffusionGetCommitsConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionGetCommitsConduitAPIMethod.php
@@ -1,297 +1,293 @@
<?php
final class DiffusionGetCommitsConduitAPIMethod
extends DiffusionConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.getcommits';
}
public function getMethodDescription() {
return pht('Retrieve Diffusion commit information.');
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodStatusDescription() {
return pht('Obsoleted by diffusion.querycommits.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'commits' => 'required list<string>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty list<dict<string, wild>>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$results = array();
$commits = $request->getValue('commits');
$commits = array_fill_keys($commits, array());
foreach ($commits as $name => $info) {
$matches = null;
if (!preg_match('/^r([A-Z]+)([0-9a-f]+)\z/', $name, $matches)) {
$results[$name] = array(
'error' => 'ERR-UNPARSEABLE',
);
unset($commits[$name]);
continue;
}
$commits[$name] = array(
'callsign' => $matches[1],
'commitIdentifier' => $matches[2],
);
}
if (!$commits) {
return $results;
}
$callsigns = ipull($commits, 'callsign');
$callsigns = array_unique($callsigns);
$repos = id(new PhabricatorRepositoryQuery())
->setViewer($request->getUser())
->withCallsigns($callsigns)
->execute();
$repos = mpull($repos, null, 'getCallsign');
foreach ($commits as $name => $info) {
$repo = idx($repos, $info['callsign']);
if (!$repo) {
$results[$name] = $info + array(
'error' => 'ERR-UNKNOWN-REPOSITORY',
);
unset($commits[$name]);
continue;
}
$commits[$name] += array(
'repositoryPHID' => $repo->getPHID(),
'repositoryID' => $repo->getID(),
);
}
if (!$commits) {
return $results;
}
// Execute a complicated query to figure out the primary commit information
// for each referenced commit.
$cdata = $this->queryCommitInformation($commits, $repos);
// We've built the queries so that each row also has the identifier we used
// to select it, which might be a git prefix rather than a full identifier.
$ref_map = ipull($cdata, 'commitIdentifier', 'commitRef');
$cobjs = id(new PhabricatorRepositoryCommit())->loadAllFromArray($cdata);
$cobjs = mgroup($cobjs, 'getRepositoryID', 'getCommitIdentifier');
foreach ($commits as $name => $commit) {
// Expand short git names into full identifiers. For SVN this map is just
// the identity.
$full_identifier = idx($ref_map, $commit['commitIdentifier']);
$repo_id = $commit['repositoryID'];
unset($commits[$name]['repositoryID']);
if (empty($full_identifier) ||
empty($cobjs[$commit['repositoryID']][$full_identifier])) {
$results[$name] = $commit + array(
'error' => 'ERR-UNKNOWN-COMMIT',
);
unset($commits[$name]);
continue;
}
$cobj_arr = $cobjs[$commit['repositoryID']][$full_identifier];
$cobj = head($cobj_arr);
$commits[$name] += array(
'epoch' => $cobj->getEpoch(),
'commitPHID' => $cobj->getPHID(),
'commitID' => $cobj->getID(),
);
// Upgrade git short references into full commit identifiers.
$identifier = $cobj->getCommitIdentifier();
$commits[$name]['commitIdentifier'] = $identifier;
$callsign = $commits[$name]['callsign'];
$uri = "/r{$callsign}{$identifier}";
$commits[$name]['uri'] = PhabricatorEnv::getProductionURI($uri);
}
if (!$commits) {
return $results;
}
$commits = $this->addRepositoryCommitDataInformation($commits);
$commits = $this->addDifferentialInformation($commits, $request);
$commits = $this->addManiphestInformation($commits);
foreach ($commits as $name => $commit) {
$results[$name] = $commit;
}
return $results;
}
/**
* Retrieve primary commit information for all referenced commits.
*/
private function queryCommitInformation(array $commits, array $repos) {
assert_instances_of($repos, 'PhabricatorRepository');
$conn_r = id(new PhabricatorRepositoryCommit())->establishConnection('r');
$repos = mpull($repos, null, 'getID');
$groups = array();
foreach ($commits as $name => $commit) {
$groups[$commit['repositoryID']][] = $commit['commitIdentifier'];
}
// NOTE: MySQL goes crazy and does a massive table scan if we build a more
// sensible version of this query. Make sure the query plan is OK if you
// attempt to reduce the craziness here. METANOTE: The addition of prefix
// selection for Git further complicates matters.
$query = array();
$commit_table = id(new PhabricatorRepositoryCommit())->getTableName();
foreach ($groups as $repository_id => $identifiers) {
$vcs = $repos[$repository_id]->getVersionControlSystem();
$is_git = ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT);
if ($is_git) {
foreach ($identifiers as $identifier) {
if (strlen($identifier) < 7) {
// Don't bother with silly stuff like 'rX2', which will select
// 1/16th of all commits. Note that with length 7 we'll still get
// collisions in repositories at the tens-of-thousands-of-commits
// scale.
continue;
}
$query[] = qsprintf(
$conn_r,
'SELECT %T.*, %s commitRef
FROM %T WHERE repositoryID = %d
AND commitIdentifier LIKE %>',
$commit_table,
$identifier,
$commit_table,
$repository_id,
$identifier);
}
} else {
$query[] = qsprintf(
$conn_r,
'SELECT %T.*, commitIdentifier commitRef
FROM %T WHERE repositoryID = %d
AND commitIdentifier IN (%Ls)',
$commit_table,
$commit_table,
$repository_id,
$identifiers);
}
}
return queryfx_all(
$conn_r,
'%Q',
implode(' UNION ALL ', $query));
}
/**
* Enhance the commit list with RepositoryCommitData information.
*/
private function addRepositoryCommitDataInformation(array $commits) {
$commit_ids = ipull($commits, 'commitID');
$data = id(new PhabricatorRepositoryCommitData())->loadAllWhere(
'commitID in (%Ld)',
$commit_ids);
$data = mpull($data, null, 'getCommitID');
foreach ($commits as $name => $commit) {
if (isset($data[$commit['commitID']])) {
$dobj = $data[$commit['commitID']];
$commits[$name] += array(
'commitMessage' => $dobj->getCommitMessage(),
'commitDetails' => $dobj->getCommitDetails(),
);
}
// Remove this information so we don't expose it via the API since
// external services shouldn't be storing internal Commit IDs.
unset($commits[$name]['commitID']);
}
return $commits;
}
/**
* Enhance the commit list with Differential information.
*/
private function addDifferentialInformation(
array $commits,
ConduitAPIRequest $request) {
$commit_phids = ipull($commits, 'commitPHID');
$revisions = id(new DifferentialRevisionQuery())
->setViewer($request->getUser())
->withCommitPHIDs($commit_phids)
->needCommitPHIDs(true)
->execute();
$rev_phid_commit_phids_map = mpull($revisions, 'getCommitPHIDs', 'getPHID');
$revisions = mpull($revisions, null, 'getPHID');
foreach ($rev_phid_commit_phids_map as $rev_phid => $commit_phids) {
foreach ($commits as $name => $commit) {
$commit_phid = $commit['commitPHID'];
if (in_array($commit_phid, $commit_phids)) {
$revision = $revisions[$rev_phid];
$commits[$name] += array(
'differentialRevisionID' => 'D'.$revision->getID(),
'differentialRevisionPHID' => $revision->getPHID(),
);
}
}
}
return $commits;
}
/**
* Enhances the commits list with Maniphest information.
*/
private function addManiphestInformation(array $commits) {
$task_type = DiffusionCommitHasTaskEdgeType::EDGECONST;
$commit_phids = ipull($commits, 'commitPHID');
$edge_query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs($commit_phids)
->withEdgeTypes(array($task_type));
$edges = $edge_query->execute();
foreach ($commits as $name => $commit) {
$task_phids = $edge_query->getDestinationPHIDs(
array($commit['commitPHID']),
array($task_type));
$commits[$name] += array(
'taskPHIDs' => $task_phids,
);
}
return $commits;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionGetLintMessagesConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionGetLintMessagesConduitAPIMethod.php
index ba129557b3..d73213b148 100644
--- a/src/applications/diffusion/conduit/DiffusionGetLintMessagesConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionGetLintMessagesConduitAPIMethod.php
@@ -1,73 +1,69 @@
<?php
final class DiffusionGetLintMessagesConduitAPIMethod
extends DiffusionConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.getlintmessages';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return 'Get lint messages for existing code.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'arcanistProject' => 'required string',
'branch' => 'optional string',
'commit' => 'optional string',
'files' => 'required list<string>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$project = id(new PhabricatorRepositoryArcanistProject())->loadOneWhere(
'name = %s',
$request->getValue('arcanistProject'));
if (!$project || !$project->getRepositoryID()) {
return array();
}
$branch_name = $request->getValue('branch');
if ($branch_name == '') {
$repository = id(new PhabricatorRepositoryQuery())
->setViewer($request->getUser())
->withIDs(array($project->getRepositoryID()))
->executeOne();
$branch_name = $repository->getDefaultArcanistBranch();
}
$branch = id(new PhabricatorRepositoryBranch())->loadOneWhere(
'repositoryID = %d AND name = %s',
$project->getRepositoryID(),
$branch_name);
if (!$branch || !$branch->getLintCommit()) {
return array();
}
$lint_messages = queryfx_all(
$branch->establishConnection('r'),
'SELECT path, line, code FROM %T WHERE branchID = %d AND path IN (%Ls)',
PhabricatorRepository::TABLE_LINTMESSAGE,
$branch->getID(),
$request->getValue('files'));
// TODO: Compare commit identifiers of individual files like in
// DiffusionBrowseFileController::loadLintMessages().
return $lint_messages;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionGetRecentCommitsByPathConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionGetRecentCommitsByPathConduitAPIMethod.php
index 4ef28ddbad..89e40c69ba 100644
--- a/src/applications/diffusion/conduit/DiffusionGetRecentCommitsByPathConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionGetRecentCommitsByPathConduitAPIMethod.php
@@ -1,70 +1,65 @@
<?php
final class DiffusionGetRecentCommitsByPathConduitAPIMethod
extends DiffusionConduitAPIMethod {
const DEFAULT_LIMIT = 10;
public function getAPIMethodName() {
return 'diffusion.getrecentcommitsbypath';
}
public function getMethodDescription() {
return 'Get commit identifiers for recent commits affecting a given path.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'callsign' => 'required string',
'path' => 'required string',
'branch' => 'optional string',
'limit' => 'optional int',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty list<string>';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$drequest = DiffusionRequest::newFromDictionary(
array(
'user' => $request->getUser(),
'callsign' => $request->getValue('callsign'),
'path' => $request->getValue('path'),
'branch' => $request->getValue('branch'),
));
$limit = nonempty(
$request->getValue('limit'),
self::DEFAULT_LIMIT);
$history_result = DiffusionQuery::callConduitWithDiffusionRequest(
$request->getUser(),
$drequest,
'diffusion.historyquery',
array(
'commit' => $drequest->getCommit(),
'path' => $drequest->getPath(),
'offset' => 0,
'limit' => $limit,
'needDirectChanges' => true,
'needChildChanges' => true,
));
$history = DiffusionPathChange::newFromConduit(
$history_result['pathChanges']);
$raw_commit_identifiers = mpull($history, 'getCommitIdentifier');
$result = array();
foreach ($raw_commit_identifiers as $id) {
$result[] = 'r'.$request->getValue('callsign').$id;
}
return $result;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php
index 05c98a5b5b..939a47ab64 100644
--- a/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php
@@ -1,269 +1,269 @@
<?php
final class DiffusionHistoryQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
private $parents = array();
public function getAPIMethodName() {
return 'diffusion.historyquery';
}
public function getMethodDescription() {
return 'Returns history information for a repository at a specific '.
'commit and path.';
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'array';
}
protected function defineCustomParamTypes() {
return array(
'commit' => 'required string',
'path' => 'required string',
'offset' => 'required int',
'limit' => 'required int',
'needDirectChanges' => 'optional bool',
'needChildChanges' => 'optional bool',
);
}
protected function getResult(ConduitAPIRequest $request) {
$path_changes = parent::getResult($request);
return array(
'pathChanges' => mpull($path_changes, 'toDictionary'),
'parents' => $this->parents,
);
}
protected function getGitResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commit_hash = $request->getValue('commit');
$path = $request->getValue('path');
$offset = $request->getValue('offset');
$limit = $request->getValue('limit');
list($stdout) = $repository->execxLocalCommand(
'log '.
'--skip=%d '.
'-n %d '.
'--pretty=format:%s '.
'%s -- %C',
$offset,
$limit,
'%H:%P',
$commit_hash,
// Git omits merge commits if the path is provided, even if it is empty.
(strlen($path) ? csprintf('%s', $path) : ''));
$lines = explode("\n", trim($stdout));
$lines = array_filter($lines);
if (!$lines) {
return array();
}
$hash_list = array();
$parent_map = array();
foreach ($lines as $line) {
list($hash, $parents) = explode(':', $line);
$hash_list[] = $hash;
$parent_map[$hash] = preg_split('/\s+/', $parents);
}
$this->parents = $parent_map;
return DiffusionQuery::loadHistoryForCommitIdentifiers(
$hash_list,
$drequest);
}
protected function getMercurialResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commit_hash = $request->getValue('commit');
$path = $request->getValue('path');
$offset = $request->getValue('offset');
$limit = $request->getValue('limit');
$path = DiffusionPathIDQuery::normalizePath($path);
$path = ltrim($path, '/');
// NOTE: Older versions of Mercurial give different results for these
// commands (see T1268):
//
// $ hg log -- ''
// $ hg log
//
// All versions of Mercurial give different results for these commands
// (merge commits are excluded with the "." version):
//
// $ hg log -- .
// $ hg log
//
// If we don't have a path component in the query, omit it from the command
// entirely to avoid these inconsistencies.
// NOTE: When viewing the history of a file, we don't use "-b", because
// Mercurial stops history at the branchpoint but we're interested in all
// ancestors. When viewing history of a branch, we do use "-b", and thus
// stop history (this is more consistent with the Mercurial worldview of
// branches).
if (strlen($path)) {
$path_arg = csprintf('-- %s', $path);
$branch_arg = '';
} else {
$path_arg = '';
// NOTE: --branch used to be called --only-branch; use -b for
// compatibility.
$branch_arg = csprintf('-b %s', $drequest->getBranch());
}
list($stdout) = $repository->execxLocalCommand(
'log --debug --template %s --limit %d %C --rev %s %C',
'{node};{parents}\\n',
($offset + $limit), // No '--skip' in Mercurial.
$branch_arg,
hgsprintf('reverse(ancestors(%s))', $commit_hash),
$path_arg);
$stdout = PhabricatorRepository::filterMercurialDebugOutput($stdout);
$lines = explode("\n", trim($stdout));
$lines = array_slice($lines, $offset);
$hash_list = array();
$parent_map = array();
$last = null;
foreach (array_reverse($lines) as $line) {
list($hash, $parents) = explode(';', $line);
$parents = trim($parents);
if (!$parents) {
if ($last === null) {
$parent_map[$hash] = array('...');
} else {
$parent_map[$hash] = array($last);
}
} else {
$parents = preg_split('/\s+/', $parents);
foreach ($parents as $parent) {
list($plocal, $phash) = explode(':', $parent);
if (!preg_match('/^0+$/', $phash)) {
$parent_map[$hash][] = $phash;
}
}
// This may happen for the zeroth commit in repository, both hashes
// are "000000000...".
if (empty($parent_map[$hash])) {
$parent_map[$hash] = array('...');
}
}
// The rendering code expects the first commit to be "mainline", like
// Git. Flip the order so it does the right thing.
$parent_map[$hash] = array_reverse($parent_map[$hash]);
$hash_list[] = $hash;
$last = $hash;
}
$hash_list = array_reverse($hash_list);
$this->parents = $parent_map;
return DiffusionQuery::loadHistoryForCommitIdentifiers(
$hash_list,
$drequest);
}
protected function getSVNResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commit = $request->getValue('commit');
$path = $request->getValue('path');
$offset = $request->getValue('offset');
$limit = $request->getValue('limit');
$need_direct_changes = $request->getValue('needDirectChanges');
$need_child_changes = $request->getValue('needChildChanges');
$conn_r = $repository->establishConnection('r');
$paths = queryfx_all(
$conn_r,
'SELECT id, path FROM %T WHERE pathHash IN (%Ls)',
PhabricatorRepository::TABLE_PATH,
array(md5('/'.trim($path, '/'))));
$paths = ipull($paths, 'id', 'path');
$path_id = idx($paths, '/'.trim($path, '/'));
if (!$path_id) {
return array();
}
$filter_query = '';
if ($need_direct_changes) {
if ($need_child_changes) {
$type = DifferentialChangeType::TYPE_CHILD;
$filter_query = 'AND (isDirect = 1 OR changeType = '.$type.')';
} else {
$filter_query = 'AND (isDirect = 1)';
}
}
$history_data = queryfx_all(
$conn_r,
'SELECT * FROM %T WHERE repositoryID = %d AND pathID = %d
AND commitSequence <= %d
%Q
ORDER BY commitSequence DESC
LIMIT %d, %d',
PhabricatorRepository::TABLE_PATHCHANGE,
$repository->getID(),
$path_id,
$commit ? $commit : 0x7FFFFFFF,
$filter_query,
$offset,
$limit);
$commits = array();
$commit_data = array();
$commit_ids = ipull($history_data, 'commitID');
if ($commit_ids) {
$commits = id(new PhabricatorRepositoryCommit())->loadAllWhere(
'id IN (%Ld)',
$commit_ids);
if ($commits) {
$commit_data = id(new PhabricatorRepositoryCommitData())->loadAllWhere(
'commitID in (%Ld)',
$commit_ids);
$commit_data = mpull($commit_data, null, 'getCommitID');
}
}
$history = array();
foreach ($history_data as $row) {
$item = new DiffusionPathChange();
$commit = idx($commits, $row['commitID']);
if ($commit) {
$item->setCommit($commit);
$item->setCommitIdentifier($commit->getCommitIdentifier());
$data = idx($commit_data, $commit->getID());
if ($data) {
$item->setCommitData($data);
}
}
$item->setChangeType($row['changeType']);
$item->setFileType($row['fileType']);
$history[] = $item;
}
return $history;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionLastModifiedQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionLastModifiedQueryConduitAPIMethod.php
index c5a256a307..30b436cfff 100644
--- a/src/applications/diffusion/conduit/DiffusionLastModifiedQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionLastModifiedQueryConduitAPIMethod.php
@@ -1,156 +1,156 @@
<?php
final class DiffusionLastModifiedQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.lastmodifiedquery';
}
public function getMethodDescription() {
return pht('Get the commits at which paths were last modified.');
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'map<string, string>';
}
protected function defineCustomParamTypes() {
return array(
'paths' => 'required map<string, string>',
);
}
protected function getGitResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$paths = $request->getValue('paths');
$results = $this->loadCommitsFromCache($paths);
foreach ($paths as $path => $commit) {
if (array_key_exists($path, $results)) {
continue;
}
list($hash) = $repository->execxLocalCommand(
'log -n1 --format=%%H %s -- %s',
$commit,
$path);
$results[$path] = trim($hash);
}
return $results;
}
protected function getSVNResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$results = array();
foreach ($request->getValue('paths') as $path => $commit) {
$history_result = DiffusionQuery::callConduitWithDiffusionRequest(
$request->getUser(),
$drequest,
'diffusion.historyquery',
array(
'commit' => $commit,
'path' => $path,
'limit' => 1,
'offset' => 0,
'needDirectChanges' => true,
'needChildChanges' => true,
));
$history_array = DiffusionPathChange::newFromConduit(
$history_result['pathChanges']);
if ($history_array) {
$results[$path] = head($history_array)
->getCommit()
->getCommitIdentifier();
}
}
return $results;
}
protected function getMercurialResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$paths = $request->getValue('paths');
$results = $this->loadCommitsFromCache($paths);
foreach ($paths as $path => $commit) {
if (array_key_exists($path, $results)) {
continue;
}
list($hash) = $repository->execxLocalCommand(
'log --template %s --limit 1 --removed --rev %s -- %s',
'{node}',
hgsprintf('reverse(ancestors(%s))', $commit),
nonempty(ltrim($path, '/'), '.'));
$results[$path] = trim($hash);
}
return $results;
}
private function loadCommitsFromCache(array $map) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$path_map = id(new DiffusionPathIDQuery(array_keys($map)))
->loadPathIDs();
$commit_query = id(new DiffusionCommitQuery())
->setViewer($drequest->getUser())
->withRepository($repository)
->withIdentifiers(array_values($map));
$commit_query->execute();
$commit_map = $commit_query->getIdentifierMap();
$commit_map = mpull($commit_map, 'getID');
$graph_cache = new PhabricatorRepositoryGraphCache();
$results = array();
foreach ($map as $path => $commit) {
$path_id = idx($path_map, $path);
if (!$path_id) {
continue;
}
$commit_id = idx($commit_map, $commit);
if (!$commit_id) {
continue;
}
$cache_result = $graph_cache->loadLastModifiedCommitID(
$commit_id,
$path_id);
if ($cache_result !== false) {
$results[$path] = $cache_result;
}
}
if ($results) {
$commits = id(new DiffusionCommitQuery())
->setViewer($drequest->getUser())
->withRepository($repository)
->withIDs($results)
->execute();
foreach ($results as $path => $id) {
$commit = idx($commits, $id);
if ($commit) {
$results[$path] = $commit->getCommitIdentifier();
} else {
unset($results[$path]);
}
}
}
return $results;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php
index 01a60406e8..49dd5dc117 100644
--- a/src/applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php
@@ -1,59 +1,55 @@
<?php
final class DiffusionLookSoonConduitAPIMethod
extends DiffusionConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.looksoon';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return pht(
'Advises Phabricator to look for new commits in a repository as soon '.
'as possible. This advice is most useful if you have just pushed new '.
'commits to that repository.');
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'callsigns' => 'required list<string>',
'urgency' => 'optional string',
);
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
// NOTE: The "urgency" parameter does nothing, it is just a hilarious joke
// which exemplifies the boundless clever wit of this project.
$callsigns = $request->getValue('callsigns');
if (!$callsigns) {
return null;
}
$repositories = id(new PhabricatorRepositoryQuery())
->setViewer($request->getUser())
->withCallsigns($callsigns)
->execute();
foreach ($repositories as $repository) {
$repository->writeStatusMessage(
PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE,
PhabricatorRepositoryStatusMessage::CODE_OKAY);
}
return null;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionMergedCommitsQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionMergedCommitsQueryConduitAPIMethod.php
index 867da02331..71c8014de5 100644
--- a/src/applications/diffusion/conduit/DiffusionMergedCommitsQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionMergedCommitsQueryConduitAPIMethod.php
@@ -1,110 +1,110 @@
<?php
final class DiffusionMergedCommitsQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.mergedcommitsquery';
}
public function getMethodDescription() {
return
'Merged commit information for a specific commit in a repository.';
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'array';
}
protected function defineCustomParamTypes() {
return array(
'commit' => 'required string',
'limit' => 'optional int',
);
}
private function getLimit(ConduitAPIRequest $request) {
return $request->getValue('limit', PHP_INT_MAX);
}
protected function getGitResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commit = $request->getValue('commit');
$limit = $this->getLimit($request);
list($parents) = $repository->execxLocalCommand(
'log -n 1 --format=%s %s',
'%P',
$commit);
$parents = preg_split('/\s+/', trim($parents));
if (count($parents) < 2) {
// This is not a merge commit, so it doesn't merge anything.
return array();
}
// Get all of the commits which are not reachable from the first parent.
// These are the commits this change merges.
$first_parent = head($parents);
list($logs) = $repository->execxLocalCommand(
'log -n %d --format=%s %s %s --',
// NOTE: "+ 1" accounts for the merge commit itself.
$limit + 1,
'%H',
$commit,
'^'.$first_parent);
$hashes = explode("\n", trim($logs));
// Remove the merge commit.
$hashes = array_diff($hashes, array($commit));
$history = DiffusionQuery::loadHistoryForCommitIdentifiers(
$hashes,
$drequest);
return mpull($history, 'toDictionary');
}
protected function getMercurialResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commit = $request->getValue('commit');
$limit = $this->getLimit($request);
list($parents) = $repository->execxLocalCommand(
'parents --template=%s --rev %s',
'{node}\\n',
$commit);
$parents = explode("\n", trim($parents));
if (count($parents) < 2) {
// Not a merge commit.
return array();
}
// NOTE: In Git, the first parent is the "mainline". In Mercurial, the
// second parent is the "mainline" (the way 'git merge' and 'hg merge'
// work is also reversed).
$last_parent = last($parents);
list($logs) = $repository->execxLocalCommand(
'log --template=%s --follow --limit %d --rev %s:0 --prune %s --',
'{node}\\n',
$limit + 1,
$commit,
$last_parent);
$hashes = explode("\n", trim($logs));
// Remove the merge commit.
$hashes = array_diff($hashes, array($commit));
$history = DiffusionQuery::loadHistoryForCommitIdentifiers(
$hashes,
$drequest);
return mpull($history, 'toDictionary');
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionQueryCommitsConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionQueryCommitsConduitAPIMethod.php
index 490ce03985..c2e1a3de50 100644
--- a/src/applications/diffusion/conduit/DiffusionQueryCommitsConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionQueryCommitsConduitAPIMethod.php
@@ -1,142 +1,138 @@
<?php
final class DiffusionQueryCommitsConduitAPIMethod
extends DiffusionConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.querycommits';
}
public function getMethodDescription() {
return pht('Retrieve information about commits.');
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'map<string, dict>';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<int>',
'phids' => 'optional list<phid>',
'names' => 'optional list<string>',
'repositoryPHID' => 'optional phid',
'needMessages' => 'optional bool',
'bypassCache' => 'optional bool',
) + $this->getPagerParamTypes();
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$need_messages = $request->getValue('needMessages');
$bypass_cache = $request->getValue('bypassCache');
$query = id(new DiffusionCommitQuery())
->setViewer($request->getUser())
->needCommitData(true);
$repository_phid = $request->getValue('repositoryPHID');
if ($repository_phid) {
$repository = id(new PhabricatorRepositoryQuery())
->setViewer($request->getUser())
->withPHIDs(array($repository_phid))
->executeOne();
if ($repository) {
$query->withRepository($repository);
}
}
$names = $request->getValue('names');
if ($names) {
$query->withIdentifiers($names);
}
$ids = $request->getValue('ids');
if ($ids) {
$query->withIDs($ids);
}
$phids = $request->getValue('phids');
if ($phids) {
$query->withPHIDs($phids);
}
$pager = $this->newPager($request);
$commits = $query->executeWithCursorPager($pager);
$map = $query->getIdentifierMap();
$map = mpull($map, 'getPHID');
$data = array();
foreach ($commits as $commit) {
$commit_data = $commit->getCommitData();
$callsign = $commit->getRepository()->getCallsign();
$identifier = $commit->getCommitIdentifier();
$uri = '/r'.$callsign.$identifier;
$uri = PhabricatorEnv::getProductionURI($uri);
$dict = array(
'id' => $commit->getID(),
'phid' => $commit->getPHID(),
'repositoryPHID' => $commit->getRepository()->getPHID(),
'identifier' => $identifier,
'epoch' => $commit->getEpoch(),
'uri' => $uri,
'isImporting' => !$commit->isImported(),
'summary' => $commit->getSummary(),
'authorPHID' => $commit->getAuthorPHID(),
'committerPHID' => $commit_data->getCommitDetail('committerPHID'),
'author' => $commit_data->getAuthorName(),
'authorName' => $commit_data->getCommitDetail('authorName'),
'authorEmail' => $commit_data->getCommitDetail('authorEmail'),
'committer' => $commit_data->getCommitDetail('committer'),
'committerName' => $commit_data->getCommitDetail('committerName'),
'committerEmail' => $commit_data->getCommitDetail('committerEmail'),
'hashes' => array(),
);
if ($bypass_cache) {
$lowlevel_commitref = id(new DiffusionLowLevelCommitQuery())
->setRepository($commit->getRepository())
->withIdentifier($commit->getCommitIdentifier())
->execute();
$dict['author'] = $lowlevel_commitref->getAuthor();
$dict['authorName'] = $lowlevel_commitref->getAuthorName();
$dict['authorEmail'] = $lowlevel_commitref->getAuthorEmail();
$dict['committer'] = $lowlevel_commitref->getCommitter();
$dict['committerName'] = $lowlevel_commitref->getCommitterName();
$dict['committerEmail'] = $lowlevel_commitref->getCommitterEmail();
if ($need_messages) {
$dict['message'] = $lowlevel_commitref->getMessage();
}
foreach ($lowlevel_commitref->getHashes() as $hash) {
$dict['hashes'][] = array(
'type' => $hash->getHashType(),
'value' => $hash->getHashValue(),
);
}
}
if ($need_messages && !$bypass_cache) {
$dict['message'] = $commit_data->getCommitMessage();
}
$data[$commit->getPHID()] = $dict;
}
$result = array(
'data' => $data,
'identifierMap' => nonempty($map, (object)array()),
);
return $this->addPagerResults($result, $pager);
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionQueryConduitAPIMethod.php
index dd58cd09ab..22c4adad45 100644
--- a/src/applications/diffusion/conduit/DiffusionQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionQueryConduitAPIMethod.php
@@ -1,159 +1,159 @@
<?php
abstract class DiffusionQueryConduitAPIMethod
extends DiffusionConduitAPIMethod {
public function shouldAllowPublic() {
return true;
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodStatusDescription() {
return pht(
'See T2784 - migrating diffusion working copy calls to conduit methods. '.
'Until that task is completed (and possibly after) these methods are '.
'unstable.');
}
private $diffusionRequest;
private $repository;
protected function setDiffusionRequest(DiffusionRequest $request) {
$this->diffusionRequest = $request;
return $this;
}
protected function getDiffusionRequest() {
return $this->diffusionRequest;
}
protected function getRepository(ConduitAPIRequest $request) {
return $this->getDiffusionRequest()->getRepository();
}
- final public function defineErrorTypes() {
+ final protected function defineErrorTypes() {
return $this->defineCustomErrorTypes() +
array(
'ERR-UNKNOWN-REPOSITORY' =>
pht('There is no repository with that callsign.'),
'ERR-UNKNOWN-VCS-TYPE' =>
pht('Unknown repository VCS type.'),
'ERR-UNSUPPORTED-VCS' =>
pht('VCS is not supported for this method.'),
);
}
/**
* Subclasses should override this to specify custom error types.
*/
protected function defineCustomErrorTypes() {
return array();
}
- final public function defineParamTypes() {
+ final protected function defineParamTypes() {
return $this->defineCustomParamTypes() +
array(
'callsign' => 'required string',
'branch' => 'optional string',
);
}
/**
* Subclasses should override this to specify custom param types.
*/
protected function defineCustomParamTypes() {
return array();
}
/**
* Subclasses should override these methods with the proper result for the
* pertinent version control system, e.g. getGitResult for Git.
*
* If the result is not supported for that VCS, do not implement it. e.g.
* Subversion (SVN) does not support branches.
*/
protected function getGitResult(ConduitAPIRequest $request) {
throw new ConduitException('ERR-UNSUPPORTED-VCS');
}
protected function getSVNResult(ConduitAPIRequest $request) {
throw new ConduitException('ERR-UNSUPPORTED-VCS');
}
protected function getMercurialResult(ConduitAPIRequest $request) {
throw new ConduitException('ERR-UNSUPPORTED-VCS');
}
/**
* This method is final because most queries will need to construct a
* @{class:DiffusionRequest} and use it. Consolidating this codepath and
* enforcing @{method:getDiffusionRequest} works when we need it is good.
*
* @{method:getResult} should be overridden by subclasses as necessary, e.g.
* there is a common operation across all version control systems that
* should occur after @{method:getResult}, like formatting a timestamp.
*/
final protected function execute(ConduitAPIRequest $request) {
$drequest = DiffusionRequest::newFromDictionary(
array(
'user' => $request->getUser(),
'callsign' => $request->getValue('callsign'),
'branch' => $request->getValue('branch'),
'path' => $request->getValue('path'),
'commit' => $request->getValue('commit'),
));
// Figure out whether we're going to handle this request on this device,
// or proxy it to another node in the cluster.
// If this is a cluster request and we need to proxy, we'll explode here
// to prevent infinite recursion.
$is_cluster_request = $request->getIsClusterRequest();
$repository = $drequest->getRepository();
$client = $repository->newConduitClient(
$request->getUser(),
$is_cluster_request);
if ($client) {
// We're proxying, so just make an intracluster call.
return $client->callMethodSynchronous(
$this->getAPIMethodName(),
$request->getAllParameters());
} else {
// We pass this flag on to prevent proxying of any other Conduit calls
// which we need to make in order to respond to this one. Although we
// could safely proxy them, we take a big performance hit in the common
// case, and doing more proxying wouldn't exercise any additional code so
// we wouldn't gain a testability/predictability benefit.
$drequest->setIsClusterRequest($is_cluster_request);
$this->setDiffusionRequest($drequest);
return $this->getResult($request);
}
}
protected function getResult(ConduitAPIRequest $request) {
$repository = $this->getRepository($request);
$result = null;
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$result = $this->getGitResult($request);
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$result = $this->getMercurialResult($request);
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$result = $this->getSVNResult($request);
break;
default:
throw new ConduitException('ERR-UNKNOWN-VCS-TYPE');
break;
}
return $result;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionQueryPathsConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionQueryPathsConduitAPIMethod.php
index c25d71aeb4..6061825444 100644
--- a/src/applications/diffusion/conduit/DiffusionQueryPathsConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionQueryPathsConduitAPIMethod.php
@@ -1,105 +1,105 @@
<?php
final class DiffusionQueryPathsConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.querypaths';
}
public function getMethodDescription() {
return pht('Filename search on a repository.');
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<string>';
}
protected function defineCustomParamTypes() {
return array(
'path' => 'required string',
'commit' => 'required string',
'pattern' => 'optional string',
'limit' => 'optional int',
'offset' => 'optional int',
);
}
protected function getResult(ConduitAPIRequest $request) {
$results = parent::getResult($request);
$offset = $request->getValue('offset');
return array_slice($results, $offset);
}
protected function getGitResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$path = $drequest->getPath();
$commit = $request->getValue('commit');
$repository = $drequest->getRepository();
// http://comments.gmane.org/gmane.comp.version-control.git/197735
$future = $repository->getLocalCommandFuture(
'ls-tree --name-only -r -z %s -- %s',
$commit,
$path);
$lines = id(new LinesOfALargeExecFuture($future))->setDelimiter("\0");
return $this->filterResults($lines, $request);
}
protected function getMercurialResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$path = $request->getValue('path');
$commit = $request->getValue('commit');
$entire_manifest = id(new DiffusionLowLevelMercurialPathsQuery())
->setRepository($repository)
->withCommit($commit)
->withPath($path)
->execute();
$match_against = trim($path, '/');
$match_len = strlen($match_against);
$lines = array();
foreach ($entire_manifest as $path) {
if (strlen($path) && !strncmp($path, $match_against, $match_len)) {
$lines[] = $path;
}
}
return $this->filterResults($lines, $request);
}
protected function filterResults($lines, ConduitAPIRequest $request) {
$pattern = $request->getValue('pattern');
$limit = (int)$request->getValue('limit');
$offset = (int)$request->getValue('offset');
if (strlen($pattern)) {
$pattern = '/'.preg_quote($pattern, '/').'/';
}
$results = array();
$count = 0;
foreach ($lines as $line) {
if (!$pattern || preg_match($pattern, $line)) {
if ($count >= $offset) {
$results[] = $line;
}
$count++;
if ($limit && ($count >= ($offset + $limit))) {
break;
}
}
}
return $results;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionRawDiffQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionRawDiffQueryConduitAPIMethod.php
index 0cc3d93b3a..a7e217d2aa 100644
--- a/src/applications/diffusion/conduit/DiffusionRawDiffQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionRawDiffQueryConduitAPIMethod.php
@@ -1,59 +1,59 @@
<?php
final class DiffusionRawDiffQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.rawdiffquery';
}
public function getMethodDescription() {
return
'Get raw diff information from a repository for a specific commit at an '.
'(optional) path.';
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'string';
}
protected function defineCustomParamTypes() {
return array(
'commit' => 'required string',
'path' => 'optional string',
'timeout' => 'optional int',
'byteLimit' => 'optional int',
'linesOfContext' => 'optional int',
'againstCommit' => 'optional string',
);
}
protected function getResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$raw_query = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest);
$timeout = $request->getValue('timeout');
if ($timeout !== null) {
$raw_query->setTimeout($timeout);
}
$lines_of_context = $request->getValue('linesOfContext');
if ($lines_of_context !== null) {
$raw_query->setLinesOfContext($lines_of_context);
}
$against_commit = $request->getValue('againstCommit');
if ($against_commit !== null) {
$raw_query->setAgainstCommit($against_commit);
}
$byte_limit = $request->getValue('byteLimit');
if ($byte_limit !== null) {
$raw_query->setByteLimit($byte_limit);
}
return $raw_query->loadRawDiff();
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionRefsQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionRefsQueryConduitAPIMethod.php
index 38a44de6b5..2d025e9d4a 100644
--- a/src/applications/diffusion/conduit/DiffusionRefsQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionRefsQueryConduitAPIMethod.php
@@ -1,59 +1,59 @@
<?php
final class DiffusionRefsQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.refsquery';
}
public function getMethodDescription() {
return
'Query a git repository for ref information at a specific commit.';
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'array';
}
protected function defineCustomParamTypes() {
return array(
'commit' => 'required string',
);
}
protected function getGitResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commit = $request->getValue('commit');
list($stdout) = $repository->execxLocalCommand(
'log --format=%s -n 1 %s --',
'%d',
$commit);
// %d, gives a weird output format
// similar to (remote/one, remote/two, remote/three)
$refs = trim($stdout, "() \n");
if (!$refs) {
return array();
}
$refs = explode(',', $refs);
$refs = array_map('trim', $refs);
$ref_links = array();
foreach ($refs as $ref) {
$ref_links[] = array(
'ref' => $ref,
'href' => $drequest->generateURI(
array(
'action' => 'browse',
'branch' => $ref,
)),
);
}
return $ref_links;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionResolveRefsConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionResolveRefsConduitAPIMethod.php
index 36a2256bdb..0cfb2bf565 100644
--- a/src/applications/diffusion/conduit/DiffusionResolveRefsConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionResolveRefsConduitAPIMethod.php
@@ -1,33 +1,33 @@
<?php
final class DiffusionResolveRefsConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.resolverefs';
}
public function getMethodDescription() {
return pht('Resolve references into stable, canonical identifiers.');
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict<string, list<dict<string, wild>>>';
}
protected function defineCustomParamTypes() {
return array(
'refs' => 'required list<string>',
);
}
protected function getResult(ConduitAPIRequest $request) {
$refs = $request->getValue('refs');
return id(new DiffusionLowLevelResolveRefsQuery())
->setRepository($this->getDiffusionRequest()->getRepository())
->withRefs($refs)
->execute();
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionSearchQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionSearchQueryConduitAPIMethod.php
index db73f6b79d..5cf91a10f0 100644
--- a/src/applications/diffusion/conduit/DiffusionSearchQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionSearchQueryConduitAPIMethod.php
@@ -1,118 +1,118 @@
<?php
final class DiffusionSearchQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.searchquery';
}
public function getMethodDescription() {
return 'Search (grep) a repository at a specific path and commit.';
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'array';
}
protected function defineCustomParamTypes() {
return array(
'path' => 'required string',
'commit' => 'optional string',
'grep' => 'required string',
'limit' => 'optional int',
'offset' => 'optional int',
);
}
protected function defineCustomErrorTypes() {
return array(
'ERR-GREP-COMMAND' => 'Grep command failed.',
);
}
protected function getResult(ConduitAPIRequest $request) {
try {
$results = parent::getResult($request);
} catch (CommandException $ex) {
throw id(new ConduitException('ERR-GREP-COMMAND'))
->setErrorDescription($ex->getStderr());
}
$offset = $request->getValue('offset');
$results = array_slice($results, $offset);
return $results;
}
protected function getGitResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$path = $drequest->getPath();
$grep = $request->getValue('grep');
$repository = $drequest->getRepository();
$limit = $request->getValue('limit');
$offset = $request->getValue('offset');
$results = array();
$future = $repository->getLocalCommandFuture(
// NOTE: --perl-regexp is available only with libpcre compiled in.
'grep --extended-regexp --null -n --no-color -e %s %s -- %s',
$grep,
$drequest->getStableCommit(),
$path);
$binary_pattern = '/Binary file [^:]*:(.+) matches/';
$lines = new LinesOfALargeExecFuture($future);
foreach ($lines as $line) {
$result = null;
if (preg_match('/[^:]*:(.+)\0(.+)\0(.*)/', $line, $result)) {
$results[] = array_slice($result, 1);
} else if (preg_match($binary_pattern, $line, $result)) {
list(, $path) = $result;
$results[] = array($path, null, pht('Binary file'));
} else {
$results[] = array(null, null, $line);
}
if (count($results) >= $offset + $limit) {
break;
}
}
unset($lines);
return $results;
}
protected function getMercurialResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$path = $drequest->getPath();
$grep = $request->getValue('grep');
$repository = $drequest->getRepository();
$limit = $request->getValue('limit');
$offset = $request->getValue('offset');
$results = array();
$future = $repository->getLocalCommandFuture(
'grep --rev %s --print0 --line-number %s %s',
hgsprintf('ancestors(%s)', $drequest->getStableCommit()),
$grep,
$path);
$lines = id(new LinesOfALargeExecFuture($future))->setDelimiter("\0");
$parts = array();
foreach ($lines as $line) {
$parts[] = $line;
if (count($parts) == 4) {
list($path, $char_offset, $line, $string) = $parts;
$results[] = array($path, $line, $string);
if (count($results) >= $offset + $limit) {
break;
}
$parts = array();
}
}
unset($lines);
return $results;
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionTagsQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionTagsQueryConduitAPIMethod.php
index 1ece4dd85b..ddf3a2152b 100644
--- a/src/applications/diffusion/conduit/DiffusionTagsQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionTagsQueryConduitAPIMethod.php
@@ -1,168 +1,168 @@
<?php
final class DiffusionTagsQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.tagsquery';
}
public function getMethodDescription() {
return pht('Retrieve information about tags in a repository.');
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'array';
}
protected function defineCustomParamTypes() {
return array(
'names' => 'optional list<string>',
'commit' => 'optional string',
'needMessages' => 'optional bool',
'offset' => 'optional int',
'limit' => 'optional int',
);
}
protected function getGitResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commit = $drequest->getSymbolicCommit();
$commit_filter = null;
if ($commit) {
$commit_filter = $this->loadTagNamesForCommit($commit);
}
$name_filter = $request->getValue('names', null);
$all_tags = $this->loadGitTagList();
$all_tags = mpull($all_tags, null, 'getName');
if ($name_filter !== null) {
$all_tags = array_intersect_key($all_tags, array_fuse($name_filter));
}
if ($commit_filter !== null) {
$all_tags = array_intersect_key($all_tags, $commit_filter);
}
$tags = array_values($all_tags);
$offset = $request->getValue('offset');
$limit = $request->getValue('limit');
if ($offset) {
$tags = array_slice($tags, $offset);
}
if ($limit) {
$tags = array_slice($tags, 0, $limit);
}
if ($request->getValue('needMessages')) {
$this->loadMessagesForTags($all_tags);
}
return mpull($tags, 'toDictionary');
}
private function loadGitTagList() {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$refs = id(new DiffusionLowLevelGitRefQuery())
->setRepository($repository)
->withIsTag(true)
->execute();
$tags = array();
foreach ($refs as $ref) {
$fields = $ref->getRawFields();
$tag = id(new DiffusionRepositoryTag())
->setAuthor($fields['author'])
->setEpoch($fields['epoch'])
->setCommitIdentifier($ref->getCommitIdentifier())
->setName($ref->getShortName())
->setDescription($fields['subject'])
->setType('git/'.$fields['objecttype']);
$tags[] = $tag;
}
return $tags;
}
private function loadTagNamesForCommit($commit) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
list($err, $stdout) = $repository->execLocalCommand(
'tag -l --contains %s',
$commit);
if ($err) {
// Git exits with an error code if the commit is bogus.
return array();
}
$stdout = rtrim($stdout, "\n");
if (!strlen($stdout)) {
return array();
}
$tag_names = explode("\n", $stdout);
$tag_names = array_fill_keys($tag_names, true);
return $tag_names;
}
private function loadMessagesForTags(array $tags) {
assert_instances_of($tags, 'DiffusionRepositoryTag');
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$futures = array();
foreach ($tags as $key => $tag) {
$futures[$key] = $repository->getLocalCommandFuture(
'cat-file tag %s',
$tag->getName());
}
id(new FutureIterator($futures))
->resolveAll();
foreach ($tags as $key => $tag) {
$future = $futures[$key];
list($err, $stdout) = $future->resolve();
$message = null;
if ($err) {
// Not all tags are actually "tag" objects: a "tag" object is only
// created if you provide a message or sign the tag. Tags created with
// `git tag x [commit]` are "lightweight tags" and `git cat-file tag`
// will fail on them. This is fine: they don't have messages.
} else {
$parts = explode("\n\n", $stdout, 2);
if (count($parts) == 2) {
$message = last($parts);
}
}
$tag->attachMessage($message);
}
return $tags;
}
protected function getMercurialResult(ConduitAPIRequest $request) {
// For now, we don't support Mercurial tags via API.
return array();
}
protected function getSVNResult(ConduitAPIRequest $request) {
// Subversion has no meaningful concept of tags.
return array();
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionUpdateCoverageConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionUpdateCoverageConduitAPIMethod.php
index bcadbd9f00..f356da3a10 100644
--- a/src/applications/diffusion/conduit/DiffusionUpdateCoverageConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionUpdateCoverageConduitAPIMethod.php
@@ -1,100 +1,96 @@
<?php
final class DiffusionUpdateCoverageConduitAPIMethod
extends DiffusionConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.updatecoverage';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return pht('Publish coverage information for a repository.');
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'repositoryPHID' => 'required phid',
'branch' => 'required string',
'commit' => 'required string',
'coverage' => 'required map<string, string>',
);
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$repository_phid = $request->getValue('repositoryPHID');
$repository = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->withPHIDs(array($repository_phid))
->executeOne();
if (!$repository) {
throw new Exception(
pht('No repository exists with PHID "%s".', $repository_phid));
}
$commit_name = $request->getValue('commit');
$commit = id(new DiffusionCommitQuery())
->setViewer($viewer)
->withRepository($repository)
->withIdentifiers(array($commit_name))
->executeOne();
if (!$commit) {
throw new Exception(
pht('No commit exists with identifier "%s".', $commit_name));
}
$branch = PhabricatorRepositoryBranch::loadOrCreateBranch(
$repository->getID(),
$request->getValue('branch'));
$coverage = $request->getValue('coverage');
$path_map = id(new DiffusionPathIDQuery(array_keys($coverage)))
->loadPathIDs();
$conn = $repository->establishConnection('w');
$sql = array();
foreach ($coverage as $path => $coverage_info) {
$sql[] = qsprintf(
$conn,
'(%d, %d, %d, %s)',
$branch->getID(),
$path_map[$path],
$commit->getID(),
$coverage_info);
}
$table_name = 'repository_coverage';
$conn->openTransaction();
queryfx(
$conn,
'DELETE FROM %T WHERE branchID = %d',
$table_name,
$branch->getID());
foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) {
queryfx(
$conn,
'INSERT INTO %T (branchID, pathID, commitID, coverage) VALUES %Q',
$table_name,
$chunk);
}
$conn->saveTransaction();
}
}
diff --git a/src/applications/diffusion/query/DiffusionQuery.php b/src/applications/diffusion/query/DiffusionQuery.php
index 5a1755084f..24f58583bf 100644
--- a/src/applications/diffusion/query/DiffusionQuery.php
+++ b/src/applications/diffusion/query/DiffusionQuery.php
@@ -1,217 +1,217 @@
<?php
abstract class DiffusionQuery extends PhabricatorQuery {
private $request;
final protected function __construct() {
// <protected>
}
protected static function newQueryObject(
$base_class,
DiffusionRequest $request) {
$repository = $request->getRepository();
$obj = self::initQueryObject($base_class, $repository);
$obj->request = $request;
return $obj;
}
final protected static function initQueryObject(
$base_class,
PhabricatorRepository $repository) {
$map = array(
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => 'Git',
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => 'Mercurial',
PhabricatorRepositoryType::REPOSITORY_TYPE_SVN => 'Svn',
);
$name = idx($map, $repository->getVersionControlSystem());
if (!$name) {
throw new Exception('Unsupported VCS!');
}
$class = str_replace('Diffusion', 'Diffusion'.$name, $base_class);
$obj = new $class();
return $obj;
}
final protected function getRequest() {
return $this->request;
}
final public static function callConduitWithDiffusionRequest(
PhabricatorUser $user,
DiffusionRequest $drequest,
$method,
array $params = array()) {
$repository = $drequest->getRepository();
$core_params = array(
'callsign' => $repository->getCallsign(),
);
if ($drequest->getBranch() !== null) {
$core_params['branch'] = $drequest->getBranch();
}
// If the method we're calling doesn't actually take some of the implicit
// parameters we derive from the DiffusionRequest, omit them.
$method_object = ConduitAPIMethod::getConduitMethod($method);
- $method_params = $method_object->defineParamTypes();
+ $method_params = $method_object->getParamTypes();
foreach ($core_params as $key => $value) {
if (empty($method_params[$key])) {
unset($core_params[$key]);
}
}
$params = $params + $core_params;
$client = $repository->newConduitClient(
$user,
$drequest->getIsClusterRequest());
if (!$client) {
return id(new ConduitCall($method, $params))
->setUser($user)
->execute();
} else {
return $client->callMethodSynchronous($method, $params);
}
}
public function execute() {
return $this->executeQuery();
}
abstract protected function executeQuery();
/* -( Query Utilities )---------------------------------------------------- */
final public static function loadCommitsByIdentifiers(
array $identifiers,
DiffusionRequest $drequest) {
if (!$identifiers) {
return array();
}
$commits = array();
$commit_data = array();
$repository = $drequest->getRepository();
$commits = id(new PhabricatorRepositoryCommit())->loadAllWhere(
'repositoryID = %d AND commitIdentifier IN (%Ls)',
$repository->getID(),
$identifiers);
$commits = mpull($commits, null, 'getCommitIdentifier');
// Build empty commit objects for every commit, so we can show unparsed
// commits in history views (as "Importing") instead of not showing them.
// This makes the process of importing and parsing commits clearer to the
// user.
$commit_list = array();
foreach ($identifiers as $identifier) {
$commit_obj = idx($commits, $identifier);
if (!$commit_obj) {
$commit_obj = new PhabricatorRepositoryCommit();
$commit_obj->setRepositoryID($repository->getID());
$commit_obj->setCommitIdentifier($identifier);
$commit_obj->makeEphemeral();
}
$commit_list[$identifier] = $commit_obj;
}
$commits = $commit_list;
$commit_ids = array_filter(mpull($commits, 'getID'));
if ($commit_ids) {
$commit_data = id(new PhabricatorRepositoryCommitData())->loadAllWhere(
'commitID in (%Ld)',
$commit_ids);
$commit_data = mpull($commit_data, null, 'getCommitID');
}
foreach ($commits as $commit) {
if (!$commit->getID()) {
continue;
}
if (idx($commit_data, $commit->getID())) {
$commit->attachCommitData($commit_data[$commit->getID()]);
}
}
return $commits;
}
final public static function loadHistoryForCommitIdentifiers(
array $identifiers,
DiffusionRequest $drequest) {
if (!$identifiers) {
return array();
}
$repository = $drequest->getRepository();
$commits = self::loadCommitsByIdentifiers($identifiers, $drequest);
if (!$commits) {
return array();
}
$path = $drequest->getPath();
$conn_r = $repository->establishConnection('r');
$path_normal = DiffusionPathIDQuery::normalizePath($path);
$paths = queryfx_all(
$conn_r,
'SELECT id, path FROM %T WHERE pathHash IN (%Ls)',
PhabricatorRepository::TABLE_PATH,
array(md5($path_normal)));
$paths = ipull($paths, 'id', 'path');
$path_id = idx($paths, $path_normal);
$commit_ids = array_filter(mpull($commits, 'getID'));
$path_changes = array();
if ($path_id && $commit_ids) {
$path_changes = queryfx_all(
$conn_r,
'SELECT * FROM %T WHERE commitID IN (%Ld) AND pathID = %d',
PhabricatorRepository::TABLE_PATHCHANGE,
$commit_ids,
$path_id);
$path_changes = ipull($path_changes, null, 'commitID');
}
$history = array();
foreach ($identifiers as $identifier) {
$item = new DiffusionPathChange();
$item->setCommitIdentifier($identifier);
$commit = idx($commits, $identifier);
if ($commit) {
$item->setCommit($commit);
try {
$item->setCommitData($commit->getCommitData());
} catch (Exception $ex) {
// Ignore, commit just doesn't have data.
}
$change = idx($path_changes, $commit->getID());
if ($change) {
$item->setChangeType($change['changeType']);
$item->setFileType($change['fileType']);
}
}
$history[] = $item;
}
return $history;
}
}
diff --git a/src/applications/feed/conduit/FeedPublishConduitAPIMethod.php b/src/applications/feed/conduit/FeedPublishConduitAPIMethod.php
index 7cb741e151..a082e36fea 100644
--- a/src/applications/feed/conduit/FeedPublishConduitAPIMethod.php
+++ b/src/applications/feed/conduit/FeedPublishConduitAPIMethod.php
@@ -1,54 +1,49 @@
<?php
final class FeedPublishConduitAPIMethod extends FeedConduitAPIMethod {
public function getAPIMethodName() {
return 'feed.publish';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return 'Publish a story to the feed.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'type' => 'required string',
'data' => 'required dict',
'time' => 'optional int',
);
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty phid';
}
protected function execute(ConduitAPIRequest $request) {
$type = $request->getValue('type');
$data = $request->getValue('data');
$time = $request->getValue('time');
$author_phid = $request->getUser()->getPHID();
$phids = array($author_phid);
$publisher = new PhabricatorFeedStoryPublisher();
$publisher->setStoryType($type);
$publisher->setStoryData($data);
$publisher->setStoryTime($time);
$publisher->setRelatedPHIDs($phids);
$publisher->setStoryAuthorPHID($author_phid);
$data = $publisher->publish();
return $data->getPHID();
}
}
diff --git a/src/applications/feed/conduit/FeedQueryConduitAPIMethod.php b/src/applications/feed/conduit/FeedQueryConduitAPIMethod.php
index 9612122b40..02efb83f73 100644
--- a/src/applications/feed/conduit/FeedQueryConduitAPIMethod.php
+++ b/src/applications/feed/conduit/FeedQueryConduitAPIMethod.php
@@ -1,145 +1,145 @@
<?php
final class FeedQueryConduitAPIMethod extends FeedConduitAPIMethod {
public function getAPIMethodName() {
return 'feed.query';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return 'Query the feed for stories';
}
private function getDefaultLimit() {
return 100;
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'filterPHIDs' => 'optional list <phid>',
'limit' => 'optional int (default '.$this->getDefaultLimit().')',
'after' => 'optional int',
'before' => 'optional int',
'view' => 'optional string (data, html, html-summary, text)',
);
}
private function getSupportedViewTypes() {
return array(
'html' => 'Full HTML presentation of story',
'data' => 'Dictionary with various data of the story',
'html-summary' => 'Story contains only the title of the story',
'text' => 'Simple one-line plain text representation of story',
);
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
$view_types = array_keys($this->getSupportedViewTypes());
$view_types = implode(', ', $view_types);
return array(
'ERR-UNKNOWN-TYPE' =>
'Unsupported view type, possibles are: '.$view_types,
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
protected function execute(ConduitAPIRequest $request) {
$results = array();
$user = $request->getUser();
$view_type = $request->getValue('view');
if (!$view_type) {
$view_type = 'data';
}
$limit = $request->getValue('limit');
if (!$limit) {
$limit = $this->getDefaultLimit();
}
$filter_phids = $request->getValue('filterPHIDs');
if (!$filter_phids) {
$filter_phids = array();
}
$query = id(new PhabricatorFeedQuery())
->setLimit($limit)
->setFilterPHIDs($filter_phids)
->setViewer($user);
$after = $request->getValue('after');
if (strlen($after)) {
$query->setAfterID($after);
}
$before = $request->getValue('before');
if (strlen($before)) {
$query->setBeforeID($before);
}
$stories = $query->execute();
if ($stories) {
foreach ($stories as $story) {
$story_data = $story->getStoryData();
$data = null;
try {
$view = $story->renderView();
} catch (Exception $ex) {
// When stories fail to render, just fail that story.
phlog($ex);
continue;
}
$view->setEpoch($story->getEpoch());
$view->setUser($user);
switch ($view_type) {
case 'html':
$data = $view->render();
break;
case 'html-summary':
$data = $view->render();
break;
case 'data':
$data = array(
'class' => $story_data->getStoryType(),
'epoch' => $story_data->getEpoch(),
'authorPHID' => $story_data->getAuthorPHID(),
'chronologicalKey' => $story_data->getChronologicalKey(),
'data' => $story_data->getStoryData(),
);
break;
case 'text':
$data = array(
'class' => $story_data->getStoryType(),
'epoch' => $story_data->getEpoch(),
'authorPHID' => $story_data->getAuthorPHID(),
'chronologicalKey' => $story_data->getChronologicalKey(),
'objectPHID' => $story->getPrimaryObjectPHID(),
'text' => $story->renderText(),
);
break;
default:
throw new ConduitException('ERR-UNKNOWN-TYPE');
}
$results[$story_data->getPHID()] = $data;
}
}
return $results;
}
}
diff --git a/src/applications/files/conduit/FileAllocateConduitAPIMethod.php b/src/applications/files/conduit/FileAllocateConduitAPIMethod.php
index 80f1cad7e1..d21c26fe11 100644
--- a/src/applications/files/conduit/FileAllocateConduitAPIMethod.php
+++ b/src/applications/files/conduit/FileAllocateConduitAPIMethod.php
@@ -1,137 +1,133 @@
<?php
final class FileAllocateConduitAPIMethod
extends FileConduitAPIMethod {
public function getAPIMethodName() {
return 'file.allocate';
}
public function getMethodDescription() {
return pht('Prepare to upload a file.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'name' => 'string',
'contentLength' => 'int',
'contentHash' => 'optional string',
'viewPolicy' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'map<string, wild>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$hash = $request->getValue('contentHash');
$name = $request->getValue('name');
$view_policy = $request->getValue('viewPolicy');
$length = $request->getValue('contentLength');
$properties = array(
'name' => $name,
'authorPHID' => $viewer->getPHID(),
'viewPolicy' => $view_policy,
'isExplicitUpload' => true,
);
$file = null;
if ($hash) {
$file = PhabricatorFile::newFileFromContentHash(
$hash,
$properties);
}
if ($hash && !$file) {
$chunked_hash = PhabricatorChunkedFileStorageEngine::getChunkedHash(
$viewer,
$hash);
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withContentHashes(array($chunked_hash))
->executeOne();
}
if (strlen($name) && !$hash && !$file) {
if ($length > PhabricatorFileStorageEngine::getChunkThreshold()) {
// If we don't have a hash, but this file is large enough to store in
// chunks and thus may be resumable, try to find a partially uploaded
// file by the same author with the same name and same length. This
// allows us to resume uploads in Javascript where we can't efficiently
// compute file hashes.
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withAuthorPHIDs(array($viewer->getPHID()))
->withNames(array($name))
->withLengthBetween($length, $length)
->withIsPartial(true)
->setLimit(1)
->executeOne();
}
}
if ($file) {
return array(
'upload' => (bool)$file->getIsPartial(),
'filePHID' => $file->getPHID(),
);
}
// If there are any non-chunk engines which this file can fit into,
// just tell the client to upload the file.
$engines = PhabricatorFileStorageEngine::loadStorageEngines($length);
if ($engines) {
return array(
'upload' => true,
'filePHID' => null,
);
}
// Otherwise, this is a large file and we want to perform a chunked
// upload if we have a chunk engine available.
$chunk_engines = PhabricatorFileStorageEngine::loadWritableChunkEngines();
if ($chunk_engines) {
$chunk_properties = $properties;
if ($hash) {
$chunk_properties += array(
'chunkedHash' => $chunked_hash,
);
}
$chunk_engine = head($chunk_engines);
$file = $chunk_engine->allocateChunks($length, $chunk_properties);
return array(
'upload' => true,
'filePHID' => $file->getPHID(),
);
}
// None of the storage engines can accept this file.
if (PhabricatorFileStorageEngine::loadWritableEngines()) {
$error = pht(
'Unable to upload file: this file is too large for any '.
'configured storage engine.');
} else {
$error = pht(
'Unable to upload file: the server is not configured with any '.
'writable storage engines.');
}
return array(
'upload' => false,
'filePHID' => null,
'error' => $error,
);
}
}
diff --git a/src/applications/files/conduit/FileDownloadConduitAPIMethod.php b/src/applications/files/conduit/FileDownloadConduitAPIMethod.php
index ede4a07317..67e9d1f25c 100644
--- a/src/applications/files/conduit/FileDownloadConduitAPIMethod.php
+++ b/src/applications/files/conduit/FileDownloadConduitAPIMethod.php
@@ -1,43 +1,43 @@
<?php
final class FileDownloadConduitAPIMethod extends FileConduitAPIMethod {
public function getAPIMethodName() {
return 'file.download';
}
public function getMethodDescription() {
return 'Download a file from the server.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'phid' => 'required phid',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty base64-bytes';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-BAD-PHID' => 'No such file exists.',
);
}
protected function execute(ConduitAPIRequest $request) {
$phid = $request->getValue('phid');
$file = id(new PhabricatorFileQuery())
->setViewer($request->getUser())
->withPHIDs(array($phid))
->executeOne();
if (!$file) {
throw new ConduitException('ERR-BAD-PHID');
}
return base64_encode($file->loadFileData());
}
}
diff --git a/src/applications/files/conduit/FileInfoConduitAPIMethod.php b/src/applications/files/conduit/FileInfoConduitAPIMethod.php
index d95b002b9a..7b8cecbdf1 100644
--- a/src/applications/files/conduit/FileInfoConduitAPIMethod.php
+++ b/src/applications/files/conduit/FileInfoConduitAPIMethod.php
@@ -1,64 +1,64 @@
<?php
final class FileInfoConduitAPIMethod extends FileConduitAPIMethod {
public function getAPIMethodName() {
return 'file.info';
}
public function getMethodDescription() {
return 'Get information about a file.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'phid' => 'optional phid',
'id' => 'optional id',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-NOT-FOUND' => 'No such file exists.',
);
}
protected function execute(ConduitAPIRequest $request) {
$phid = $request->getValue('phid');
$id = $request->getValue('id');
$query = id(new PhabricatorFileQuery())
->setViewer($request->getUser());
if ($id) {
$query->withIDs(array($id));
} else {
$query->withPHIDs(array($phid));
}
$file = $query->executeOne();
if (!$file) {
throw new ConduitException('ERR-NOT-FOUND');
}
$uri = $file->getInfoURI();
return array(
'id' => $file->getID(),
'phid' => $file->getPHID(),
'objectName' => 'F'.$file->getID(),
'name' => $file->getName(),
'mimeType' => $file->getMimeType(),
'byteSize' => $file->getByteSize(),
'authorPHID' => $file->getAuthorPHID(),
'dateCreated' => $file->getDateCreated(),
'dateModified' => $file->getDateModified(),
'uri' => PhabricatorEnv::getProductionURI($uri),
);
}
}
diff --git a/src/applications/files/conduit/FileQueryChunksConduitAPIMethod.php b/src/applications/files/conduit/FileQueryChunksConduitAPIMethod.php
index 6f5db0733c..e0929ef8c4 100644
--- a/src/applications/files/conduit/FileQueryChunksConduitAPIMethod.php
+++ b/src/applications/files/conduit/FileQueryChunksConduitAPIMethod.php
@@ -1,47 +1,43 @@
<?php
final class FileQueryChunksConduitAPIMethod
extends FileConduitAPIMethod {
public function getAPIMethodName() {
return 'file.querychunks';
}
public function getMethodDescription() {
return pht('Get information about file chunks.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'filePHID' => 'phid',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<wild>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$file_phid = $request->getValue('filePHID');
$file = $this->loadFileByPHID($viewer, $file_phid);
$chunks = $this->loadFileChunks($viewer, $file);
$results = array();
foreach ($chunks as $chunk) {
$results[] = array(
'byteStart' => $chunk->getByteStart(),
'byteEnd' => $chunk->getByteEnd(),
'complete' => (bool)$chunk->getDataFilePHID(),
);
}
return $results;
}
}
diff --git a/src/applications/files/conduit/FileUploadChunkConduitAPIMethod.php b/src/applications/files/conduit/FileUploadChunkConduitAPIMethod.php
index c26ab42124..e3444d05e2 100644
--- a/src/applications/files/conduit/FileUploadChunkConduitAPIMethod.php
+++ b/src/applications/files/conduit/FileUploadChunkConduitAPIMethod.php
@@ -1,77 +1,73 @@
<?php
final class FileUploadChunkConduitAPIMethod
extends FileConduitAPIMethod {
public function getAPIMethodName() {
return 'file.uploadchunk';
}
public function getMethodDescription() {
return pht('Upload a chunk of file data to the server.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'filePHID' => 'phid',
'byteStart' => 'int',
'data' => 'string',
'dataEncoding' => 'string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$file_phid = $request->getValue('filePHID');
$file = $this->loadFileByPHID($viewer, $file_phid);
$start = $request->getValue('byteStart');
$data = $request->getValue('data');
$encoding = $request->getValue('dataEncoding');
switch ($encoding) {
case 'base64':
$data = $this->decodeBase64($data);
break;
case null:
break;
default:
throw new Exception(pht('Unsupported data encoding.'));
}
$length = strlen($data);
$chunk = $this->loadFileChunkForUpload(
$viewer,
$file,
$start,
$start + $length);
// NOTE: These files have a view policy which prevents normal access. They
// are only accessed through the storage engine.
$chunk_data = PhabricatorFile::newFromFileData(
$data,
array(
'name' => $file->getMonogram().'.chunk-'.$chunk->getID(),
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
));
$chunk->setDataFilePHID($chunk_data->getPHID())->save();
$missing = $this->loadAnyMissingChunk($viewer, $file);
if (!$missing) {
$file->setIsPartial(0)->save();
}
return null;
}
}
diff --git a/src/applications/files/conduit/FileUploadConduitAPIMethod.php b/src/applications/files/conduit/FileUploadConduitAPIMethod.php
index 3601594dad..594b53bcce 100644
--- a/src/applications/files/conduit/FileUploadConduitAPIMethod.php
+++ b/src/applications/files/conduit/FileUploadConduitAPIMethod.php
@@ -1,54 +1,49 @@
<?php
final class FileUploadConduitAPIMethod extends FileConduitAPIMethod {
public function getAPIMethodName() {
return 'file.upload';
}
public function getMethodDescription() {
return 'Upload a file to the server.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'data_base64' => 'required nonempty base64-bytes',
'name' => 'optional string',
'viewPolicy' => 'optional valid policy string or <phid>',
'canCDN' => 'optional bool',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty guid';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$name = $request->getValue('name');
$can_cdn = $request->getValue('canCDN');
$view_policy = $request->getValue('viewPolicy');
$data = $request->getValue('data_base64');
$data = $this->decodeBase64($data);
$file = PhabricatorFile::newFromFileData(
$data,
array(
'name' => $name,
'authorPHID' => $viewer->getPHID(),
'viewPolicy' => $view_policy,
'canCDN' => $can_cdn,
'isExplicitUpload' => true,
));
return $file->getPHID();
}
}
diff --git a/src/applications/files/conduit/FileUploadHashConduitAPIMethod.php b/src/applications/files/conduit/FileUploadHashConduitAPIMethod.php
index 8d1132c022..2ab13dc350 100644
--- a/src/applications/files/conduit/FileUploadHashConduitAPIMethod.php
+++ b/src/applications/files/conduit/FileUploadHashConduitAPIMethod.php
@@ -1,48 +1,43 @@
<?php
final class FileUploadHashConduitAPIMethod extends FileConduitAPIMethod {
public function getAPIMethodName() {
// TODO: Deprecate this in favor of `file.allocate`.
return 'file.uploadhash';
}
public function getMethodDescription() {
return 'Upload a file to the server using content hash.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'hash' => 'required nonempty string',
'name' => 'required nonempty string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'phid or null';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$hash = $request->getValue('hash');
$name = $request->getValue('name');
$user = $request->getUser();
$file = PhabricatorFile::newFileFromContentHash(
$hash,
array(
'name' => $name,
'authorPHID' => $user->getPHID(),
));
if ($file) {
return $file->getPHID();
}
return $file;
}
}
diff --git a/src/applications/flag/conduit/FlagDeleteConduitAPIMethod.php b/src/applications/flag/conduit/FlagDeleteConduitAPIMethod.php
index fe10f35467..6634fa7769 100644
--- a/src/applications/flag/conduit/FlagDeleteConduitAPIMethod.php
+++ b/src/applications/flag/conduit/FlagDeleteConduitAPIMethod.php
@@ -1,60 +1,60 @@
<?php
final class FlagDeleteConduitAPIMethod extends FlagConduitAPIMethod {
public function getAPIMethodName() {
return 'flag.delete';
}
public function getMethodDescription() {
return 'Clear a flag.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'id' => 'optional id',
'objectPHID' => 'optional phid',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict | null';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_NOT_FOUND' => 'Bad flag ID.',
'ERR_WRONG_USER' => 'You are not the creator of this flag.',
'ERR_NEED_PARAM' => 'Must pass an id or an objectPHID.',
);
}
protected function execute(ConduitAPIRequest $request) {
$id = $request->getValue('id');
$object = $request->getValue('objectPHID');
if ($id) {
$flag = id(new PhabricatorFlag())->load($id);
if (!$flag) {
throw new ConduitException('ERR_NOT_FOUND');
}
if ($flag->getOwnerPHID() != $request->getUser()->getPHID()) {
throw new ConduitException('ERR_WRONG_USER');
}
} else if ($object) {
$flag = id(new PhabricatorFlag())->loadOneWhere(
'objectPHID = %s AND ownerPHID = %s',
$object,
$request->getUser()->getPHID());
if (!$flag) {
return null;
}
} else {
throw new ConduitException('ERR_NEED_PARAM');
}
$this->attachHandleToFlag($flag, $request->getUser());
$ret = $this->buildFlagInfoDictionary($flag);
$flag->delete();
return $ret;
}
}
diff --git a/src/applications/flag/conduit/FlagEditConduitAPIMethod.php b/src/applications/flag/conduit/FlagEditConduitAPIMethod.php
index 4629ae942a..5a07cdeb9d 100644
--- a/src/applications/flag/conduit/FlagEditConduitAPIMethod.php
+++ b/src/applications/flag/conduit/FlagEditConduitAPIMethod.php
@@ -1,65 +1,60 @@
<?php
final class FlagEditConduitAPIMethod extends FlagConduitAPIMethod {
public function getAPIMethodName() {
return 'flag.edit';
}
public function getMethodDescription() {
return 'Create or modify a flag.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'objectPHID' => 'required phid',
'color' => 'optional int',
'note' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser()->getPHID();
$phid = $request->getValue('objectPHID');
$new = false;
$flag = id(new PhabricatorFlag())->loadOneWhere(
'objectPHID = %s AND ownerPHID = %s',
$phid,
$user);
if ($flag) {
$params = $request->getAllParameters();
if (isset($params['color'])) {
$flag->setColor($params['color']);
}
if (isset($params['note'])) {
$flag->setNote($params['note']);
}
} else {
$default_color = PhabricatorFlagColor::COLOR_BLUE;
$flag = id(new PhabricatorFlag())
->setOwnerPHID($user)
->setType(phid_get_type($phid))
->setObjectPHID($phid)
->setReasonPHID($user)
->setColor($request->getValue('color', $default_color))
->setNote($request->getValue('note', ''));
$new = true;
}
$this->attachHandleToFlag($flag, $request->getUser());
$flag->save();
$ret = $this->buildFlagInfoDictionary($flag);
$ret['new'] = $new;
return $ret;
}
}
diff --git a/src/applications/flag/conduit/FlagQueryConduitAPIMethod.php b/src/applications/flag/conduit/FlagQueryConduitAPIMethod.php
index fd4c48c3c4..486a5afa9c 100644
--- a/src/applications/flag/conduit/FlagQueryConduitAPIMethod.php
+++ b/src/applications/flag/conduit/FlagQueryConduitAPIMethod.php
@@ -1,67 +1,62 @@
<?php
final class FlagQueryConduitAPIMethod extends FlagConduitAPIMethod {
public function getAPIMethodName() {
return 'flag.query';
}
public function getMethodDescription() {
return 'Query flag markers.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ownerPHIDs' => 'optional list<phid>',
'types' => 'optional list<type>',
'objectPHIDs' => 'optional list<phid>',
'offset' => 'optional int',
'limit' => 'optional int (default = 100)',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$query = new PhabricatorFlagQuery();
$query->setViewer($request->getUser());
$owner_phids = $request->getValue('ownerPHIDs', array());
if ($owner_phids) {
$query->withOwnerPHIDs($owner_phids);
}
$object_phids = $request->getValue('objectPHIDs', array());
if ($object_phids) {
$query->withObjectPHIDs($object_phids);
}
$types = $request->getValue('types', array());
if ($types) {
$query->withTypes($types);
}
$query->needHandles(true);
$query->setOffset($request->getValue('offset', 0));
$query->setLimit($request->getValue('limit', 100));
$flags = $query->execute();
$results = array();
foreach ($flags as $flag) {
$results[] = $this->buildFlagInfoDictionary($flag);
}
return $results;
}
}
diff --git a/src/applications/harbormaster/conduit/HarbormasterQueryBuildablesConduitAPIMethod.php b/src/applications/harbormaster/conduit/HarbormasterQueryBuildablesConduitAPIMethod.php
index e0cd69d8be..818b983538 100644
--- a/src/applications/harbormaster/conduit/HarbormasterQueryBuildablesConduitAPIMethod.php
+++ b/src/applications/harbormaster/conduit/HarbormasterQueryBuildablesConduitAPIMethod.php
@@ -1,95 +1,91 @@
<?php
final class HarbormasterQueryBuildablesConduitAPIMethod
extends HarbormasterConduitAPIMethod {
public function getAPIMethodName() {
return 'harbormaster.querybuildables';
}
public function getMethodDescription() {
return pht('Query Harbormaster buildables.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<id>',
'phids' => 'optional list<phid>',
'buildablePHIDs' => 'optional list<phid>',
'containerPHIDs' => 'optional list<phid>',
'manualBuildables' => 'optional bool',
) + self::getPagerParamTypes();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'wild';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$query = id(new HarbormasterBuildableQuery())
->setViewer($viewer);
$ids = $request->getValue('ids');
if ($ids !== null) {
$query->withIDs($ids);
}
$phids = $request->getValue('phids');
if ($phids !== null) {
$query->withPHIDs($phids);
}
$buildable_phids = $request->getValue('buildablePHIDs');
if ($buildable_phids !== null) {
$query->withBuildablePHIDs($buildable_phids);
}
$container_phids = $request->getValue('containerPHIDs');
if ($container_phids !== null) {
$query->withContainerPHIDs($container_phids);
}
$manual = $request->getValue('manualBuildables');
if ($manual !== null) {
$query->withManualBuildables($manual);
}
$pager = $this->newPager($request);
$buildables = $query->executeWithCursorPager($pager);
$data = array();
foreach ($buildables as $buildable) {
$monogram = $buildable->getMonogram();
$status = $buildable->getBuildableStatus();
$status_name = HarbormasterBuildable::getBuildableStatusName($status);
$data[] = array(
'id' => $buildable->getID(),
'phid' => $buildable->getPHID(),
'monogram' => $monogram,
'uri' => PhabricatorEnv::getProductionURI('/'.$monogram),
'buildableStatus' => $status,
'buildableStatusName' => $status_name,
'buildablePHID' => $buildable->getBuildablePHID(),
'containerPHID' => $buildable->getContainerPHID(),
'isManualBuildable' => (bool)$buildable->getIsManualBuildable(),
);
}
$results = array(
'data' => $data,
);
$results = $this->addPagerResults($results, $pager);
return $results;
}
}
diff --git a/src/applications/harbormaster/conduit/HarbormasterQueryBuildsConduitAPIMethod.php b/src/applications/harbormaster/conduit/HarbormasterQueryBuildsConduitAPIMethod.php
index dfb8a7109d..95628500c1 100644
--- a/src/applications/harbormaster/conduit/HarbormasterQueryBuildsConduitAPIMethod.php
+++ b/src/applications/harbormaster/conduit/HarbormasterQueryBuildsConduitAPIMethod.php
@@ -1,94 +1,90 @@
<?php
final class HarbormasterQueryBuildsConduitAPIMethod
extends HarbormasterConduitAPIMethod {
public function getAPIMethodName() {
return 'harbormaster.querybuilds';
}
public function getMethodDescription() {
return pht('Query Harbormaster builds.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<id>',
'phids' => 'optional list<phid>',
'buildStatuses' => 'optional list<string>',
'buildablePHIDs' => 'optional list<phid>',
'buildPlanPHIDs' => 'optional list<phid>',
) + self::getPagerParamTypes();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'wild';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$query = id(new HarbormasterBuildQuery())
->setViewer($viewer);
$ids = $request->getValue('ids');
if ($ids !== null) {
$query->withIDs($ids);
}
$phids = $request->getValue('phids');
if ($phids !== null) {
$query->withPHIDs($phids);
}
$statuses = $request->getValue('buildStatuses');
if ($statuses !== null) {
$query->withBuildStatuses($statuses);
}
$buildable_phids = $request->getValue('buildablePHIDs');
if ($buildable_phids !== null) {
$query->withBuildablePHIDs($buildable_phids);
}
$build_plan_phids = $request->getValue('buildPlanPHIDs');
if ($build_plan_phids !== null) {
$query->withBuildPlanPHIDs($build_plan_phids);
}
$pager = $this->newPager($request);
$builds = $query->executeWithCursorPager($pager);
$data = array();
foreach ($builds as $build) {
$id = $build->getID();
$uri = '/harbormaster/build/'.$id.'/';
$status = $build->getBuildStatus();
$data[] = array(
'id' => $id,
'phid' => $build->getPHID(),
'uri' => PhabricatorEnv::getProductionURI($uri),
'name' => $build->getBuildPlan()->getName(),
'buildablePHID' => $build->getBuildablePHID(),
'buildPlanPHID' => $build->getBuildPlanPHID(),
'buildStatus' => $status,
'buildStatusName' => HarbormasterBuild::getBuildStatusName($status),
);
}
$results = array(
'data' => $data,
);
$results = $this->addPagerResults($results, $pager);
return $results;
}
}
diff --git a/src/applications/harbormaster/conduit/HarbormasterSendMessageConduitAPIMethod.php b/src/applications/harbormaster/conduit/HarbormasterSendMessageConduitAPIMethod.php
index 3eafe55259..f6752f08fb 100644
--- a/src/applications/harbormaster/conduit/HarbormasterSendMessageConduitAPIMethod.php
+++ b/src/applications/harbormaster/conduit/HarbormasterSendMessageConduitAPIMethod.php
@@ -1,63 +1,59 @@
<?php
final class HarbormasterSendMessageConduitAPIMethod
extends HarbormasterConduitAPIMethod {
public function getAPIMethodName() {
return 'harbormaster.sendmessage';
}
public function getMethodDescription() {
return pht(
'Send a message to a build target, notifying it of results in an '.
'external system.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$type_const = $this->formatStringConstants(array('pass', 'fail'));
return array(
'buildTargetPHID' => 'required phid',
'type' => 'required '.$type_const,
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$build_target_phid = $request->getValue('buildTargetPHID');
$message_type = $request->getValue('type');
$build_target = id(new HarbormasterBuildTargetQuery())
->setViewer($viewer)
->withPHIDs(array($build_target_phid))
->executeOne();
if (!$build_target) {
throw new Exception(pht('No such build target!'));
}
$message = HarbormasterBuildMessage::initializeNewMessage($viewer)
->setBuildTargetPHID($build_target->getPHID())
->setType($message_type)
->save();
// If the build has completely paused because all steps are blocked on
// waiting targets, this will resume it.
PhabricatorWorker::scheduleTask(
'HarbormasterBuildWorker',
array(
'buildID' => $build_target->getBuild()->getID(),
));
return null;
}
}
diff --git a/src/applications/macro/conduit/MacroCreateMemeConduitAPIMethod.php b/src/applications/macro/conduit/MacroCreateMemeConduitAPIMethod.php
index 05f14b1677..308f1c3b3a 100644
--- a/src/applications/macro/conduit/MacroCreateMemeConduitAPIMethod.php
+++ b/src/applications/macro/conduit/MacroCreateMemeConduitAPIMethod.php
@@ -1,57 +1,57 @@
<?php
final class MacroCreateMemeConduitAPIMethod extends MacroConduitAPIMethod {
public function getAPIMethodName() {
return 'macro.creatememe';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return pht('Generate a meme.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'macroName' => 'string',
'upperText' => 'optional string',
'lowerText' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'string';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-NOT-FOUND' => 'Macro was not found.',
);
}
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser();
$macro_name = $request->getValue('macroName');
$upper_text = $request->getValue('upperText');
$lower_text = $request->getValue('lowerText');
$uri = PhabricatorMacroMemeController::generateMacro(
$user,
$macro_name,
$upper_text,
$lower_text);
if (!$uri) {
throw new ConduitException('ERR-NOT-FOUND');
}
return array(
'uri' => $uri,
);
}
}
diff --git a/src/applications/macro/conduit/MacroQueryConduitAPIMethod.php b/src/applications/macro/conduit/MacroQueryConduitAPIMethod.php
index 29702c8dc1..66cdedeebc 100644
--- a/src/applications/macro/conduit/MacroQueryConduitAPIMethod.php
+++ b/src/applications/macro/conduit/MacroQueryConduitAPIMethod.php
@@ -1,84 +1,79 @@
<?php
final class MacroQueryConduitAPIMethod extends MacroConduitAPIMethod {
public function getAPIMethodName() {
return 'macro.query';
}
public function getMethodDescription() {
return 'Retrieve image macro information.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'authorPHIDs' => 'optional list<phid>',
'phids' => 'optional list<phid>',
'ids' => 'optional list<id>',
'names' => 'optional list<string>',
'nameLike' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$query = id(new PhabricatorMacroQuery())
->setViewer($request->getUser())
->needFiles(true);
$author_phids = $request->getValue('authorPHIDs');
$phids = $request->getValue('phids');
$ids = $request->getValue('ids');
$name_like = $request->getValue('nameLike');
$names = $request->getValue('names');
if ($author_phids) {
$query->withAuthorPHIDs($author_phids);
}
if ($phids) {
$query->withPHIDs($phids);
}
if ($ids) {
$query->withIDs($ids);
}
if ($name_like) {
$query->withNameLike($name_like);
}
if ($names) {
$query->withNames($names);
}
$macros = $query->execute();
if (!$macros) {
return array();
}
$results = array();
foreach ($macros as $macro) {
$file = $macro->getFile();
$results[$macro->getName()] = array(
'uri' => $file->getBestURI(),
'phid' => $macro->getPHID(),
'authorPHID' => $file->getAuthorPHID(),
'dateCreated' => $file->getDateCreated(),
'filePHID' => $file->getPHID(),
);
}
return $results;
}
}
diff --git a/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php b/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php
index b89369f692..39067f7cbd 100644
--- a/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php
+++ b/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php
@@ -1,322 +1,322 @@
<?php
abstract class ManiphestConduitAPIMethod extends ConduitAPIMethod {
final public function getApplication() {
return PhabricatorApplication::getByClass(
'PhabricatorManiphestApplication');
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-INVALID-PARAMETER' => 'Missing or malformed parameter.',
);
}
protected function buildTaskInfoDictionary(ManiphestTask $task) {
$results = $this->buildTaskInfoDictionaries(array($task));
return idx($results, $task->getPHID());
}
protected function getTaskFields($is_new) {
$fields = array();
if (!$is_new) {
$fields += array(
'id' => 'optional int',
'phid' => 'optional int',
);
}
$fields += array(
'title' => $is_new ? 'required string' : 'optional string',
'description' => 'optional string',
'ownerPHID' => 'optional phid',
'viewPolicy' => 'optional phid or policy string',
'editPolicy' => 'optional phid or policy string',
'ccPHIDs' => 'optional list<phid>',
'priority' => 'optional int',
'projectPHIDs' => 'optional list<phid>',
'auxiliary' => 'optional dict',
);
if (!$is_new) {
$fields += array(
'status' => 'optional string',
'comments' => 'optional string',
);
}
return $fields;
}
protected function applyRequest(
ManiphestTask $task,
ConduitAPIRequest $request,
$is_new) {
$changes = array();
if ($is_new) {
$task->setTitle((string)$request->getValue('title'));
$task->setDescription((string)$request->getValue('description'));
$changes[ManiphestTransaction::TYPE_STATUS] =
ManiphestTaskStatus::getDefaultStatus();
$changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] =
array('+' => array($request->getUser()->getPHID()));
} else {
$comments = $request->getValue('comments');
if (!$is_new && $comments !== null) {
$changes[PhabricatorTransactions::TYPE_COMMENT] = null;
}
$title = $request->getValue('title');
if ($title !== null) {
$changes[ManiphestTransaction::TYPE_TITLE] = $title;
}
$desc = $request->getValue('description');
if ($desc !== null) {
$changes[ManiphestTransaction::TYPE_DESCRIPTION] = $desc;
}
$status = $request->getValue('status');
if ($status !== null) {
$valid_statuses = ManiphestTaskStatus::getTaskStatusMap();
if (!isset($valid_statuses[$status])) {
throw id(new ConduitException('ERR-INVALID-PARAMETER'))
->setErrorDescription('Status set to invalid value.');
}
$changes[ManiphestTransaction::TYPE_STATUS] = $status;
}
}
$priority = $request->getValue('priority');
if ($priority !== null) {
$valid_priorities = ManiphestTaskPriority::getTaskPriorityMap();
if (!isset($valid_priorities[$priority])) {
throw id(new ConduitException('ERR-INVALID-PARAMETER'))
->setErrorDescription('Priority set to invalid value.');
}
$changes[ManiphestTransaction::TYPE_PRIORITY] = $priority;
}
$owner_phid = $request->getValue('ownerPHID');
if ($owner_phid !== null) {
$this->validatePHIDList(
array($owner_phid),
PhabricatorPeopleUserPHIDType::TYPECONST,
'ownerPHID');
$changes[ManiphestTransaction::TYPE_OWNER] = $owner_phid;
}
$ccs = $request->getValue('ccPHIDs');
if ($ccs !== null) {
$changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] =
array('=' => array_fuse($ccs));
}
$transactions = array();
$view_policy = $request->getValue('viewPolicy');
if ($view_policy !== null) {
$transactions[] = id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
->setNewValue($view_policy);
}
$edit_policy = $request->getValue('editPolicy');
if ($edit_policy !== null) {
$transactions[] = id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
->setNewValue($edit_policy);
}
$project_phids = $request->getValue('projectPHIDs');
if ($project_phids !== null) {
$this->validatePHIDList(
$project_phids,
PhabricatorProjectProjectPHIDType::TYPECONST,
'projectPHIDS');
$project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
$transactions[] = id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue('edge:type', $project_type)
->setNewValue(
array(
'=' => array_fuse($project_phids),
));
}
$template = new ManiphestTransaction();
foreach ($changes as $type => $value) {
$transaction = clone $template;
$transaction->setTransactionType($type);
if ($type == PhabricatorTransactions::TYPE_COMMENT) {
$transaction->attachComment(
id(new ManiphestTransactionComment())
->setContent($comments));
} else {
$transaction->setNewValue($value);
}
$transactions[] = $transaction;
}
$field_list = PhabricatorCustomField::getObjectFields(
$task,
PhabricatorCustomField::ROLE_EDIT);
$field_list->readFieldsFromStorage($task);
$auxiliary = $request->getValue('auxiliary');
if ($auxiliary) {
foreach ($field_list->getFields() as $key => $field) {
if (!array_key_exists($key, $auxiliary)) {
continue;
}
$transaction = clone $template;
$transaction->setTransactionType(
PhabricatorTransactions::TYPE_CUSTOMFIELD);
$transaction->setMetadataValue('customfield:key', $key);
$transaction->setOldValue(
$field->getOldValueForApplicationTransactions());
$transaction->setNewValue($auxiliary[$key]);
$transactions[] = $transaction;
}
}
if (!$transactions) {
return;
}
$event = new PhabricatorEvent(
PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK,
array(
'task' => $task,
'new' => $is_new,
'transactions' => $transactions,
));
$event->setUser($request->getUser());
$event->setConduitRequest($request);
PhutilEventEngine::dispatchEvent($event);
$task = $event->getValue('task');
$transactions = $event->getValue('transactions');
$content_source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_CONDUIT,
array());
$editor = id(new ManiphestTransactionEditor())
->setActor($request->getUser())
->setContentSource($content_source)
->setContinueOnNoEffect(true);
if (!$is_new) {
$editor->setContinueOnMissingFields(true);
}
$editor->applyTransactions($task, $transactions);
$event = new PhabricatorEvent(
PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK,
array(
'task' => $task,
'new' => $is_new,
'transactions' => $transactions,
));
$event->setUser($request->getUser());
$event->setConduitRequest($request);
PhutilEventEngine::dispatchEvent($event);
// reload the task now that we've done all the fun stuff
return id(new ManiphestTaskQuery())
->setViewer($request->getUser())
->withPHIDs(array($task->getPHID()))
->needSubscriberPHIDs(true)
->needProjectPHIDs(true)
->executeOne();
}
protected function buildTaskInfoDictionaries(array $tasks) {
assert_instances_of($tasks, 'ManiphestTask');
if (!$tasks) {
return array();
}
$task_phids = mpull($tasks, 'getPHID');
$all_deps = id(new PhabricatorEdgeQuery())
->withSourcePHIDs($task_phids)
->withEdgeTypes(array(ManiphestTaskDependsOnTaskEdgeType::EDGECONST));
$all_deps->execute();
$result = array();
foreach ($tasks as $task) {
// TODO: Batch this get as CustomField gets cleaned up.
$field_list = PhabricatorCustomField::getObjectFields(
$task,
PhabricatorCustomField::ROLE_EDIT);
$field_list->readFieldsFromStorage($task);
$auxiliary = mpull(
$field_list->getFields(),
'getValueForStorage',
'getFieldKey');
$task_deps = $all_deps->getDestinationPHIDs(
array($task->getPHID()),
array(ManiphestTaskDependsOnTaskEdgeType::EDGECONST));
$result[$task->getPHID()] = array(
'id' => $task->getID(),
'phid' => $task->getPHID(),
'authorPHID' => $task->getAuthorPHID(),
'ownerPHID' => $task->getOwnerPHID(),
'ccPHIDs' => $task->getSubscriberPHIDs(),
'status' => $task->getStatus(),
'statusName' => ManiphestTaskStatus::getTaskStatusName(
$task->getStatus()),
'isClosed' => $task->isClosed(),
'priority' => ManiphestTaskPriority::getTaskPriorityName(
$task->getPriority()),
'priorityColor' => ManiphestTaskPriority::getTaskPriorityColor(
$task->getPriority()),
'title' => $task->getTitle(),
'description' => $task->getDescription(),
'projectPHIDs' => $task->getProjectPHIDs(),
'uri' => PhabricatorEnv::getProductionURI('/T'.$task->getID()),
'auxiliary' => $auxiliary,
'objectName' => 'T'.$task->getID(),
'dateCreated' => $task->getDateCreated(),
'dateModified' => $task->getDateModified(),
'dependsOnTaskPHIDs' => $task_deps,
);
}
return $result;
}
/**
* NOTE: This is a temporary stop gap since its easy to make malformed tasks.
* Long-term, the values set in @{method:defineParamTypes} will be used to
* validate data implicitly within the larger Conduit application.
*
* TODO: Remove this in favor of generalized Conduit hotness.
*/
private function validatePHIDList(array $phid_list, $phid_type, $field) {
$phid_groups = phid_group_by_type($phid_list);
unset($phid_groups[$phid_type]);
if (!empty($phid_groups)) {
throw id(new ConduitException('ERR-INVALID-PARAMETER'))
->setErrorDescription('One or more PHIDs were invalid for '.$field.'.');
}
return true;
}
}
diff --git a/src/applications/maniphest/conduit/ManiphestCreateTaskConduitAPIMethod.php b/src/applications/maniphest/conduit/ManiphestCreateTaskConduitAPIMethod.php
index 4abcaecb6a..ed16f77495 100644
--- a/src/applications/maniphest/conduit/ManiphestCreateTaskConduitAPIMethod.php
+++ b/src/applications/maniphest/conduit/ManiphestCreateTaskConduitAPIMethod.php
@@ -1,36 +1,36 @@
<?php
final class ManiphestCreateTaskConduitAPIMethod
extends ManiphestConduitAPIMethod {
public function getAPIMethodName() {
return 'maniphest.createtask';
}
public function getMethodDescription() {
return 'Create a new Maniphest task.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return $this->getTaskFields($is_new = true);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-INVALID-PARAMETER' => 'Missing or malformed parameter.',
);
}
protected function execute(ConduitAPIRequest $request) {
$task = ManiphestTask::initializeNewTask($request->getUser());
$task = $this->applyRequest($task, $request, $is_new = true);
return $this->buildTaskInfoDictionary($task);
}
}
diff --git a/src/applications/maniphest/conduit/ManiphestGetTaskTransactionsConduitAPIMethod.php b/src/applications/maniphest/conduit/ManiphestGetTaskTransactionsConduitAPIMethod.php
index cf3f755314..ff51dafd7d 100644
--- a/src/applications/maniphest/conduit/ManiphestGetTaskTransactionsConduitAPIMethod.php
+++ b/src/applications/maniphest/conduit/ManiphestGetTaskTransactionsConduitAPIMethod.php
@@ -1,80 +1,75 @@
<?php
final class ManiphestGetTaskTransactionsConduitAPIMethod
extends ManiphestConduitAPIMethod {
public function getAPIMethodName() {
return 'maniphest.gettasktransactions';
}
public function getMethodDescription() {
return 'Retrieve Maniphest Task Transactions.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'required list<int>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty list<dict<string, wild>>';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$results = array();
$task_ids = $request->getValue('ids');
if (!$task_ids) {
return $results;
}
$tasks = id(new ManiphestTaskQuery())
->setViewer($request->getUser())
->withIDs($task_ids)
->execute();
$tasks = mpull($tasks, null, 'getPHID');
$transactions = array();
if ($tasks) {
$transactions = id(new ManiphestTransactionQuery())
->setViewer($request->getUser())
->withObjectPHIDs(mpull($tasks, 'getPHID'))
->needComments(true)
->execute();
}
foreach ($transactions as $transaction) {
$task_phid = $transaction->getObjectPHID();
if (empty($tasks[$task_phid])) {
continue;
}
$task_id = $tasks[$task_phid]->getID();
$comments = null;
if ($transaction->hasComment()) {
$comments = $transaction->getComment()->getContent();
}
$results[$task_id][] = array(
'taskID' => $task_id,
'transactionPHID' => $transaction->getPHID(),
'transactionType' => $transaction->getTransactionType(),
'oldValue' => $transaction->getOldValue(),
'newValue' => $transaction->getNewValue(),
'comments' => $comments,
'authorPHID' => $transaction->getAuthorPHID(),
'dateCreated' => $transaction->getDateCreated(),
);
}
return $results;
}
}
diff --git a/src/applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php b/src/applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php
index b998bb627c..5915e74fb5 100644
--- a/src/applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php
+++ b/src/applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php
@@ -1,45 +1,45 @@
<?php
final class ManiphestInfoConduitAPIMethod extends ManiphestConduitAPIMethod {
public function getAPIMethodName() {
return 'maniphest.info';
}
public function getMethodDescription() {
return 'Retrieve information about a Maniphest task, given its id.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'task_id' => 'required id',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BAD_TASK' => 'No such maniphest task exists',
);
}
protected function execute(ConduitAPIRequest $request) {
$task_id = $request->getValue('task_id');
$task = id(new ManiphestTaskQuery())
->setViewer($request->getUser())
->withIDs(array($task_id))
->needSubscriberPHIDs(true)
->needProjectPHIDs(true)
->executeOne();
if (!$task) {
throw new ConduitException('ERR_BAD_TASK');
}
return $this->buildTaskInfoDictionary($task);
}
}
diff --git a/src/applications/maniphest/conduit/ManiphestQueryConduitAPIMethod.php b/src/applications/maniphest/conduit/ManiphestQueryConduitAPIMethod.php
index 6c850b8630..a8c687b36e 100644
--- a/src/applications/maniphest/conduit/ManiphestQueryConduitAPIMethod.php
+++ b/src/applications/maniphest/conduit/ManiphestQueryConduitAPIMethod.php
@@ -1,123 +1,119 @@
<?php
final class ManiphestQueryConduitAPIMethod extends ManiphestConduitAPIMethod {
public function getAPIMethodName() {
return 'maniphest.query';
}
public function getMethodDescription() {
return 'Execute complex searches for Maniphest tasks.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$statuses = array(
ManiphestTaskQuery::STATUS_ANY,
ManiphestTaskQuery::STATUS_OPEN,
ManiphestTaskQuery::STATUS_CLOSED,
ManiphestTaskQuery::STATUS_RESOLVED,
ManiphestTaskQuery::STATUS_WONTFIX,
ManiphestTaskQuery::STATUS_INVALID,
ManiphestTaskQuery::STATUS_SPITE,
ManiphestTaskQuery::STATUS_DUPLICATE,
);
$status_const = $this->formatStringConstants($statuses);
$orders = array(
ManiphestTaskQuery::ORDER_PRIORITY,
ManiphestTaskQuery::ORDER_CREATED,
ManiphestTaskQuery::ORDER_MODIFIED,
);
$order_const = $this->formatStringConstants($orders);
return array(
'ids' => 'optional list<uint>',
'phids' => 'optional list<phid>',
'ownerPHIDs' => 'optional list<phid>',
'authorPHIDs' => 'optional list<phid>',
'projectPHIDs' => 'optional list<phid>',
'ccPHIDs' => 'optional list<phid>',
'fullText' => 'optional string',
'status' => 'optional '.$status_const,
'order' => 'optional '.$order_const,
'limit' => 'optional int',
'offset' => 'optional int',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$query = id(new ManiphestTaskQuery())
->setViewer($request->getUser())
->needProjectPHIDs(true)
->needSubscriberPHIDs(true);
$task_ids = $request->getValue('ids');
if ($task_ids) {
$query->withIDs($task_ids);
}
$task_phids = $request->getValue('phids');
if ($task_phids) {
$query->withPHIDs($task_phids);
}
$owners = $request->getValue('ownerPHIDs');
if ($owners) {
$query->withOwners($owners);
}
$authors = $request->getValue('authorPHIDs');
if ($authors) {
$query->withAuthors($authors);
}
$projects = $request->getValue('projectPHIDs');
if ($projects) {
$query->withAllProjects($projects);
}
$ccs = $request->getValue('ccPHIDs');
if ($ccs) {
$query->withSubscribers($ccs);
}
$full_text = $request->getValue('fullText');
if ($full_text) {
$query->withFullTextSearch($full_text);
}
$status = $request->getValue('status');
if ($status) {
$query->withStatus($status);
}
$order = $request->getValue('order');
if ($order) {
$query->setOrderBy($order);
}
$limit = $request->getValue('limit');
if ($limit) {
$query->setLimit($limit);
}
$offset = $request->getValue('offset');
if ($offset) {
$query->setOffset($offset);
}
$results = $query->execute();
return $this->buildTaskInfoDictionaries($results);
}
}
diff --git a/src/applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php b/src/applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php
index b6d933ae1e..8255b3474c 100644
--- a/src/applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php
+++ b/src/applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php
@@ -1,39 +1,35 @@
<?php
final class ManiphestQueryStatusesConduitAPIMethod
extends ManiphestConduitAPIMethod {
public function getAPIMethodName() {
return 'maniphest.querystatuses';
}
public function getMethodDescription() {
return 'Retrieve information about possible Maniphest Task status values.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict<string, wild>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$results = array(
'defaultStatus' => ManiphestTaskStatus::getDefaultStatus(),
'defaultClosedStatus' => ManiphestTaskStatus::getDefaultClosedStatus(),
'duplicateStatus' => ManiphestTaskStatus::getDuplicateStatus(),
'openStatuses' => ManiphestTaskStatus::getOpenStatusConstants(),
'closedStatuses' => ManiphestTaskStatus::getClosedStatusConstants(),
'allStatuses' => array_keys(ManiphestTaskStatus::getTaskStatusMap()),
'statusMap' => ManiphestTaskStatus::getTaskStatusMap(),
);
return $results;
}
}
diff --git a/src/applications/maniphest/conduit/ManiphestUpdateConduitAPIMethod.php b/src/applications/maniphest/conduit/ManiphestUpdateConduitAPIMethod.php
index 667857a189..a4a6232679 100644
--- a/src/applications/maniphest/conduit/ManiphestUpdateConduitAPIMethod.php
+++ b/src/applications/maniphest/conduit/ManiphestUpdateConduitAPIMethod.php
@@ -1,65 +1,65 @@
<?php
final class ManiphestUpdateConduitAPIMethod extends ManiphestConduitAPIMethod {
public function getAPIMethodName() {
return 'maniphest.update';
}
public function getMethodDescription() {
return 'Update an existing Maniphest task.';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-BAD-TASK' => 'No such maniphest task exists.',
'ERR-INVALID-PARAMETER' => 'Missing or malformed parameter.',
'ERR-NO-EFFECT' => 'Update has no effect.',
);
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return $this->getTaskFields($is_new = false);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
protected function execute(ConduitAPIRequest $request) {
$id = $request->getValue('id');
$phid = $request->getValue('phid');
if (($id && $phid) || (!$id && !$phid)) {
throw new Exception("Specify exactly one of 'id' and 'phid'.");
}
$query = id (new ManiphestTaskQuery())
->setViewer($request->getUser())
->needSubscriberPHIDs(true)
->needProjectPHIDs(true);
if ($id) {
$query->withIDs(array($id));
} else {
$query->withPHIDs(array($phid));
}
$task = $query->executeOne();
$params = $request->getAllParameters();
unset($params['id']);
unset($params['phid']);
if (call_user_func_array('coalesce', $params) === null) {
throw new ConduitException('ERR-NO-EFFECT');
}
if (!$task) {
throw new ConduitException('ERR-BAD-TASK');
}
$task = $this->applyRequest($task, $request, $is_new = false);
return $this->buildTaskInfoDictionary($task);
}
}
diff --git a/src/applications/nuance/conduit/NuanceCreateItemConduitAPIMethod.php b/src/applications/nuance/conduit/NuanceCreateItemConduitAPIMethod.php
index ae2220834c..2bc5e9151a 100644
--- a/src/applications/nuance/conduit/NuanceCreateItemConduitAPIMethod.php
+++ b/src/applications/nuance/conduit/NuanceCreateItemConduitAPIMethod.php
@@ -1,73 +1,73 @@
<?php
final class NuanceCreateItemConduitAPIMethod extends NuanceConduitAPIMethod {
public function getAPIMethodName() {
return 'nuance.createitem';
}
public function getMethodDescription() {
return pht('Create a new item.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'requestorPHID' => 'required string',
'sourcePHID' => 'required string',
'ownerPHID' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-NO-REQUESTOR-PHID' => pht('Items must have a requestor.'),
'ERR-NO-SOURCE-PHID' => pht('Items must have a source.'),
);
}
protected function execute(ConduitAPIRequest $request) {
$source_phid = $request->getValue('sourcePHID');
$owner_phid = $request->getValue('ownerPHID');
$requestor_phid = $request->getValue('requestorPHID');
$user = $request->getUser();
$item = NuanceItem::initializeNewItem($user);
$xactions = array();
if ($source_phid) {
$xactions[] = id(new NuanceItemTransaction())
->setTransactionType(NuanceItemTransaction::TYPE_SOURCE)
->setNewValue($source_phid);
} else {
throw new ConduitException('ERR-NO-SOURCE-PHID');
}
if ($owner_phid) {
$xactions[] = id(new NuanceItemTransaction())
->setTransactionType(NuanceItemTransaction::TYPE_OWNER)
->setNewValue($owner_phid);
}
if ($requestor_phid) {
$xactions[] = id(new NuanceItemTransaction())
->setTransactionType(NuanceItemTransaction::TYPE_REQUESTOR)
->setNewValue($requestor_phid);
} else {
throw new ConduitException('ERR-NO-REQUESTOR-PHID');
}
$source = PhabricatorContentSource::newFromConduitRequest($request);
$editor = id(new NuanceItemEditor())
->setActor($user)
->setContentSource($source)
->applyTransactions($item, $xactions);
return $item->toDictionary();
}
}
diff --git a/src/applications/owners/conduit/OwnersQueryConduitAPIMethod.php b/src/applications/owners/conduit/OwnersQueryConduitAPIMethod.php
index f0908f83e7..f62c456283 100644
--- a/src/applications/owners/conduit/OwnersQueryConduitAPIMethod.php
+++ b/src/applications/owners/conduit/OwnersQueryConduitAPIMethod.php
@@ -1,157 +1,157 @@
<?php
final class OwnersQueryConduitAPIMethod extends OwnersConduitAPIMethod {
public function getAPIMethodName() {
return 'owners.query';
}
public function getMethodDescription() {
return 'Query for packages by one of the following: repository/path, '.
'packages with a given user or project owner, or packages affiliated '.
'with a user (owned by either the user or a project they are a member '.
'of.) You should only provide at most one search query.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'userOwner' => 'optional string',
'projectOwner' => 'optional string',
'userAffiliated' => 'optional string',
'repositoryCallsign' => 'optional string',
'path' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict<phid -> dict of package info>';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-INVALID-USAGE' =>
'Provide one of a single owner phid (user/project), a single '.
'affiliated user phid (user), or a repository/path.',
'ERR-INVALID-PARAMETER' => 'parameter should be a phid',
'ERR_REP_NOT_FOUND' => 'The repository callsign is not recognized',
);
}
protected static function queryAll() {
return id(new PhabricatorOwnersPackage())->loadAll();
}
protected static function queryByOwner($owner) {
$is_valid_phid =
phid_get_type($owner) == PhabricatorPeopleUserPHIDType::TYPECONST ||
phid_get_type($owner) == PhabricatorProjectProjectPHIDType::TYPECONST;
if (!$is_valid_phid) {
throw id(new ConduitException('ERR-INVALID-PARAMETER'))
->setErrorDescription(
'Expected user/project PHID for owner, got '.$owner);
}
$owners = id(new PhabricatorOwnersOwner())->loadAllWhere(
'userPHID = %s',
$owner);
$package_ids = mpull($owners, 'getPackageID');
$packages = array();
foreach ($package_ids as $id) {
$packages[] = id(new PhabricatorOwnersPackage())->load($id);
}
return $packages;
}
private static function queryByPath(
PhabricatorUser $viewer,
$repo_callsign,
$path) {
$repository = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->withCallsigns(array($repo_callsign))
->executeOne();
if (!$repository) {
throw id(new ConduitException('ERR_REP_NOT_FOUND'))
->setErrorDescription(
'Repository callsign '.$repo_callsign.' not recognized');
}
if ($path == null) {
return PhabricatorOwnersPackage::loadPackagesForRepository($repository);
} else {
return PhabricatorOwnersPackage::loadOwningPackages(
$repository, $path);
}
}
public static function buildPackageInformationDictionaries($packages) {
assert_instances_of($packages, 'PhabricatorOwnersPackage');
$result = array();
foreach ($packages as $package) {
$p_owners = $package->loadOwners();
$p_paths = $package->loadPaths();
$owners = array_values(mpull($p_owners, 'getUserPHID'));
$paths = array();
foreach ($p_paths as $p) {
$paths[] = array($p->getRepositoryPHID(), $p->getPath());
}
$result[$package->getPHID()] = array(
'phid' => $package->getPHID(),
'name' => $package->getName(),
'description' => $package->getDescription(),
'primaryOwner' => $package->getPrimaryOwnerPHID(),
'owners' => $owners,
'paths' => $paths,
);
}
return $result;
}
protected function execute(ConduitAPIRequest $request) {
$is_owner_query =
($request->getValue('userOwner') ||
$request->getValue('projectOwner')) ?
1 : 0;
$is_affiliated_query = $request->getValue('userAffiliated') ? 1 : 0;
$repo = $request->getValue('repositoryCallsign');
$path = $request->getValue('path');
$is_path_query = $repo ? 1 : 0;
if ($is_owner_query + $is_path_query + $is_affiliated_query === 0) {
// if no search terms are provided, return everything
$packages = self::queryAll();
} else if ($is_owner_query + $is_path_query + $is_affiliated_query > 1) {
// otherwise, exactly one of these should be provided
throw new ConduitException('ERR-INVALID-USAGE');
}
if ($is_affiliated_query) {
$query = id(new PhabricatorOwnersPackageQuery())
->setViewer($request->getUser());
$query->withOwnerPHIDs(array($request->getValue('userAffiliated')));
$packages = $query->execute();
} else if ($is_owner_query) {
$owner = nonempty(
$request->getValue('userOwner'),
$request->getValue('projectOwner'));
$packages = self::queryByOwner($owner);
} else if ($is_path_query) {
$packages = self::queryByPath($request->getUser(), $repo, $path);
}
return self::buildPackageInformationDictionaries($packages);
}
}
diff --git a/src/applications/passphrase/conduit/PassphraseQueryConduitAPIMethod.php b/src/applications/passphrase/conduit/PassphraseQueryConduitAPIMethod.php
index c0ec34acf5..07a8b0226e 100644
--- a/src/applications/passphrase/conduit/PassphraseQueryConduitAPIMethod.php
+++ b/src/applications/passphrase/conduit/PassphraseQueryConduitAPIMethod.php
@@ -1,124 +1,120 @@
<?php
final class PassphraseQueryConduitAPIMethod
extends PassphraseConduitAPIMethod {
public function getAPIMethodName() {
return 'passphrase.query';
}
public function getMethodDescription() {
return pht('Query credentials.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<int>',
'phids' => 'optional list<phid>',
'needSecrets' => 'optional bool',
'needPublicKeys' => 'optional bool',
) + $this->getPagerParamTypes();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$query = id(new PassphraseCredentialQuery())
->setViewer($request->getUser());
if ($request->getValue('ids')) {
$query->withIDs($request->getValue('ids'));
}
if ($request->getValue('phids')) {
$query->withPHIDs($request->getValue('phids'));
}
if ($request->getValue('needSecrets')) {
$query->needSecrets(true);
}
$pager = $this->newPager($request);
$credentials = $query->executeWithCursorPager($pager);
$results = array();
foreach ($credentials as $credential) {
$type = PassphraseCredentialType::getTypeByConstant(
$credential->getCredentialType());
if (!$type) {
continue;
}
$public_key = null;
if ($request->getValue('needPublicKeys') && $type->hasPublicKey()) {
$public_key = $type->getPublicKey(
$request->getUser(),
$credential);
}
$secret = null;
if ($request->getValue('needSecrets')) {
if ($credential->getAllowConduit()) {
$secret = $credential->getSecret()->openEnvelope();
}
}
$material = array();
switch ($credential->getCredentialType()) {
case PassphraseCredentialTypeSSHPrivateKeyFile::CREDENTIAL_TYPE:
if ($secret) {
$material['file'] = $secret;
}
if ($public_key) {
$material['publicKey'] = $public_key;
}
break;
case PassphraseCredentialTypeSSHGeneratedKey::CREDENTIAL_TYPE:
case PassphraseCredentialTypeSSHPrivateKeyText::CREDENTIAL_TYPE:
if ($secret) {
$material['privateKey'] = $secret;
}
if ($public_key) {
$material['publicKey'] = $public_key;
}
break;
case PassphraseCredentialTypePassword::CREDENTIAL_TYPE:
if ($secret) {
$material['password'] = $secret;
}
break;
}
if (!$credential->getAllowConduit()) {
$material['noAPIAccess'] = pht(
'This credential\'s private material '.
'is not accessible via API calls.');
}
$results[$credential->getPHID()] = array(
'id' => $credential->getID(),
'phid' => $credential->getPHID(),
'type' => $credential->getCredentialType(),
'name' => $credential->getName(),
'uri' =>
PhabricatorEnv::getProductionURI('/'.$credential->getMonogram()),
'monogram' => $credential->getMonogram(),
'username' => $credential->getUsername(),
'material' => $material,
);
}
$result = array(
'data' => $results,
);
return $this->addPagerResults($result, $pager);
}
}
diff --git a/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php b/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php
index f1172f6915..0c09109a2c 100644
--- a/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php
+++ b/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php
@@ -1,76 +1,76 @@
<?php
final class PasteCreateConduitAPIMethod extends PasteConduitAPIMethod {
public function getAPIMethodName() {
return 'paste.create';
}
public function getMethodDescription() {
return 'Create a new paste.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'content' => 'required string',
'title' => 'optional string',
'language' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-NO-PASTE' => 'Paste may not be empty.',
);
}
protected function execute(ConduitAPIRequest $request) {
$content = $request->getValue('content');
$title = $request->getValue('title');
$language = $request->getValue('language');
if (!strlen($content)) {
throw new ConduitException('ERR-NO-PASTE');
}
$title = nonempty($title, 'Masterwork From Distant Lands');
$language = nonempty($language, '');
$viewer = $request->getUser();
$paste = PhabricatorPaste::initializeNewPaste($viewer);
$file = PhabricatorPasteEditor::initializeFileForPaste(
$viewer,
$title,
$content);
$xactions = array();
$xactions[] = id(new PhabricatorPasteTransaction())
->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
->setNewValue($file->getPHID());
$xactions[] = id(new PhabricatorPasteTransaction())
->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
->setNewValue($title);
$xactions[] = id(new PhabricatorPasteTransaction())
->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)
->setNewValue($language);
$editor = id(new PhabricatorPasteEditor())
->setActor($viewer)
->setContentSourceFromConduitRequest($request);
$xactions = $editor->applyTransactions($paste, $xactions);
$paste->attachRawContent($content);
return $this->buildPasteInfoDictionary($paste);
}
}
diff --git a/src/applications/paste/conduit/PasteInfoConduitAPIMethod.php b/src/applications/paste/conduit/PasteInfoConduitAPIMethod.php
index 574391461e..ea39b9c18c 100644
--- a/src/applications/paste/conduit/PasteInfoConduitAPIMethod.php
+++ b/src/applications/paste/conduit/PasteInfoConduitAPIMethod.php
@@ -1,50 +1,50 @@
<?php
final class PasteInfoConduitAPIMethod extends PasteConduitAPIMethod {
public function getAPIMethodName() {
return 'paste.info';
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodStatusDescription() {
return "Replaced by 'paste.query'.";
}
public function getMethodDescription() {
return 'Retrieve an array of information about a paste.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'paste_id' => 'required id',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BAD_PASTE' => 'No such paste exists',
);
}
protected function execute(ConduitAPIRequest $request) {
$paste_id = $request->getValue('paste_id');
$paste = id(new PhabricatorPasteQuery())
->setViewer($request->getUser())
->withIDs(array($paste_id))
->needRawContent(true)
->executeOne();
if (!$paste) {
throw new ConduitException('ERR_BAD_PASTE');
}
return $this->buildPasteInfoDictionary($paste);
}
}
diff --git a/src/applications/paste/conduit/PasteQueryConduitAPIMethod.php b/src/applications/paste/conduit/PasteQueryConduitAPIMethod.php
index a8bcf9c574..b03079245a 100644
--- a/src/applications/paste/conduit/PasteQueryConduitAPIMethod.php
+++ b/src/applications/paste/conduit/PasteQueryConduitAPIMethod.php
@@ -1,67 +1,63 @@
<?php
final class PasteQueryConduitAPIMethod extends PasteConduitAPIMethod {
public function getAPIMethodName() {
return 'paste.query';
}
public function getMethodDescription() {
return 'Query Pastes.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<int>',
'phids' => 'optional list<phid>',
'authorPHIDs' => 'optional list<phid>',
'after' => 'optional int',
'limit' => 'optional int, default = 100',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$query = id(new PhabricatorPasteQuery())
->setViewer($request->getUser())
->needRawContent(true);
if ($request->getValue('ids')) {
$query->withIDs($request->getValue('ids'));
}
if ($request->getValue('phids')) {
$query->withPHIDs($request->getValue('phids'));
}
if ($request->getValue('authorPHIDs')) {
$query->withAuthorPHIDs($request->getValue('authorPHIDs'));
}
if ($request->getValue('after')) {
$query->setAfterID($request->getValue('after'));
}
$limit = $request->getValue('limit', 100);
if ($limit) {
$query->setLimit($limit);
}
$pastes = $query->execute();
$results = array();
foreach ($pastes as $paste) {
$results[$paste->getPHID()] = $this->buildPasteInfoDictionary($paste);
}
return $results;
}
}
diff --git a/src/applications/people/conduit/UserAddStatusConduitAPIMethod.php b/src/applications/people/conduit/UserAddStatusConduitAPIMethod.php
index d3d9a6c8cf..71ddd26997 100644
--- a/src/applications/people/conduit/UserAddStatusConduitAPIMethod.php
+++ b/src/applications/people/conduit/UserAddStatusConduitAPIMethod.php
@@ -1,66 +1,66 @@
<?php
final class UserAddStatusConduitAPIMethod extends UserConduitAPIMethod {
public function getAPIMethodName() {
return 'user.addstatus';
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodDescription() {
return pht('Add status information to the logged-in user.');
}
public function getMethodStatusDescription() {
return pht(
'Statuses are becoming full-fledged events as part of the '.
'Calendar application.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$status_const = $this->formatStringConstants(array('away', 'sporadic'));
return array(
'fromEpoch' => 'required int',
'toEpoch' => 'required int',
'status' => 'required '.$status_const,
'description' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-BAD-EPOCH' => "'toEpoch' must be bigger than 'fromEpoch'.",
'ERR-OVERLAP' =>
'There must be no status in any part of the specified epoch.',
);
}
protected function execute(ConduitAPIRequest $request) {
$user_phid = $request->getUser()->getPHID();
$from = $request->getValue('fromEpoch');
$to = $request->getValue('toEpoch');
$status = $request->getValue('status');
$description = $request->getValue('description', '');
try {
id(new PhabricatorCalendarEvent())
->setUserPHID($user_phid)
->setDateFrom($from)
->setDateTo($to)
->setTextStatus($status)
->setDescription($description)
->save();
} catch (PhabricatorCalendarEventInvalidEpochException $e) {
throw new ConduitException('ERR-BAD-EPOCH');
}
}
}
diff --git a/src/applications/people/conduit/UserDisableConduitAPIMethod.php b/src/applications/people/conduit/UserDisableConduitAPIMethod.php
index 22925b16c6..6d9850a8ab 100644
--- a/src/applications/people/conduit/UserDisableConduitAPIMethod.php
+++ b/src/applications/people/conduit/UserDisableConduitAPIMethod.php
@@ -1,53 +1,53 @@
<?php
final class UserDisableConduitAPIMethod extends UserConduitAPIMethod {
public function getAPIMethodName() {
return 'user.disable';
}
public function getMethodDescription() {
return 'Permanently disable specified users (admin only).';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'phids' => 'required list<phid>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-PERMISSIONS' => 'Only admins can call this method.',
'ERR-BAD-PHID' => 'Non existent user PHID.',
);
}
protected function execute(ConduitAPIRequest $request) {
$actor = $request->getUser();
if (!$actor->getIsAdmin()) {
throw new ConduitException('ERR-PERMISSIONS');
}
$phids = $request->getValue('phids');
$users = id(new PhabricatorUser())->loadAllWhere(
'phid IN (%Ls)',
$phids);
if (count($phids) != count($users)) {
throw new ConduitException('ERR-BAD-PHID');
}
foreach ($users as $user) {
id(new PhabricatorUserEditor())
->setActor($actor)
->disableUser($user, true);
}
}
}
diff --git a/src/applications/people/conduit/UserEnableConduitAPIMethod.php b/src/applications/people/conduit/UserEnableConduitAPIMethod.php
index 2f785e91d0..e29ce3ca61 100644
--- a/src/applications/people/conduit/UserEnableConduitAPIMethod.php
+++ b/src/applications/people/conduit/UserEnableConduitAPIMethod.php
@@ -1,53 +1,53 @@
<?php
final class UserEnableConduitAPIMethod extends UserConduitAPIMethod {
public function getAPIMethodName() {
return 'user.enable';
}
public function getMethodDescription() {
return 'Re-enable specified users (admin only).';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'phids' => 'required list<phid>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-PERMISSIONS' => 'Only admins can call this method.',
'ERR-BAD-PHID' => 'Non existent user PHID.',
);
}
protected function execute(ConduitAPIRequest $request) {
$actor = $request->getUser();
if (!$actor->getIsAdmin()) {
throw new ConduitException('ERR-PERMISSIONS');
}
$phids = $request->getValue('phids');
$users = id(new PhabricatorUser())->loadAllWhere(
'phid IN (%Ls)',
$phids);
if (count($phids) != count($users)) {
throw new ConduitException('ERR-BAD-PHID');
}
foreach ($users as $user) {
id(new PhabricatorUserEditor())
->setActor($actor)
->disableUser($user, false);
}
}
}
diff --git a/src/applications/people/conduit/UserFindConduitAPIMethod.php b/src/applications/people/conduit/UserFindConduitAPIMethod.php
index afb6d0c1c8..06f124d3a3 100644
--- a/src/applications/people/conduit/UserFindConduitAPIMethod.php
+++ b/src/applications/people/conduit/UserFindConduitAPIMethod.php
@@ -1,45 +1,40 @@
<?php
final class UserFindConduitAPIMethod extends UserConduitAPIMethod {
public function getAPIMethodName() {
return 'user.find';
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodStatusDescription() {
return pht('Obsoleted by "user.query".');
}
public function getMethodDescription() {
return pht('Lookup PHIDs by username. Obsoleted by "user.query".');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'aliases' => 'required list<string>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict<string, phid>';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$users = id(new PhabricatorPeopleQuery())
->setViewer($request->getUser())
->withUsernames($request->getValue('aliases', array()))
->execute();
return mpull($users, 'getPHID', 'getUsername');
}
}
diff --git a/src/applications/people/conduit/UserQueryConduitAPIMethod.php b/src/applications/people/conduit/UserQueryConduitAPIMethod.php
index 1678c88246..5c81fd5d4f 100644
--- a/src/applications/people/conduit/UserQueryConduitAPIMethod.php
+++ b/src/applications/people/conduit/UserQueryConduitAPIMethod.php
@@ -1,83 +1,83 @@
<?php
final class UserQueryConduitAPIMethod extends UserConduitAPIMethod {
public function getAPIMethodName() {
return 'user.query';
}
public function getMethodDescription() {
return 'Query users.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'usernames' => 'optional list<string>',
'emails' => 'optional list<string>',
'realnames' => 'optional list<string>',
'phids' => 'optional list<phid>',
'ids' => 'optional list<uint>',
'offset' => 'optional int',
'limit' => 'optional int (default = 100)',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-INVALID-PARAMETER' => 'Missing or malformed parameter.',
);
}
protected function execute(ConduitAPIRequest $request) {
$usernames = $request->getValue('usernames', array());
$emails = $request->getValue('emails', array());
$realnames = $request->getValue('realnames', array());
$phids = $request->getValue('phids', array());
$ids = $request->getValue('ids', array());
$offset = $request->getValue('offset', 0);
$limit = $request->getValue('limit', 100);
$query = id(new PhabricatorPeopleQuery())
->setViewer($request->getUser())
->needProfileImage(true);
if ($usernames) {
$query->withUsernames($usernames);
}
if ($emails) {
$query->withEmails($emails);
}
if ($realnames) {
$query->withRealnames($realnames);
}
if ($phids) {
$query->withPHIDs($phids);
}
if ($ids) {
$query->withIDs($ids);
}
if ($limit) {
$query->setLimit($limit);
}
if ($offset) {
$query->setOffset($offset);
}
$users = $query->execute();
$statuses = id(new PhabricatorCalendarEvent())->loadCurrentStatuses(
mpull($users, 'getPHID'));
$results = array();
foreach ($users as $user) {
$results[] = $this->buildUserInformationDictionary(
$user,
idx($statuses, $user->getPHID()));
}
return $results;
}
}
diff --git a/src/applications/people/conduit/UserRemoveStatusConduitAPIMethod.php b/src/applications/people/conduit/UserRemoveStatusConduitAPIMethod.php
index 3acabd0916..9cb83db1c1 100644
--- a/src/applications/people/conduit/UserRemoveStatusConduitAPIMethod.php
+++ b/src/applications/people/conduit/UserRemoveStatusConduitAPIMethod.php
@@ -1,85 +1,85 @@
<?php
final class UserRemoveStatusConduitAPIMethod extends UserConduitAPIMethod {
public function getAPIMethodName() {
return 'user.removestatus';
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodDescription() {
return pht('Delete status information of the logged-in user.');
}
public function getMethodStatusDescription() {
return pht(
'Statuses are becoming full-fledged events as part of the '.
'Calendar application.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'fromEpoch' => 'required int',
'toEpoch' => 'required int',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'int';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-BAD-EPOCH' => "'toEpoch' must be bigger than 'fromEpoch'.",
);
}
protected function execute(ConduitAPIRequest $request) {
$user_phid = $request->getUser()->getPHID();
$from = $request->getValue('fromEpoch');
$to = $request->getValue('toEpoch');
if ($to <= $from) {
throw new ConduitException('ERR-BAD-EPOCH');
}
$table = new PhabricatorCalendarEvent();
$table->openTransaction();
$table->beginReadLocking();
$overlap = $table->loadAllWhere(
'userPHID = %s AND dateFrom < %d AND dateTo > %d',
$user_phid,
$to,
$from);
foreach ($overlap as $status) {
if ($status->getDateFrom() < $from) {
if ($status->getDateTo() > $to) {
// Split the interval.
id(new PhabricatorCalendarEvent())
->setUserPHID($user_phid)
->setDateFrom($to)
->setDateTo($status->getDateTo())
->setStatus($status->getStatus())
->setDescription($status->getDescription())
->save();
}
$status->setDateTo($from);
$status->save();
} else if ($status->getDateTo() > $to) {
$status->setDateFrom($to);
$status->save();
} else {
$status->delete();
}
}
$table->endReadLocking();
$table->saveTransaction();
return count($overlap);
}
}
diff --git a/src/applications/people/conduit/UserWhoAmIConduitAPIMethod.php b/src/applications/people/conduit/UserWhoAmIConduitAPIMethod.php
index 97023bebd4..aa7e3e7f26 100644
--- a/src/applications/people/conduit/UserWhoAmIConduitAPIMethod.php
+++ b/src/applications/people/conduit/UserWhoAmIConduitAPIMethod.php
@@ -1,39 +1,35 @@
<?php
final class UserWhoAmIConduitAPIMethod extends UserConduitAPIMethod {
public function getAPIMethodName() {
return 'user.whoami';
}
public function getMethodDescription() {
return 'Retrieve information about the logged-in user.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict<string, wild>';
}
- public function defineErrorTypes() {
- return array();
- }
-
public function getRequiredScope() {
return PhabricatorOAuthServerScope::SCOPE_WHOAMI;
}
protected function execute(ConduitAPIRequest $request) {
$person = id(new PhabricatorPeopleQuery())
->setViewer($request->getUser())
->needProfileImage(true)
->withPHIDs(array($request->getUser()->getPHID()))
->executeOne();
return $this->buildUserInformationDictionary($person);
}
}
diff --git a/src/applications/phame/conduit/PhameCreatePostConduitAPIMethod.php b/src/applications/phame/conduit/PhameCreatePostConduitAPIMethod.php
index 2515b185cc..bdee6e2829 100644
--- a/src/applications/phame/conduit/PhameCreatePostConduitAPIMethod.php
+++ b/src/applications/phame/conduit/PhameCreatePostConduitAPIMethod.php
@@ -1,103 +1,103 @@
<?php
final class PhameCreatePostConduitAPIMethod extends PhameConduitAPIMethod {
public function getAPIMethodName() {
return 'phame.createpost';
}
public function getMethodDescription() {
return pht('Create a phame post.');
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'blogPHID' => 'required phid',
'title' => 'required string',
'body' => 'required string',
'phameTitle' => 'optional string',
'bloggerPHID' => 'optional phid',
'isDraft' => 'optional bool',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-INVALID-PARAMETER' =>
pht('Missing or malformed parameter.'),
'ERR-INVALID-BLOG' =>
pht('Invalid blog PHID or user can not post to blog.'),
);
}
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser();
$blog_phid = $request->getValue('blogPHID');
$title = $request->getValue('title');
$body = $request->getValue('body');
$exception_description = array();
if (!$blog_phid) {
$exception_description[] = pht('No blog phid.');
}
if (!strlen($title)) {
$exception_description[] = pht('No post title.');
}
if (!strlen($body)) {
$exception_description[] = pht('No post body.');
}
if ($exception_description) {
throw id(new ConduitException('ERR-INVALID-PARAMETER'))
->setErrorDescription(implode("\n", $exception_description));
}
$blogger_phid = $request->getValue('bloggerPHID');
if ($blogger_phid) {
$blogger = id(new PhabricatorPeopleQuery())
->setViewer($user)
->withPHIDs(array($blogger_phid))
->executeOne();
} else {
$blogger = $user;
}
$blog = id(new PhameBlogQuery())
->setViewer($blogger)
->withPHIDs(array($blog_phid))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_JOIN,
))
->executeOne();
if (!$blog) {
throw new ConduitException('ERR-INVALID-BLOG');
}
$post = PhamePost::initializePost($blogger, $blog);
$is_draft = $request->getValue('isDraft', false);
if (!$is_draft) {
$post->setDatePublished(time());
$post->setVisibility(PhamePost::VISIBILITY_PUBLISHED);
}
$post->setTitle($title);
$phame_title = $request->getValue(
'phameTitle',
id(new PhutilUTF8StringTruncator())
->setMaximumBytes(64)
->truncateString($title));
$post->setPhameTitle(PhabricatorSlug::normalize($phame_title));
$post->setBody($body);
$post->save();
return $post->toDictionary();
}
}
diff --git a/src/applications/phame/conduit/PhameQueryConduitAPIMethod.php b/src/applications/phame/conduit/PhameQueryConduitAPIMethod.php
index a1a4d196e9..8b882674a3 100644
--- a/src/applications/phame/conduit/PhameQueryConduitAPIMethod.php
+++ b/src/applications/phame/conduit/PhameQueryConduitAPIMethod.php
@@ -1,82 +1,78 @@
<?php
final class PhameQueryConduitAPIMethod extends PhameConduitAPIMethod {
public function getAPIMethodName() {
return 'phame.query';
}
public function getMethodDescription() {
return 'Query phame blogs.';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<int>',
'phids' => 'optional list<phid>',
'after' => 'optional int',
'before' => 'optional int',
'limit' => 'optional int',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$query = new PhameBlogQuery();
$query->setViewer($request->getUser());
$ids = $request->getValue('ids', array());
if ($ids) {
$query->withIDs($ids);
}
$phids = $request->getValue('phids', array());
if ($phids) {
$query->withPHIDs($phids);
}
$after = $request->getValue('after', null);
if ($after !== null) {
$query->setAfterID($after);
}
$before = $request->getValue('before', null);
if ($before !== null) {
$query->setBeforeID($before);
}
$limit = $request->getValue('limit', null);
if ($limit !== null) {
$query->setLimit($limit);
}
$blogs = $query->execute();
$results = array();
foreach ($blogs as $blog) {
$results[] = array(
'id' => $blog->getID(),
'phid' => $blog->getPHID(),
'name' => $blog->getName(),
'description' => $blog->getDescription(),
'domain' => $blog->getDomain(),
'creatorPHID' => $blog->getCreatorPHID(),
);
}
return $results;
}
}
diff --git a/src/applications/phame/conduit/PhameQueryPostsConduitAPIMethod.php b/src/applications/phame/conduit/PhameQueryPostsConduitAPIMethod.php
index 2fd95ec3db..822c32a8da 100644
--- a/src/applications/phame/conduit/PhameQueryPostsConduitAPIMethod.php
+++ b/src/applications/phame/conduit/PhameQueryPostsConduitAPIMethod.php
@@ -1,108 +1,103 @@
<?php
final class PhameQueryPostsConduitAPIMethod extends PhameConduitAPIMethod {
public function getAPIMethodName() {
return 'phame.queryposts';
}
public function getMethodDescription() {
return 'Query phame posts.';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<int>',
'phids' => 'optional list<phid>',
'blogPHIDs' => 'optional list<phid>',
'bloggerPHIDs' => 'optional list<phid>',
'phameTitles' => 'optional list<string>',
'published' => 'optional bool',
'publishedAfter' => 'optional date',
'before' => 'optional int',
'after' => 'optional int',
'limit' => 'optional int',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$query = new PhamePostQuery();
$query->setViewer($request->getUser());
$ids = $request->getValue('ids', array());
if ($ids) {
$query->withIDs($ids);
}
$phids = $request->getValue('phids', array());
if ($phids) {
$query->withPHIDs($phids);
}
$blog_phids = $request->getValue('blogPHIDs', array());
if ($blog_phids) {
$query->withBlogPHIDs($blog_phids);
}
$blogger_phids = $request->getValue('bloggerPHIDs', array());
if ($blogger_phids) {
$query->withBloggerPHIDs($blogger_phids);
}
$phame_titles = $request->getValue('phameTitles', array());
if ($phame_titles) {
$query->withPhameTitles($phame_titles);
}
$published = $request->getValue('published', null);
if ($published === true) {
$query->withVisibility(PhamePost::VISIBILITY_PUBLISHED);
} else if ($published === false) {
$query->withVisibility(PhamePost::VISIBILITY_DRAFT);
}
$published_after = $request->getValue('publishedAfter', null);
if ($published_after !== null) {
$query->withPublishedAfter($published_after);
}
$after = $request->getValue('after', null);
if ($after !== null) {
$query->setAfterID($after);
}
$before = $request->getValue('before', null);
if ($before !== null) {
$query->setBeforeID($before);
}
$limit = $request->getValue('limit', null);
if ($limit !== null) {
$query->setLimit($limit);
}
$posts = $query->execute();
$results = array();
foreach ($posts as $post) {
$results[] = $post->toDictionary();
}
return $results;
}
}
diff --git a/src/applications/phid/conduit/PHIDInfoConduitAPIMethod.php b/src/applications/phid/conduit/PHIDInfoConduitAPIMethod.php
index 6c6282a4e7..465697c60e 100644
--- a/src/applications/phid/conduit/PHIDInfoConduitAPIMethod.php
+++ b/src/applications/phid/conduit/PHIDInfoConduitAPIMethod.php
@@ -1,52 +1,52 @@
<?php
final class PHIDInfoConduitAPIMethod extends PHIDConduitAPIMethod {
public function getAPIMethodName() {
return 'phid.info';
}
public function getMethodStatus() {
return self::METHOD_STATUS_DEPRECATED;
}
public function getMethodStatusDescription() {
return "Replaced by 'phid.query'.";
}
public function getMethodDescription() {
return 'Retrieve information about an arbitrary PHID.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'phid' => 'required phid',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict<string, wild>';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-BAD-PHID' => 'No such object exists.',
);
}
protected function execute(ConduitAPIRequest $request) {
$phid = $request->getValue('phid');
$handle = id(new PhabricatorHandleQuery())
->setViewer($request->getUser())
->withPHIDs(array($phid))
->executeOne();
if (!$handle->isComplete()) {
throw new ConduitException('ERR-BAD-PHID');
}
return $this->buildHandleInformationDictionary($handle);
}
}
diff --git a/src/applications/phid/conduit/PHIDLookupConduitAPIMethod.php b/src/applications/phid/conduit/PHIDLookupConduitAPIMethod.php
index ecf3f12db2..73196daaff 100644
--- a/src/applications/phid/conduit/PHIDLookupConduitAPIMethod.php
+++ b/src/applications/phid/conduit/PHIDLookupConduitAPIMethod.php
@@ -1,51 +1,47 @@
<?php
final class PHIDLookupConduitAPIMethod extends PHIDConduitAPIMethod {
public function getAPIMethodName() {
return 'phid.lookup';
}
public function getMethodDescription() {
return 'Look up objects by name.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'names' => 'required list<string>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict<string, wild>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$names = $request->getValue('names');
$query = id(new PhabricatorObjectQuery())
->setViewer($request->getUser())
->withNames($names);
$query->execute();
$name_map = $query->getNamedResults();
$handles = id(new PhabricatorHandleQuery())
->setViewer($request->getUser())
->withPHIDs(mpull($name_map, 'getPHID'))
->execute();
$result = array();
foreach ($name_map as $name => $object) {
$phid = $object->getPHID();
$handle = $handles[$phid];
$result[$name] = $this->buildHandleInformationDictionary($handle);
}
return $result;
}
}
diff --git a/src/applications/phid/conduit/PHIDQueryConduitAPIMethod.php b/src/applications/phid/conduit/PHIDQueryConduitAPIMethod.php
index e90f605985..69b6fe0acb 100644
--- a/src/applications/phid/conduit/PHIDQueryConduitAPIMethod.php
+++ b/src/applications/phid/conduit/PHIDQueryConduitAPIMethod.php
@@ -1,45 +1,41 @@
<?php
final class PHIDQueryConduitAPIMethod extends PHIDConduitAPIMethod {
public function getAPIMethodName() {
return 'phid.query';
}
public function getMethodDescription() {
return 'Retrieve information about arbitrary PHIDs.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'phids' => 'required list<phid>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict<string, wild>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$phids = $request->getValue('phids');
$handles = id(new PhabricatorHandleQuery())
->setViewer($request->getUser())
->withPHIDs($phids)
->execute();
$result = array();
foreach ($handles as $phid => $handle) {
if ($handle->isComplete()) {
$result[$phid] = $this->buildHandleInformationDictionary($handle);
}
}
return $result;
}
}
diff --git a/src/applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php b/src/applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php
index 186b8ed4c8..dedf00e1eb 100644
--- a/src/applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php
+++ b/src/applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php
@@ -1,189 +1,189 @@
<?php
final class PhragmentGetPatchConduitAPIMethod
extends PhragmentConduitAPIMethod {
public function getAPIMethodName() {
return 'phragment.getpatch';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return pht('Retrieve the patches to apply for a given set of files.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'path' => 'required string',
'state' => 'required dict<string, string>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BAD_FRAGMENT' => 'No such fragment exists',
);
}
protected function execute(ConduitAPIRequest $request) {
$path = $request->getValue('path');
$state = $request->getValue('state');
// The state is an array mapping file paths to hashes.
$patches = array();
// We need to get all of the mappings (like phragment.getstate) first
// so that we can detect deletions and creations of files.
$fragment = id(new PhragmentFragmentQuery())
->setViewer($request->getUser())
->withPaths(array($path))
->executeOne();
if ($fragment === null) {
throw new ConduitException('ERR_BAD_FRAGMENT');
}
$mappings = $fragment->getFragmentMappings(
$request->getUser(),
$fragment->getPath());
$file_phids = mpull(mpull($mappings, 'getLatestVersion'), 'getFilePHID');
$files = id(new PhabricatorFileQuery())
->setViewer($request->getUser())
->withPHIDs($file_phids)
->execute();
$files = mpull($files, null, 'getPHID');
// Scan all of the files that the caller currently has and iterate
// over that.
foreach ($state as $path => $hash) {
// If $mappings[$path] exists, then the user has the file and it's
// also a fragment.
if (array_key_exists($path, $mappings)) {
$file_phid = $mappings[$path]->getLatestVersion()->getFilePHID();
if ($file_phid !== null) {
// If the file PHID is present, then we need to check the
// hashes to see if they are the same.
$hash_caller = strtolower($state[$path]);
$hash_current = $files[$file_phid]->getContentHash();
if ($hash_caller === $hash_current) {
// The user's version is identical to our version, so
// there is no update needed.
} else {
// The hash differs, and the user needs to update.
$patches[] = array(
'path' => $path,
'fileOld' => null,
'fileNew' => $files[$file_phid],
'hashOld' => $hash_caller,
'hashNew' => $hash_current,
'patchURI' => null,
);
}
} else {
// We have a record of this as a file, but there is no file
// attached to the latest version, so we consider this to be
// a deletion.
$patches[] = array(
'path' => $path,
'fileOld' => null,
'fileNew' => null,
'hashOld' => $hash_caller,
'hashNew' => PhragmentPatchUtil::EMPTY_HASH,
'patchURI' => null,
);
}
} else {
// If $mappings[$path] does not exist, then the user has a file,
// and we have absolutely no record of it what-so-ever (we haven't
// even recorded a deletion). Assuming most applications will store
// some form of data near their own files, this is probably a data
// file relevant for the application that is not versioned, so we
// don't tell the client to do anything with it.
}
}
// Check the remaining files that we know about but the caller has
// not reported.
foreach ($mappings as $path => $child) {
if (array_key_exists($path, $state)) {
// We have already evaluated this above.
} else {
$file_phid = $mappings[$path]->getLatestVersion()->getFilePHID();
if ($file_phid !== null) {
// If the file PHID is present, then this is a new file that
// we know about, but the caller does not. We need to tell
// the caller to create the file.
$hash_current = $files[$file_phid]->getContentHash();
$patches[] = array(
'path' => $path,
'fileOld' => null,
'fileNew' => $files[$file_phid],
'hashOld' => PhragmentPatchUtil::EMPTY_HASH,
'hashNew' => $hash_current,
'patchURI' => null,
);
} else {
// We have a record of deleting this file, and the caller hasn't
// reported it, so they've probably deleted it in a previous
// update.
}
}
}
// Before we can calculate patches, we need to resolve the old versions
// of files so we can draw diffs on them.
$hashes = array();
foreach ($patches as $patch) {
if ($patch['hashOld'] !== PhragmentPatchUtil::EMPTY_HASH) {
$hashes[] = $patch['hashOld'];
}
}
$old_files = array();
if (count($hashes) !== 0) {
$old_files = id(new PhabricatorFileQuery())
->setViewer($request->getUser())
->withContentHashes($hashes)
->execute();
}
$old_files = mpull($old_files, null, 'getContentHash');
foreach ($patches as $key => $patch) {
if ($patch['hashOld'] !== PhragmentPatchUtil::EMPTY_HASH) {
if (array_key_exists($patch['hashOld'], $old_files)) {
$patches[$key]['fileOld'] = $old_files[$patch['hashOld']];
} else {
// We either can't see or can't read the old file.
$patches[$key]['hashOld'] = PhragmentPatchUtil::EMPTY_HASH;
$patches[$key]['fileOld'] = null;
}
}
}
// Now run through all of the patch entries, calculate the patches
// and return the results.
foreach ($patches as $key => $patch) {
$data = PhragmentPatchUtil::calculatePatch(
$patches[$key]['fileOld'],
$patches[$key]['fileNew']);
unset($patches[$key]['fileOld']);
unset($patches[$key]['fileNew']);
$file = PhabricatorFile::buildFromFileDataOrHash(
$data,
array(
'name' => 'patch.dmp',
'ttl' => time() + 60 * 60 * 24,
));
$patches[$key]['patchURI'] = $file->getDownloadURI();
}
return $patches;
}
}
diff --git a/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php b/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php
index f4aafd3105..27ddac1d36 100644
--- a/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php
+++ b/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php
@@ -1,85 +1,85 @@
<?php
final class PhragmentQueryFragmentsConduitAPIMethod
extends PhragmentConduitAPIMethod {
public function getAPIMethodName() {
return 'phragment.queryfragments';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return pht('Query fragments based on their paths.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'paths' => 'required list<string>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BAD_FRAGMENT' => 'No such fragment exists',
);
}
protected function execute(ConduitAPIRequest $request) {
$paths = $request->getValue('paths');
$fragments = id(new PhragmentFragmentQuery())
->setViewer($request->getUser())
->withPaths($paths)
->execute();
$fragments = mpull($fragments, null, 'getPath');
foreach ($paths as $path) {
if (!array_key_exists($path, $fragments)) {
throw new ConduitException('ERR_BAD_FRAGMENT');
}
}
$results = array();
foreach ($fragments as $path => $fragment) {
$mappings = $fragment->getFragmentMappings(
$request->getUser(),
$fragment->getPath());
$file_phids = mpull(mpull($mappings, 'getLatestVersion'), 'getFilePHID');
$files = id(new PhabricatorFileQuery())
->setViewer($request->getUser())
->withPHIDs($file_phids)
->execute();
$files = mpull($files, null, 'getPHID');
$result = array();
foreach ($mappings as $cpath => $child) {
$file_phid = $child->getLatestVersion()->getFilePHID();
if (!isset($files[$file_phid])) {
// Skip any files we don't have permission to access.
continue;
}
$file = $files[$file_phid];
$cpath = substr($child->getPath(), strlen($fragment->getPath()) + 1);
$result[] = array(
'phid' => $child->getPHID(),
'phidVersion' => $child->getLatestVersionPHID(),
'path' => $cpath,
'hash' => $file->getContentHash(),
'version' => $child->getLatestVersion()->getSequence(),
'uri' => $file->getViewURI(),
);
}
$results[$path] = $result;
}
return $results;
}
}
diff --git a/src/applications/phrequent/conduit/PhrequentPopConduitAPIMethod.php b/src/applications/phrequent/conduit/PhrequentPopConduitAPIMethod.php
index 467d822d9f..59b11bbbdc 100644
--- a/src/applications/phrequent/conduit/PhrequentPopConduitAPIMethod.php
+++ b/src/applications/phrequent/conduit/PhrequentPopConduitAPIMethod.php
@@ -1,52 +1,47 @@
<?php
final class PhrequentPopConduitAPIMethod extends PhrequentConduitAPIMethod {
public function getAPIMethodName() {
return 'phrequent.pop';
}
public function getMethodDescription() {
return pht('Stop tracking time on an object by popping it from the stack.');
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'objectPHID' => 'phid',
'stopTime' => 'int',
'note' => 'string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'phid';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser();
$object_phid = $request->getValue('objectPHID');
$timestamp = $request->getValue('stopTime');
$note = $request->getValue('note');
if ($timestamp === null) {
$timestamp = time();
}
$editor = new PhrequentTrackingEditor();
if (!$object_phid) {
return $editor->stopTrackingTop($user, $timestamp, $note);
} else {
return $editor->stopTracking($user, $object_phid, $timestamp, $note);
}
}
}
diff --git a/src/applications/phrequent/conduit/PhrequentPushConduitAPIMethod.php b/src/applications/phrequent/conduit/PhrequentPushConduitAPIMethod.php
index d890f8e87c..1095aeab0d 100644
--- a/src/applications/phrequent/conduit/PhrequentPushConduitAPIMethod.php
+++ b/src/applications/phrequent/conduit/PhrequentPushConduitAPIMethod.php
@@ -1,47 +1,42 @@
<?php
final class PhrequentPushConduitAPIMethod extends PhrequentConduitAPIMethod {
public function getAPIMethodName() {
return 'phrequent.push';
}
public function getMethodDescription() {
return pht(
'Start tracking time on an object by '.
'pushing it on the tracking stack.');
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'objectPHID' => 'required phid',
'startTime' => 'int',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'phid';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser();
$object_phid = $request->getValue('objectPHID');
$timestamp = $request->getValue('startTime');
if ($timestamp === null) {
$timestamp = time();
}
$editor = new PhrequentTrackingEditor();
return $editor->startTracking($user, $object_phid, $timestamp);
}
}
diff --git a/src/applications/phrequent/conduit/PhrequentTrackingConduitAPIMethod.php b/src/applications/phrequent/conduit/PhrequentTrackingConduitAPIMethod.php
index 07f1e6a43e..f5391a56fb 100644
--- a/src/applications/phrequent/conduit/PhrequentTrackingConduitAPIMethod.php
+++ b/src/applications/phrequent/conduit/PhrequentTrackingConduitAPIMethod.php
@@ -1,50 +1,45 @@
<?php
final class PhrequentTrackingConduitAPIMethod
extends PhrequentConduitAPIMethod {
public function getAPIMethodName() {
return 'phrequent.tracking';
}
public function getMethodDescription() {
return pht(
'Returns current objects being tracked in Phrequent.');
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'array';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser();
$times = id(new PhrequentUserTimeQuery())
->setViewer($user)
->needPreemptingEvents(true)
->withEnded(PhrequentUserTimeQuery::ENDED_NO)
->withUserPHIDs(array($user->getPHID()))
->execute();
$now = time();
$results = id(new PhrequentTimeBlock($times))
->getCurrentWorkStack($now);
return array('data' => $results);
}
}
diff --git a/src/applications/phriction/conduit/PhrictionCreateConduitAPIMethod.php b/src/applications/phriction/conduit/PhrictionCreateConduitAPIMethod.php
index c0aaedf15f..e3d28941bb 100644
--- a/src/applications/phriction/conduit/PhrictionCreateConduitAPIMethod.php
+++ b/src/applications/phriction/conduit/PhrictionCreateConduitAPIMethod.php
@@ -1,70 +1,71 @@
<?php
final class PhrictionCreateConduitAPIMethod extends PhrictionConduitAPIMethod {
+
public function getAPIMethodName() {
return 'phriction.create';
}
+
public function getMethodDescription() {
return pht('Create a Phriction document.');
}
- public function defineParamTypes() {
+
+ protected function defineParamTypes() {
return array(
'slug' => 'required string',
'title' => 'required string',
'content' => 'required string',
'description' => 'optional string',
);
}
- public function defineReturnType() {
+
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
- return array(
- );
- }
+
protected function execute(ConduitAPIRequest $request) {
$slug = $request->getValue('slug');
if (!strlen($slug)) {
throw new Exception(pht('No such document.'));
}
$doc = id(new PhrictionDocumentQuery())
->setViewer($request->getUser())
->withSlugs(array(PhabricatorSlug::normalize($slug)))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if ($doc) {
throw new Exception(pht('Document already exists!'));
}
$doc = PhrictionDocument::initializeNewDocument(
$request->getUser(),
$slug);
$xactions = array();
$xactions[] = id(new PhrictionTransaction())
->setTransactionType(PhrictionTransaction::TYPE_TITLE)
->setNewValue($request->getValue('title'));
$xactions[] = id(new PhrictionTransaction())
->setTransactionType(PhrictionTransaction::TYPE_CONTENT)
->setNewValue($request->getValue('content'));
$editor = id(new PhrictionTransactionEditor())
->setActor($request->getUser())
->setContentSourceFromConduitRequest($request)
->setContinueOnNoEffect(true)
->setDescription($request->getValue('description'));
try {
$editor->applyTransactions($doc, $xactions);
} catch (PhabricatorApplicationTransactionValidationException $ex) {
// TODO - some magical hotness via T5873
throw $ex;
}
return $this->buildDocumentInfoDictionary($doc);
}
}
diff --git a/src/applications/phriction/conduit/PhrictionEditConduitAPIMethod.php b/src/applications/phriction/conduit/PhrictionEditConduitAPIMethod.php
index 1bf6b53395..f9c8c26a3e 100644
--- a/src/applications/phriction/conduit/PhrictionEditConduitAPIMethod.php
+++ b/src/applications/phriction/conduit/PhrictionEditConduitAPIMethod.php
@@ -1,72 +1,67 @@
<?php
final class PhrictionEditConduitAPIMethod extends PhrictionConduitAPIMethod {
public function getAPIMethodName() {
return 'phriction.edit';
}
public function getMethodDescription() {
return pht('Update a Phriction document.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'slug' => 'required string',
'title' => 'optional string',
'content' => 'optional string',
'description' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$slug = $request->getValue('slug');
$doc = id(new PhrictionDocumentQuery())
->setViewer($request->getUser())
->withSlugs(array(PhabricatorSlug::normalize($slug)))
->needContent(true)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$doc) {
throw new Exception(pht('No such document.'));
}
$xactions = array();
$xactions[] = id(new PhrictionTransaction())
->setTransactionType(PhrictionTransaction::TYPE_TITLE)
->setNewValue($request->getValue('title'));
$xactions[] = id(new PhrictionTransaction())
->setTransactionType(PhrictionTransaction::TYPE_CONTENT)
->setNewValue($request->getValue('content'));
$editor = id(new PhrictionTransactionEditor())
->setActor($request->getUser())
->setContentSourceFromConduitRequest($request)
->setContinueOnNoEffect(true)
->setDescription($request->getValue('description'));
try {
$editor->applyTransactions($doc, $xactions);
} catch (PhabricatorApplicationTransactionValidationException $ex) {
// TODO - some magical hotness via T5873
throw $ex;
}
return $this->buildDocumentInfoDictionary($doc);
}
}
diff --git a/src/applications/phriction/conduit/PhrictionHistoryConduitAPIMethod.php b/src/applications/phriction/conduit/PhrictionHistoryConduitAPIMethod.php
index 372ff4a97c..9a4098b5bd 100644
--- a/src/applications/phriction/conduit/PhrictionHistoryConduitAPIMethod.php
+++ b/src/applications/phriction/conduit/PhrictionHistoryConduitAPIMethod.php
@@ -1,53 +1,53 @@
<?php
final class PhrictionHistoryConduitAPIMethod extends PhrictionConduitAPIMethod {
public function getAPIMethodName() {
return 'phriction.history';
}
public function getMethodDescription() {
return pht('Retrieve history about a Phriction document.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'slug' => 'required string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty list';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-BAD-DOCUMENT' => 'No such document exists.',
);
}
protected function execute(ConduitAPIRequest $request) {
$slug = $request->getValue('slug');
$doc = id(new PhrictionDocumentQuery())
->setViewer($request->getUser())
->withSlugs(array(PhabricatorSlug::normalize($slug)))
->executeOne();
if (!$doc) {
throw new ConduitException('ERR-BAD-DOCUMENT');
}
$content = id(new PhrictionContent())->loadAllWhere(
'documentID = %d ORDER BY version DESC',
$doc->getID());
$results = array();
foreach ($content as $version) {
$results[] = $this->buildDocumentContentDictionary(
$doc,
$version);
}
return $results;
}
}
diff --git a/src/applications/phriction/conduit/PhrictionInfoConduitAPIMethod.php b/src/applications/phriction/conduit/PhrictionInfoConduitAPIMethod.php
index 33eb51dffe..14e424e83c 100644
--- a/src/applications/phriction/conduit/PhrictionInfoConduitAPIMethod.php
+++ b/src/applications/phriction/conduit/PhrictionInfoConduitAPIMethod.php
@@ -1,46 +1,46 @@
<?php
final class PhrictionInfoConduitAPIMethod extends PhrictionConduitAPIMethod {
public function getAPIMethodName() {
return 'phriction.info';
}
public function getMethodDescription() {
return pht('Retrieve information about a Phriction document.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'slug' => 'required string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-BAD-DOCUMENT' => 'No such document exists.',
);
}
protected function execute(ConduitAPIRequest $request) {
$slug = $request->getValue('slug');
$document = id(new PhrictionDocumentQuery())
->setViewer($request->getUser())
->withSlugs(array(PhabricatorSlug::normalize($slug)))
->needContent(true)
->executeOne();
if (!$document) {
throw new ConduitException('ERR-BAD-DOCUMENT');
}
return $this->buildDocumentInfoDictionary(
$document,
$document->getContent());
}
}
diff --git a/src/applications/project/conduit/ProjectCreateConduitAPIMethod.php b/src/applications/project/conduit/ProjectCreateConduitAPIMethod.php
index fef3eb7ec3..47be6aa3f9 100644
--- a/src/applications/project/conduit/ProjectCreateConduitAPIMethod.php
+++ b/src/applications/project/conduit/ProjectCreateConduitAPIMethod.php
@@ -1,64 +1,60 @@
<?php
final class ProjectCreateConduitAPIMethod extends ProjectConduitAPIMethod {
public function getAPIMethodName() {
return 'project.create';
}
public function getMethodDescription() {
return pht('Create a project.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'name' => 'required string',
'members' => 'optional list<phid>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser();
$this->requireApplicationCapability(
ProjectCreateProjectsCapability::CAPABILITY,
$user);
$project = PhabricatorProject::initializeNewProject($user);
$type_name = PhabricatorProjectTransaction::TYPE_NAME;
$members = $request->getValue('members');
$xactions = array();
$xactions[] = id(new PhabricatorProjectTransaction())
->setTransactionType($type_name)
->setNewValue($request->getValue('name'));
$xactions[] = id(new PhabricatorProjectTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue(
'edge:type',
PhabricatorProjectProjectHasMemberEdgeType::EDGECONST)
->setNewValue(
array(
'+' => array_fuse($members),
));
$editor = id(new PhabricatorProjectTransactionEditor())
->setActor($user)
->setContinueOnNoEffect(true)
->setContentSourceFromConduitRequest($request);
$editor->applyTransactions($project, $xactions);
return $this->buildProjectInfoDictionary($project);
}
}
diff --git a/src/applications/project/conduit/ProjectQueryConduitAPIMethod.php b/src/applications/project/conduit/ProjectQueryConduitAPIMethod.php
index 8818d96a1e..1f2078ff67 100644
--- a/src/applications/project/conduit/ProjectQueryConduitAPIMethod.php
+++ b/src/applications/project/conduit/ProjectQueryConduitAPIMethod.php
@@ -1,118 +1,114 @@
<?php
final class ProjectQueryConduitAPIMethod extends ProjectConduitAPIMethod {
public function getAPIMethodName() {
return 'project.query';
}
public function getMethodDescription() {
return 'Execute searches for Projects.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$statuses = array(
PhabricatorProjectQuery::STATUS_ANY,
PhabricatorProjectQuery::STATUS_OPEN,
PhabricatorProjectQuery::STATUS_CLOSED,
PhabricatorProjectQuery::STATUS_ACTIVE,
PhabricatorProjectQuery::STATUS_ARCHIVED,
);
$status_const = $this->formatStringConstants($statuses);
return array(
'ids' => 'optional list<int>',
'names' => 'optional list<string>',
'phids' => 'optional list<phid>',
'slugs' => 'optional list<string>',
'status' => 'optional '.$status_const,
'members' => 'optional list<phid>',
'limit' => 'optional int',
'offset' => 'optional int',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$query = new PhabricatorProjectQuery();
$query->setViewer($request->getUser());
$query->needMembers(true);
$query->needSlugs(true);
$ids = $request->getValue('ids');
if ($ids) {
$query->withIDs($ids);
}
$names = $request->getValue('names');
if ($names) {
$query->withNames($names);
}
$status = $request->getValue('status');
if ($status) {
$query->withStatus($status);
}
$phids = $request->getValue('phids');
if ($phids) {
$query->withPHIDs($phids);
}
$slugs = $request->getValue('slugs');
if ($slugs) {
$query->withSlugs($slugs);
}
$members = $request->getValue('members');
if ($members) {
$query->withMemberPHIDs($members);
}
$limit = $request->getValue('limit');
if ($limit) {
$query->setLimit($limit);
}
$offset = $request->getValue('offset');
if ($offset) {
$query->setOffset($offset);
}
$pager = $this->newPager($request);
$results = $query->executeWithCursorPager($pager);
$projects = $this->buildProjectInfoDictionaries($results);
// TODO: This is pretty hideous.
$slug_map = array();
if ($slugs) {
foreach ($slugs as $slug) {
$normal = rtrim(PhabricatorSlug::normalize($slug), '/');
foreach ($projects as $project) {
if (in_array($normal, $project['slugs'])) {
$slug_map[$slug] = $project['phid'];
}
}
}
}
$result = array(
'data' => $projects,
'slugMap' => $slug_map,
);
return $this->addPagerResults($result, $pager);
}
}
diff --git a/src/applications/releeph/conduit/ReleephGetBranchesConduitAPIMethod.php b/src/applications/releeph/conduit/ReleephGetBranchesConduitAPIMethod.php
index 14c1c59fe6..59e8900108 100644
--- a/src/applications/releeph/conduit/ReleephGetBranchesConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/ReleephGetBranchesConduitAPIMethod.php
@@ -1,66 +1,61 @@
<?php
final class ReleephGetBranchesConduitAPIMethod extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releeph.getbranches';
}
public function getMethodDescription() {
return 'Return information about all active Releeph branches.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty list<dict<string, wild>>';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$results = array();
$projects = id(new ReleephProductQuery())
->setViewer($request->getUser())
->withActive(1)
->execute();
foreach ($projects as $project) {
$repository = $project->getRepository();
$branches = $project->loadRelatives(
id(new ReleephBranch()),
'releephProjectID',
'getID',
'isActive = 1');
foreach ($branches as $branch) {
$full_branch_name = $branch->getName();
$cut_point_commit = $branch->loadOneRelative(
id(new PhabricatorRepositoryCommit()),
'phid',
'getCutPointCommitPHID');
$results[] = array(
'project' => $project->getName(),
'repository' => $repository->getCallsign(),
'branch' => $branch->getBasename(),
'fullBranchName' => $full_branch_name,
'symbolicName' => $branch->getSymbolicName(),
'cutPoint' => $cut_point_commit->getCommitIdentifier(),
);
}
}
return $results;
}
}
diff --git a/src/applications/releeph/conduit/ReleephProjectInfoConduitAPIMethod.php b/src/applications/releeph/conduit/ReleephProjectInfoConduitAPIMethod.php
index 821bcf00f4..f30d1070c4 100644
--- a/src/applications/releeph/conduit/ReleephProjectInfoConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/ReleephProjectInfoConduitAPIMethod.php
@@ -1,98 +1,98 @@
<?php
final class ReleephProjectInfoConduitAPIMethod extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releeph.projectinfo';
}
public function getMethodDescription() {
return
'Fetch information about all Releeph projects '.
'for a given Arcanist project.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'arcProjectName' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict<string, wild>';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_UNKNOWN_ARC' =>
"The given Arcanist project name doesn't exist in the ".
"installation of Phabricator you are accessing.",
);
}
protected function execute(ConduitAPIRequest $request) {
$arc_project_name = $request->getValue('arcProjectName');
if ($arc_project_name) {
$arc_project = id(new PhabricatorRepositoryArcanistProject())
->loadOneWhere('name = %s', $arc_project_name);
if (!$arc_project) {
throw id(new ConduitException('ERR_UNKNOWN_ARC'))
->setErrorDescription(
"Unknown Arcanist project '{$arc_project_name}': ".
"are you using the correct Conduit URI?");
}
$releeph_projects = id(new ReleephProject())
->loadAllWhere('arcanistProjectID = %d', $arc_project->getID());
} else {
$releeph_projects = id(new ReleephProject())->loadAll();
}
$releeph_projects = mfilter($releeph_projects, 'getIsActive');
$result = array();
foreach ($releeph_projects as $releeph_project) {
$selector = $releeph_project->getReleephFieldSelector();
$fields = $selector->getFieldSpecifications();
$fields_info = array();
foreach ($fields as $field) {
$field->setReleephProject($releeph_project);
if ($field->isEditable()) {
$key = $field->getKeyForConduit();
$fields_info[$key] = array(
'class' => get_class($field),
'name' => $field->getName(),
'key' => $key,
'arcHelp' => $field->renderHelpForArcanist(),
);
}
}
$releeph_branches = mfilter(
id(new ReleephBranch())
->loadAllWhere('releephProjectID = %d', $releeph_project->getID()),
'getIsActive');
$releeph_branches_struct = array();
foreach ($releeph_branches as $branch) {
$releeph_branches_struct[] = array(
'branchName' => $branch->getName(),
'projectName' => $releeph_project->getName(),
'projectPHID' => $releeph_project->getPHID(),
'branchPHID' => $branch->getPHID(),
);
}
$result[] = array(
'projectName' => $releeph_project->getName(),
'projectPHID' => $releeph_project->getPHID(),
'branches' => $releeph_branches_struct,
'fields' => $fields_info,
);
}
return $result;
}
}
diff --git a/src/applications/releeph/conduit/ReleephQueryBranchesConduitAPIMethod.php b/src/applications/releeph/conduit/ReleephQueryBranchesConduitAPIMethod.php
index 2785f06507..400bbee604 100644
--- a/src/applications/releeph/conduit/ReleephQueryBranchesConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/ReleephQueryBranchesConduitAPIMethod.php
@@ -1,77 +1,73 @@
<?php
final class ReleephQueryBranchesConduitAPIMethod
extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releeph.querybranches';
}
public function getMethodDescription() {
return pht('Query information about Releeph branches.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<id>',
'phids' => 'optional list<phid>',
'productPHIDs' => 'optional list<phid>',
) + $this->getPagerParamTypes();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'query-results';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$query = id(new ReleephBranchQuery())
->setViewer($viewer);
$ids = $request->getValue('ids');
if ($ids !== null) {
$query->withIDs($ids);
}
$phids = $request->getValue('phids');
if ($phids !== null) {
$query->withPHIDs($phids);
}
$product_phids = $request->getValue('productPHIDs');
if ($product_phids !== null) {
$query->withProductPHIDs($product_phids);
}
$pager = $this->newPager($request);
$branches = $query->executeWithCursorPager($pager);
$data = array();
foreach ($branches as $branch) {
$id = $branch->getID();
$uri = '/releeph/branch/'.$id.'/';
$uri = PhabricatorEnv::getProductionURI($uri);
$data[] = array(
'id' => $id,
'phid' => $branch->getPHID(),
'uri' => $uri,
'name' => $branch->getName(),
'productPHID' => $branch->getProduct()->getPHID(),
);
}
return $this->addPagerResults(
array(
'data' => $data,
),
$pager);
}
}
diff --git a/src/applications/releeph/conduit/ReleephQueryProductsConduitAPIMethod.php b/src/applications/releeph/conduit/ReleephQueryProductsConduitAPIMethod.php
index 8a38a732f1..fe4d1d1df9 100644
--- a/src/applications/releeph/conduit/ReleephQueryProductsConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/ReleephQueryProductsConduitAPIMethod.php
@@ -1,84 +1,80 @@
<?php
final class ReleephQueryProductsConduitAPIMethod
extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releeph.queryproducts';
}
public function getMethodDescription() {
return pht('Query information about Releeph products.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<id>',
'phids' => 'optional list<phid>',
'repositoryPHIDs' => 'optional list<phid>',
'isActive' => 'optional bool',
) + $this->getPagerParamTypes();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'query-results';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$query = id(new ReleephProductQuery())
->setViewer($viewer);
$ids = $request->getValue('ids');
if ($ids !== null) {
$query->withIDs($ids);
}
$phids = $request->getValue('phids');
if ($phids !== null) {
$query->withPHIDs($phids);
}
$repository_phids = $request->getValue('repositoryPHIDs');
if ($repository_phids !== null) {
$query->withRepositoryPHIDs($repository_phids);
}
$is_active = $request->getValue('isActive');
if ($is_active !== null) {
$query->withActive($is_active);
}
$pager = $this->newPager($request);
$products = $query->executeWithCursorPager($pager);
$data = array();
foreach ($products as $product) {
$id = $product->getID();
$uri = '/releeph/product/'.$id.'/';
$uri = PhabricatorEnv::getProductionURI($uri);
$data[] = array(
'id' => $id,
'phid' => $product->getPHID(),
'uri' => $uri,
'name' => $product->getName(),
'isActive' => (bool)$product->getIsActive(),
'repositoryPHID' => $product->getRepositoryPHID(),
);
}
return $this->addPagerResults(
array(
'data' => $data,
),
$pager);
}
}
diff --git a/src/applications/releeph/conduit/ReleephQueryRequestsConduitAPIMethod.php b/src/applications/releeph/conduit/ReleephQueryRequestsConduitAPIMethod.php
index e59f4dd9f8..5ccc8a967d 100644
--- a/src/applications/releeph/conduit/ReleephQueryRequestsConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/ReleephQueryRequestsConduitAPIMethod.php
@@ -1,81 +1,77 @@
<?php
final class ReleephQueryRequestsConduitAPIMethod
extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releeph.queryrequests';
}
public function getMethodDescription() {
return
'Return information about all Releeph requests linked to the given ids.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'revisionPHIDs' => 'optional list<phid>',
'requestedCommitPHIDs' => 'optional list<phid>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict<string, wild>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $conduit_request) {
$revision_phids = $conduit_request->getValue('revisionPHIDs');
$requested_commit_phids =
$conduit_request->getValue('requestedCommitPHIDs');
$result = array();
if (!$revision_phids && !$requested_commit_phids) {
return $result;
}
$query = new ReleephRequestQuery();
$query->setViewer($conduit_request->getUser());
if ($revision_phids) {
$query->withRequestedObjectPHIDs($revision_phids);
} else if ($requested_commit_phids) {
$query->withRequestedCommitPHIDs($requested_commit_phids);
}
$releeph_requests = $query->execute();
foreach ($releeph_requests as $releeph_request) {
$branch = $releeph_request->getBranch();
$request_commit_phid = $releeph_request->getRequestCommitPHID();
$object = $releeph_request->getRequestedObject();
if ($object instanceof DifferentialRevision) {
$object_phid = $object->getPHID();
} else {
$object_phid = null;
}
$status = $releeph_request->getStatus();
$status_name = ReleephRequestStatus::getStatusDescriptionFor($status);
$url = PhabricatorEnv::getProductionURI('/RQ'.$releeph_request->getID());
$result[] = array(
'branchBasename' => $branch->getBasename(),
'branchSymbolic' => $branch->getSymbolicName(),
'requestID' => $releeph_request->getID(),
'revisionPHID' => $object_phid,
'status' => $status,
'status_name' => $status_name,
'url' => $url,
);
}
return $result;
}
}
diff --git a/src/applications/releeph/conduit/ReleephRequestConduitAPIMethod.php b/src/applications/releeph/conduit/ReleephRequestConduitAPIMethod.php
index bc084b206d..f60e40894b 100644
--- a/src/applications/releeph/conduit/ReleephRequestConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/ReleephRequestConduitAPIMethod.php
@@ -1,169 +1,169 @@
<?php
final class ReleephRequestConduitAPIMethod extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releeph.request';
}
public function getMethodDescription() {
return 'Request a commit or diff to be picked to a branch.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'branchPHID' => 'required string',
'things' => 'required list<string>',
'fields' => 'dict<string, string>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict<string, wild>';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BRANCH' => 'Unknown Releeph branch.',
'ERR_FIELD_PARSE' => 'Unable to parse a Releeph field.',
);
}
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser();
$viewer_handle = id(new PhabricatorHandleQuery())
->setViewer($user)
->withPHIDs(array($user->getPHID()))
->executeOne();
$branch_phid = $request->getValue('branchPHID');
$releeph_branch = id(new ReleephBranchQuery())
->setViewer($user)
->withPHIDs(array($branch_phid))
->executeOne();
if (!$releeph_branch) {
throw id(new ConduitException('ERR_BRANCH'))->setErrorDescription(
"No ReleephBranch found with PHID {$branch_phid}!");
}
$releeph_project = $releeph_branch->getProduct();
// Find the requested commit identifiers
$requested_commits = array();
$requested_object_phids = array();
$things = $request->getValue('things');
$finder = id(new ReleephCommitFinder())
->setUser($user)
->setReleephProject($releeph_project);
foreach ($things as $thing) {
try {
$requested_commits[$thing] = $finder->fromPartial($thing);
$object_phid = $finder->getRequestedObjectPHID();
if (!$object_phid) {
$object_phid = $requested_commits[$thing]->getPHID();
}
$requested_object_phids[$thing] = $object_phid;
} catch (ReleephCommitFinderException $ex) {
throw id(new ConduitException('ERR_NO_MATCHES'))
->setErrorDescription($ex->getMessage());
}
}
$requested_commit_phids = mpull($requested_commits, 'getPHID');
// Find any existing requests that clash on the commit id, for this branch
$existing_releeph_requests = id(new ReleephRequest())->loadAllWhere(
'requestCommitPHID IN (%Ls) AND branchID = %d',
$requested_commit_phids,
$releeph_branch->getID());
$existing_releeph_requests = mpull(
$existing_releeph_requests,
null,
'getRequestCommitPHID');
$selector = $releeph_project->getReleephFieldSelector();
$fields = $selector->getFieldSpecifications();
foreach ($fields as $field) {
$field
->setReleephProject($releeph_project)
->setReleephBranch($releeph_branch);
}
$results = array();
$handles = id(new PhabricatorHandleQuery())
->setViewer($user)
->withPHIDs($requested_commit_phids)
->execute();
foreach ($requested_commits as $thing => $commit) {
$phid = $commit->getPHID();
$name = id($handles[$phid])->getName();
$releeph_request = null;
$existing_releeph_request = idx($existing_releeph_requests, $phid);
if ($existing_releeph_request) {
$releeph_request = $existing_releeph_request;
} else {
$releeph_request = id(new ReleephRequest())
->setRequestUserPHID($user->getPHID())
->setBranchID($releeph_branch->getID())
->setInBranch(0)
->setRequestedObjectPHID($requested_object_phids[$thing]);
$xactions = array();
$xactions[] = id(new ReleephRequestTransaction())
->setTransactionType(ReleephRequestTransaction::TYPE_REQUEST)
->setNewValue($commit->getPHID());
$xactions[] = id(new ReleephRequestTransaction())
->setTransactionType(ReleephRequestTransaction::TYPE_USER_INTENT)
->setMetadataValue('userPHID', $user->getPHID())
->setMetadataValue(
'isAuthoritative',
$releeph_project->isAuthoritative($user))
->setNewValue(ReleephRequest::INTENT_WANT);
foreach ($fields as $field) {
if (!$field->isEditable()) {
continue;
}
$field->setReleephRequest($releeph_request);
try {
$field->setValueFromConduitAPIRequest($request);
} catch (ReleephFieldParseException $ex) {
throw id(new ConduitException('ERR_FIELD_PARSE'))
->setErrorDescription($ex->getMessage());
}
}
$editor = id(new ReleephRequestTransactionalEditor())
->setActor($user)
->setContinueOnNoEffect(true)
->setContentSource(
PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_CONDUIT,
array()));
$editor->applyTransactions($releeph_request, $xactions);
}
$url = PhabricatorEnv::getProductionURI('/Y'.$releeph_request->getID());
$results[$thing] = array(
'thing' => $thing,
'branch' => $releeph_branch->getDisplayNameWithDetail(),
'commitName' => $name,
'commitID' => $commit->getCommitIdentifier(),
'url' => $url,
'requestID' => $releeph_request->getID(),
'requestor' => $viewer_handle->getName(),
'requestTime' => $releeph_request->getDateCreated(),
'existing' => $existing_releeph_request !== null,
);
}
return $results;
}
}
diff --git a/src/applications/releeph/conduit/work/ReleephWorkCanPushConduitAPIMethod.php b/src/applications/releeph/conduit/work/ReleephWorkCanPushConduitAPIMethod.php
index 19d3d95acf..339f0ac5eb 100644
--- a/src/applications/releeph/conduit/work/ReleephWorkCanPushConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/work/ReleephWorkCanPushConduitAPIMethod.php
@@ -1,38 +1,34 @@
<?php
final class ReleephWorkCanPushConduitAPIMethod extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releephwork.canpush';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return 'Return whether the conduit user is allowed to push.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'projectPHID' => 'required string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'bool';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$releeph_project = id(new ReleephProject())
->loadOneWhere('phid = %s', $request->getValue('projectPHID'));
$user = $request->getUser();
return $releeph_project->isAuthoritative($user);
}
}
diff --git a/src/applications/releeph/conduit/work/ReleephWorkGetAuthorInfoConduitAPIMethod.php b/src/applications/releeph/conduit/work/ReleephWorkGetAuthorInfoConduitAPIMethod.php
index 28986d72a6..08381befb7 100644
--- a/src/applications/releeph/conduit/work/ReleephWorkGetAuthorInfoConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/work/ReleephWorkGetAuthorInfoConduitAPIMethod.php
@@ -1,48 +1,44 @@
<?php
final class ReleephWorkGetAuthorInfoConduitAPIMethod
extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releephwork.getauthorinfo';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return 'Return a string to use as the VCS author.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'userPHID' => 'required string',
'vcsType' => 'required string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty string';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$user = id(new PhabricatorUser())
->loadOneWhere('phid = %s', $request->getValue('userPHID'));
$email = $user->loadPrimaryEmailAddress();
if (is_numeric($email)) {
$email = $user->getUserName().'@fb.com';
}
return sprintf(
'%s <%s>',
$user->getRealName(),
$email);
}
}
diff --git a/src/applications/releeph/conduit/work/ReleephWorkGetBranchCommitMessageConduitAPIMethod.php b/src/applications/releeph/conduit/work/ReleephWorkGetBranchCommitMessageConduitAPIMethod.php
index 9ba11b85b7..20d86a003a 100644
--- a/src/applications/releeph/conduit/work/ReleephWorkGetBranchCommitMessageConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/work/ReleephWorkGetBranchCommitMessageConduitAPIMethod.php
@@ -1,104 +1,100 @@
<?php
final class ReleephWorkGetBranchCommitMessageConduitAPIMethod
extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releephwork.getbranchcommitmessage';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return 'Get a commit message for committing a Releeph branch.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'branchPHID' => 'required string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty string';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$branch = id(new ReleephBranchQuery())
->setViewer($viewer)
->withPHIDs(array($request->getValue('branchPHID')))
->executeOne();
$project = $branch->getProduct();
$creator_phid = $branch->getCreatedByUserPHID();
$cut_phid = $branch->getCutPointCommitPHID();
$phids = array(
$branch->getPHID(),
$project->getPHID(),
$creator_phid,
$cut_phid,
);
$handles = id(new PhabricatorHandleQuery())
->setViewer($request->getUser())
->withPHIDs($phids)
->execute();
$h_branch = $handles[$branch->getPHID()];
$h_project = $handles[$project->getPHID()];
// Not as customizable as a ReleephRequest's commit message. It doesn't
// really need to be.
// TODO: Yes it does, see FB-specific stuff below.
$commit_message = array();
$commit_message[] = $h_branch->getFullName();
$commit_message[] = $h_branch->getURI();
$commit_message[] = 'Cut Point: '.$handles[$cut_phid]->getName();
$cut_point_pr_commit = id(new PhabricatorRepositoryCommit())
->loadOneWhere('phid = %s', $cut_phid);
$cut_point_commit_date = strftime(
'%Y-%m-%d %H:%M:%S%z',
$cut_point_pr_commit->getEpoch());
$commit_message[] = "Cut Point Date: {$cut_point_commit_date}";
$commit_message[] = 'Created By: '.$handles[$creator_phid]->getName();
$project_uri = $project->getURI();
$commit_message[] = 'Project: '.$h_project->getName().' '.$project_uri;
/**
* Required for 090-limit_new_branch_creations.sh in
* admin/scripts/git/hosting/hooks/update.d (in the E repo):
*
* http://fburl.com/2372545
*
* The commit message must have a line saying:
*
* @new-branch: <branch-name>
*
*/
$repo = $project->getRepository();
switch ($repo->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$commit_message[] = sprintf(
'@new-branch: %s',
$branch->getName());
break;
}
return implode("\n\n", $commit_message);
}
}
diff --git a/src/applications/releeph/conduit/work/ReleephWorkGetBranchConduitAPIMethod.php b/src/applications/releeph/conduit/work/ReleephWorkGetBranchConduitAPIMethod.php
index c687205aef..5f6f82b17d 100644
--- a/src/applications/releeph/conduit/work/ReleephWorkGetBranchConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/work/ReleephWorkGetBranchConduitAPIMethod.php
@@ -1,61 +1,57 @@
<?php
final class ReleephWorkGetBranchConduitAPIMethod
extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releephwork.getbranch';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return 'Return information to help checkout / cut a Releeph branch.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'branchPHID' => 'required string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict<string, wild>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$branch = id(new ReleephBranchQuery())
->setViewer($request->getUser())
->withPHIDs(array($request->getValue('branchPHID')))
->needCutPointCommits(true)
->executeOne();
$cut_phid = $branch->getCutPointCommitPHID();
$phids = array($cut_phid);
$handles = id(new PhabricatorHandleQuery())
->setViewer($request->getUser())
->withPHIDs($phids)
->execute();
$project = $branch->getProject();
$repo = $project->getRepository();
$commit = $branch->getCutPointCommit();
return array(
'branchName' => $branch->getName(),
'branchPHID' => $branch->getPHID(),
'vcsType' => $repo->getVersionControlSystem(),
'cutCommitID' => $commit->getCommitIdentifier(),
'cutCommitName' => $handles[$cut_phid]->getName(),
'creatorPHID' => $branch->getCreatedByUserPHID(),
'trunk' => $project->getTrunkBranch(),
);
}
}
diff --git a/src/applications/releeph/conduit/work/ReleephWorkGetCommitMessageConduitAPIMethod.php b/src/applications/releeph/conduit/work/ReleephWorkGetCommitMessageConduitAPIMethod.php
index e0539fb690..398f37e7a0 100644
--- a/src/applications/releeph/conduit/work/ReleephWorkGetCommitMessageConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/work/ReleephWorkGetCommitMessageConduitAPIMethod.php
@@ -1,100 +1,96 @@
<?php
final class ReleephWorkGetCommitMessageConduitAPIMethod
extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releephwork.getcommitmessage';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return
'Get commit message components for building '.
'a ReleephRequest commit message.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$action_const = $this->formatStringConstants(array('pick', 'revert'));
return array(
'requestPHID' => 'required string',
'action' => 'required '.$action_const,
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'dict<string, string>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$releeph_request = id(new ReleephRequestQuery())
->setViewer($viewer)
->withPHIDs(array($request->getValue('requestPHID')))
->executeOne();
$action = $request->getValue('action');
$title = $releeph_request->getSummaryForDisplay();
$commit_message = array();
$branch = $releeph_request->getBranch();
$project = $branch->getProduct();
$selector = $project->getReleephFieldSelector();
$fields = $selector->getFieldSpecifications();
$fields = $selector->sortFieldsForCommitMessage($fields);
foreach ($fields as $field) {
$field
->setUser($request->getUser())
->setReleephProject($project)
->setReleephBranch($branch)
->setReleephRequest($releeph_request);
$label = null;
$value = null;
switch ($action) {
case 'pick':
if ($field->shouldAppearOnCommitMessage()) {
$label = $field->renderLabelForCommitMessage();
$value = $field->renderValueForCommitMessage();
}
break;
case 'revert':
if ($field->shouldAppearOnRevertMessage()) {
$label = $field->renderLabelForRevertMessage();
$value = $field->renderValueForRevertMessage();
}
break;
}
if ($label && $value) {
if (strpos($value, "\n") !== false ||
substr($value, 0, 2) === ' ') {
$commit_message[] = "{$label}:\n{$value}";
} else {
$commit_message[] = "{$label}: {$value}";
}
}
}
return array(
'title' => $title,
'body' => implode("\n\n", $commit_message),
);
}
}
diff --git a/src/applications/releeph/conduit/work/ReleephWorkNextRequestConduitAPIMethod.php b/src/applications/releeph/conduit/work/ReleephWorkNextRequestConduitAPIMethod.php
index cb6d7646fe..5e3d004ce6 100644
--- a/src/applications/releeph/conduit/work/ReleephWorkNextRequestConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/work/ReleephWorkNextRequestConduitAPIMethod.php
@@ -1,228 +1,228 @@
<?php
final class ReleephWorkNextRequestConduitAPIMethod
extends ReleephConduitAPIMethod {
private $project;
private $branch;
public function getAPIMethodName() {
return 'releephwork.nextrequest';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return
'Return info required to cut a branch, '.
'and pick and revert ReleephRequests';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'branchPHID' => 'required phid',
'seen' => 'required map<string, bool>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return '';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-NOT-PUSHER' =>
'You are not listed as a pusher for thie Releeph project!',
);
}
protected function execute(ConduitAPIRequest $request) {
$viewer = $request->getUser();
$seen = $request->getValue('seen');
$branch = id(new ReleephBranchQuery())
->setViewer($viewer)
->withPHIDs(array($request->getValue('branchPHID')))
->executeOne();
$project = $branch->getProduct();
$needs_pick = array();
$needs_revert = array();
// Load every request ever made for this branch...?!!!
$releeph_requests = id(new ReleephRequestQuery())
->setViewer($viewer)
->withBranchIDs(array($branch->getID()))
->execute();
foreach ($releeph_requests as $candidate) {
$phid = $candidate->getPHID();
if (idx($seen, $phid)) {
continue;
}
$should = $candidate->shouldBeInBranch();
$in = $candidate->getInBranch();
if ($should && !$in) {
$needs_pick[] = $candidate;
}
if (!$should && $in) {
$needs_revert[] = $candidate;
}
}
/**
* Sort both needs_pick and needs_revert in ascending commit order, as
* discovered by Phabricator (using the `id` column to perform that
* ordering).
*
* This is easy for $needs_pick as the ordinal is stored. It is hard for
* reverts, as we have to look that information up.
*/
$needs_pick = $this->sortPicks($needs_pick);
$needs_revert = $this->sortReverts($needs_revert);
/**
* Do reverts first in reverse order, then the picks in original-commit
* order.
*
* This seems like the correct thing to do, but there may be a better
* algorithm for the releephwork.nextrequest Conduit call that orders
* things better.
*
* We could also button-mash our way through everything that failed (at the
* end of the run) to try failed things again.
*/
$releeph_request = null;
$action = null;
if ($needs_revert) {
$releeph_request = last($needs_revert);
$action = 'revert';
$commit_id = $releeph_request->getCommitIdentifier();
$commit_phid = $releeph_request->getCommitPHID();
} else if ($needs_pick) {
$releeph_request = head($needs_pick);
$action = 'pick';
$commit = $releeph_request->loadPhabricatorRepositoryCommit();
$commit_id = $commit->getCommitIdentifier();
$commit_phid = $commit->getPHID();
} else {
// Return early if there's nothing to do!
return array();
}
// Build the response
$phids = array();
$phids[] = $commit_phid;
$diff_phid = null;
$diff_rev_id = null;
$requested_object = $releeph_request->getRequestedObject();
if ($requested_object instanceof DifferentialRevision) {
$diff_rev = $requested_object;
} else {
$diff_rev = null;
}
if ($diff_rev) {
$diff_phid = $diff_rev->getPHID();
$phids[] = $diff_phid;
$diff_rev_id = $diff_rev->getID();
}
$phids[] = $releeph_request->getPHID();
$handles = id(new PhabricatorHandleQuery())
->setViewer($request->getUser())
->withPHIDs($phids)
->execute();
$diff_name = null;
if ($diff_rev) {
$diff_name = $handles[$diff_phid]->getName();
}
$new_author_phid = null;
if ($diff_rev) {
$new_author_phid = $diff_rev->getAuthorPHID();
} else {
$pr_commit = $releeph_request->loadPhabricatorRepositoryCommit();
if ($pr_commit) {
$new_author_phid = $pr_commit->getAuthorPHID();
}
}
return array(
'requestID' => $releeph_request->getID(),
'requestPHID' => $releeph_request->getPHID(),
'requestName' => $handles[$releeph_request->getPHID()]->getName(),
'requestorPHID' => $releeph_request->getRequestUserPHID(),
'action' => $action,
'diffRevID' => $diff_rev_id,
'diffName' => $diff_name,
'commitIdentifier' => $commit_id,
'commitPHID' => $commit_phid,
'commitName' => $handles[$commit_phid]->getName(),
'needsRevert' => mpull($needs_revert, 'getID'),
'needsPick' => mpull($needs_pick, 'getID'),
'newAuthorPHID' => $new_author_phid,
);
}
private function sortPicks(array $releeph_requests) {
$surrogate = array();
foreach ($releeph_requests as $rq) {
// TODO: it's likely that relying on the `id` column to provide
// trunk-commit-order is thoroughly broken.
$ordinal = (int) $rq->loadPhabricatorRepositoryCommit()->getID();
$surrogate[$ordinal] = $rq;
}
ksort($surrogate);
return $surrogate;
}
/**
* Sort an array of ReleephRequests, that have been picked into a branch, in
* the order in which they were picked to the branch.
*/
private function sortReverts(array $releeph_requests) {
if (!$releeph_requests) {
return array();
}
// ReleephRequests, keyed by <branch-commit-id>
$releeph_requests = mpull($releeph_requests, null, 'getCommitIdentifier');
$commits = id(new PhabricatorRepositoryCommit())
->loadAllWhere(
'commitIdentifier IN (%Ls)',
mpull($releeph_requests, 'getCommitIdentifier'));
// A map of <branch-commit-id> => <branch-commit-ordinal>
$surrogate = mpull($commits, 'getID', 'getCommitIdentifier');
$unparsed = array();
$result = array();
foreach ($releeph_requests as $commit_id => $releeph_request) {
$ordinal = idx($surrogate, $commit_id);
if ($ordinal) {
$result[$ordinal] = $releeph_request;
} else {
$unparsed[] = $releeph_request;
}
}
// Sort $result in ascending order
ksort($result);
// Unparsed commits we'll just have to guess, based on time
$unparsed = msort($unparsed, 'getDateModified');
return array_merge($result, $unparsed);
}
}
diff --git a/src/applications/releeph/conduit/work/ReleephWorkRecordConduitAPIMethod.php b/src/applications/releeph/conduit/work/ReleephWorkRecordConduitAPIMethod.php
index 8eea8d1a28..43e26f2f4d 100644
--- a/src/applications/releeph/conduit/work/ReleephWorkRecordConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/work/ReleephWorkRecordConduitAPIMethod.php
@@ -1,79 +1,75 @@
<?php
final class ReleephWorkRecordConduitAPIMethod
extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releephwork.record';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
/**
* Record that a request was committed locally, and is about to be pushed to
* the remote repository.
*
* This lets us mark a ReleephRequest as being in a branch in real time so
* that no one else tries to pick it.
*
* When the daemons discover this commit in the repository with
* DifferentialReleephRequestFieldSpecification, we'll be able to record the
* commit's PHID as well. That process is slow though, and we don't want to
* wait a whole minute before marking something as cleanly picked or
* reverted.
*/
public function getMethodDescription() {
return 'Record whether we committed a pick or revert '.
'to the upstream repository.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$action_const = $this->formatStringConstants(
array(
'pick',
'revert',
));
return array(
'requestPHID' => 'required string',
'action' => 'required '.$action_const,
'commitIdentifier' => 'required string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$action = $request->getValue('action');
$new_commit_id = $request->getValue('commitIdentifier');
$releeph_request = id(new ReleephRequest())
->loadOneWhere('phid = %s', $request->getValue('requestPHID'));
$xactions = array();
$xactions[] = id(new ReleephRequestTransaction())
->setTransactionType(ReleephRequestTransaction::TYPE_COMMIT)
->setMetadataValue('action', $action)
->setNewValue($new_commit_id);
$editor = id(new ReleephRequestTransactionalEditor())
->setActor($request->getUser())
->setContinueOnNoEffect(true)
->setContentSource(
PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_CONDUIT,
array()));
$editor->applyTransactions($releeph_request, $xactions);
}
}
diff --git a/src/applications/releeph/conduit/work/ReleephWorkRecordPickStatusConduitAPIMethod.php b/src/applications/releeph/conduit/work/ReleephWorkRecordPickStatusConduitAPIMethod.php
index dd4cb7a3bc..f9434ab48c 100644
--- a/src/applications/releeph/conduit/work/ReleephWorkRecordPickStatusConduitAPIMethod.php
+++ b/src/applications/releeph/conduit/work/ReleephWorkRecordPickStatusConduitAPIMethod.php
@@ -1,87 +1,83 @@
<?php
final class ReleephWorkRecordPickStatusConduitAPIMethod
extends ReleephConduitAPIMethod {
public function getAPIMethodName() {
return 'releephwork.recordpickstatus';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return 'Record whether a pick or revert was successful or not.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$action_const = $this->formatStringConstants(
array(
'pick',
'revert',
));
return array(
'requestPHID' => 'required string',
'action' => 'required '.$action_const,
'ok' => 'required bool',
'dryRun' => 'optional bool',
'details' => 'optional dict<string, wild>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return '';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$action = $request->getValue('action');
$ok = $request->getValue('ok');
$dry_run = $request->getValue('dryRun');
$details = $request->getValue('details', array());
switch ($request->getValue('action')) {
case 'pick':
$pick_status = $ok
? ReleephRequest::PICK_OK
: ReleephRequest::PICK_FAILED;
break;
case 'revert':
$pick_status = $ok
? ReleephRequest::REVERT_OK
: ReleephRequest::REVERT_FAILED;
break;
default:
throw new Exception("Unknown action {$action}!");
}
$releeph_request = id(new ReleephRequest())
->loadOneWhere('phid = %s', $request->getValue('requestPHID'));
$editor = id(new ReleephRequestTransactionalEditor())
->setActor($request->getUser())
->setContinueOnNoEffect(true)
->setContentSource(
PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_CONDUIT,
array()));
$xactions = array();
$xactions[] = id(new ReleephRequestTransaction())
->setTransactionType(ReleephRequestTransaction::TYPE_PICK_STATUS)
->setMetadataValue('dryRun', $dry_run)
->setMetadataValue('details', $details)
->setNewValue($pick_status);
$editor->applyTransactions($releeph_request, $xactions);
}
}
diff --git a/src/applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php b/src/applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php
index 64f29405af..d6c0554234 100644
--- a/src/applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php
+++ b/src/applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php
@@ -1,76 +1,76 @@
<?php
final class RemarkupProcessConduitAPIMethod extends ConduitAPIMethod {
public function getAPIMethodName() {
return 'remarkup.process';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return 'Process text through remarkup in phabricator context.';
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-NO-CONTENT' => 'Content may not be empty.',
'ERR-INVALID-ENGINE' => 'Invalid markup engine.',
);
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$available_contexts = array_keys($this->getEngineContexts());
$available_const = $this->formatStringConstants($available_contexts);
return array(
'context' => 'required '.$available_const,
'contents' => 'required list<string>',
);
}
protected function execute(ConduitAPIRequest $request) {
$contents = $request->getValue('contents');
$context = $request->getValue('context');
$engine_class = idx($this->getEngineContexts(), $context);
if (!$engine_class) {
throw new ConduitException('ERR-INVALID_ENGINE');
}
$engine = PhabricatorMarkupEngine::$engine_class();
$engine->setConfig('viewer', $request->getUser());
$results = array();
foreach ($contents as $content) {
$text = $engine->markupText($content);
if ($text) {
$content = hsprintf('%s', $text)->getHTMLContent();
} else {
$content = '';
}
$results[] = array(
'content' => $content,
);
}
return $results;
}
private function getEngineContexts() {
return array(
'phriction' => 'newPhrictionMarkupEngine',
'maniphest' => 'newManiphestMarkupEngine',
'differential' => 'newDifferentialMarkupEngine',
'phame' => 'newPhameMarkupEngine',
'feed' => 'newFeedMarkupEngine',
'diffusion' => 'newDiffusionMarkupEngine',
);
}
}
diff --git a/src/applications/repository/conduit/RepositoryCreateConduitAPIMethod.php b/src/applications/repository/conduit/RepositoryCreateConduitAPIMethod.php
index b8a898921f..42df1b6d46 100644
--- a/src/applications/repository/conduit/RepositoryCreateConduitAPIMethod.php
+++ b/src/applications/repository/conduit/RepositoryCreateConduitAPIMethod.php
@@ -1,142 +1,142 @@
<?php
final class RepositoryCreateConduitAPIMethod
extends RepositoryConduitAPIMethod {
public function getAPIMethodName() {
return 'repository.create';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodStatusDescription() {
return 'Repository methods are new and subject to change.';
}
public function getMethodDescription() {
return pht('Create a new repository.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
$vcs_const = $this->formatStringConstants(array('git', 'hg', 'svn'));
return array(
'name' => 'required string',
'vcs' => 'required '.$vcs_const,
'callsign' => 'required string',
'description' => 'optional string',
'encoding' => 'optional string',
'tracking' => 'optional bool',
'uri' => 'required string',
'credentialPHID' => 'optional string',
'svnSubpath' => 'optional string',
'branchFilter' => 'optional list<string>',
'closeCommitsFilter' => 'optional list<string>',
'pullFrequency' => 'optional int',
'defaultBranch' => 'optional string',
'heraldEnabled' => 'optional bool, default = true',
'autocloseEnabled' => 'optional bool, default = true',
'svnUUID' => 'optional string',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR-DUPLICATE' =>
'Duplicate repository callsign.',
'ERR-BAD-CALLSIGN' =>
'Callsign is required and must be ALL UPPERCASE LETTERS.',
'ERR-UNKNOWN-REPOSITORY-VCS' =>
'Unknown repository VCS type.',
);
}
protected function execute(ConduitAPIRequest $request) {
$application = id(new PhabricatorApplicationQuery())
->setViewer($request->getUser())
->withClasses(array('PhabricatorDiffusionApplication'))
->executeOne();
PhabricatorPolicyFilter::requireCapability(
$request->getUser(),
$application,
DiffusionCreateRepositoriesCapability::CAPABILITY);
// TODO: This has some duplication with (and lacks some of the validation
// of) the web workflow; refactor things so they can share more code as this
// stabilizes. Specifically, this should move to transactions since they
// work properly now.
$repository = PhabricatorRepository::initializeNewRepository(
$request->getUser());
$repository->setName($request->getValue('name'));
$callsign = $request->getValue('callsign');
if (!preg_match('/^[A-Z]+\z/', $callsign)) {
throw new ConduitException('ERR-BAD-CALLSIGN');
}
$repository->setCallsign($callsign);
$local_path = PhabricatorEnv::getEnvConfig(
'repository.default-local-path');
$local_path = rtrim($local_path, '/');
$local_path = $local_path.'/'.$callsign.'/';
$vcs = $request->getValue('vcs');
$map = array(
'git' => PhabricatorRepositoryType::REPOSITORY_TYPE_GIT,
'hg' => PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL,
'svn' => PhabricatorRepositoryType::REPOSITORY_TYPE_SVN,
);
if (empty($map[$vcs])) {
throw new ConduitException('ERR-UNKNOWN-REPOSITORY-VCS');
}
$repository->setVersionControlSystem($map[$vcs]);
$repository->setCredentialPHID($request->getValue('credentialPHID'));
$remote_uri = $request->getValue('uri');
PhabricatorRepository::assertValidRemoteURI($remote_uri);
$details = array(
'encoding' => $request->getValue('encoding'),
'description' => $request->getValue('description'),
'tracking-enabled' => (bool)$request->getValue('tracking', true),
'remote-uri' => $remote_uri,
'local-path' => $local_path,
'branch-filter' => array_fill_keys(
$request->getValue('branchFilter', array()),
true),
'close-commits-filter' => array_fill_keys(
$request->getValue('closeCommitsFilter', array()),
true),
'pull-frequency' => $request->getValue('pullFrequency'),
'default-branch' => $request->getValue('defaultBranch'),
'herald-disabled' => !$request->getValue('heraldEnabled', true),
'svn-subpath' => $request->getValue('svnSubpath'),
'disable-autoclose' => !$request->getValue('autocloseEnabled', true),
);
foreach ($details as $key => $value) {
$repository->setDetail($key, $value);
}
try {
$repository->save();
} catch (AphrontDuplicateKeyQueryException $ex) {
throw new ConduitException('ERR-DUPLICATE');
}
return $repository->toDictionary();
}
}
diff --git a/src/applications/repository/conduit/RepositoryQueryConduitAPIMethod.php b/src/applications/repository/conduit/RepositoryQueryConduitAPIMethod.php
index 0323446fb1..92fe84120b 100644
--- a/src/applications/repository/conduit/RepositoryQueryConduitAPIMethod.php
+++ b/src/applications/repository/conduit/RepositoryQueryConduitAPIMethod.php
@@ -1,86 +1,81 @@
<?php
final class RepositoryQueryConduitAPIMethod
extends RepositoryConduitAPIMethod {
public function getAPIMethodName() {
return 'repository.query';
}
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodStatusDescription() {
return pht('Repository methods are new and subject to change.');
}
public function getMethodDescription() {
return pht('Query repositories.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'ids' => 'optional list<int>',
'phids' => 'optional list<phid>',
'callsigns' => 'optional list<string>',
'vcsTypes' => 'optional list<string>',
'remoteURIs' => 'optional list<string>',
'uuids' => 'optional list<string>',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
- return array(
- );
- }
-
protected function execute(ConduitAPIRequest $request) {
$query = id(new PhabricatorRepositoryQuery())
->setViewer($request->getUser());
$ids = $request->getValue('ids', array());
if ($ids) {
$query->withIDs($ids);
}
$phids = $request->getValue('phids', array());
if ($phids) {
$query->withPHIDs($phids);
}
$callsigns = $request->getValue('callsigns', array());
if ($callsigns) {
$query->withCallsigns($callsigns);
}
$vcs_types = $request->getValue('vcsTypes', array());
if ($vcs_types) {
$query->withTypes($vcs_types);
}
$remote_uris = $request->getValue('remoteURIs', array());
if ($remote_uris) {
$query->withRemoteURIs($remote_uris);
}
$uuids = $request->getValue('uuids', array());
if ($uuids) {
$query->withUUIDs($uuids);
}
$repositories = $query->execute();
$results = array();
foreach ($repositories as $repository) {
$results[] = $repository->toDictionary();
}
return $results;
}
}
diff --git a/src/applications/slowvote/conduit/SlowvoteInfoConduitAPIMethod.php b/src/applications/slowvote/conduit/SlowvoteInfoConduitAPIMethod.php
index 42200ec28f..50478abc0c 100644
--- a/src/applications/slowvote/conduit/SlowvoteInfoConduitAPIMethod.php
+++ b/src/applications/slowvote/conduit/SlowvoteInfoConduitAPIMethod.php
@@ -1,47 +1,47 @@
<?php
final class SlowvoteInfoConduitAPIMethod extends SlowvoteConduitAPIMethod {
public function getAPIMethodName() {
return 'slowvote.info';
}
public function getMethodDescription() {
return 'Retrieve an array of information about a poll.';
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'poll_id' => 'required id',
);
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'nonempty dict';
}
- public function defineErrorTypes() {
+ protected function defineErrorTypes() {
return array(
'ERR_BAD_POLL' => 'No such poll exists',
);
}
protected function execute(ConduitAPIRequest $request) {
$poll_id = $request->getValue('poll_id');
$poll = id(new PhabricatorSlowvotePoll())->load($poll_id);
if (!$poll) {
throw new ConduitException('ERR_BAD_POLL');
}
$result = array(
'id' => $poll->getID(),
'phid' => $poll->getPHID(),
'authorPHID' => $poll->getAuthorPHID(),
'question' => $poll->getQuestion(),
'uri' => PhabricatorEnv::getProductionURI('/V'.$poll->getID()),
);
return $result;
}
}
diff --git a/src/applications/tokens/conduit/TokenGiveConduitAPIMethod.php b/src/applications/tokens/conduit/TokenGiveConduitAPIMethod.php
index 099f93de27..4e0a463a74 100644
--- a/src/applications/tokens/conduit/TokenGiveConduitAPIMethod.php
+++ b/src/applications/tokens/conduit/TokenGiveConduitAPIMethod.php
@@ -1,44 +1,40 @@
<?php
final class TokenGiveConduitAPIMethod extends TokenConduitAPIMethod {
public function getAPIMethodName() {
return 'token.give';
}
public function getMethodDescription() {
return pht('Give or change a token.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'tokenPHID' => 'phid|null',
'objectPHID' => 'phid',
);
}
- public function defineErrorTypes() {
- return array();
- }
-
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'void';
}
protected function execute(ConduitAPIRequest $request) {
$content_source = PhabricatorContentSource::newFromConduitRequest($request);
$editor = id(new PhabricatorTokenGivenEditor())
->setActor($request->getUser())
->setContentSource($content_source);
if ($request->getValue('tokenPHID')) {
$editor->addToken(
$request->getValue('objectPHID'),
$request->getValue('tokenPHID'));
} else {
$editor->deleteToken($request->getValue('objectPHID'));
}
}
}
diff --git a/src/applications/tokens/conduit/TokenGivenConduitAPIMethod.php b/src/applications/tokens/conduit/TokenGivenConduitAPIMethod.php
index 86f666b68c..dfa887fc76 100644
--- a/src/applications/tokens/conduit/TokenGivenConduitAPIMethod.php
+++ b/src/applications/tokens/conduit/TokenGivenConduitAPIMethod.php
@@ -1,53 +1,49 @@
<?php
final class TokenGivenConduitAPIMethod extends TokenConduitAPIMethod {
public function getAPIMethodName() {
return 'token.given';
}
public function getMethodDescription() {
return pht('Query tokens given to objects.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array(
'authorPHIDs' => 'list<phid>',
'objectPHIDs' => 'list<phid>',
'tokenPHIDs' => 'list<phid>',
);
}
- public function defineErrorTypes() {
- return array();
- }
-
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
protected function execute(ConduitAPIRequest $request) {
$query = id(new PhabricatorTokenGivenQuery())
->setViewer($request->getUser());
$author_phids = $request->getValue('authorPHIDs');
if ($author_phids) {
$query->withAuthorPHIDs($author_phids);
}
$object_phids = $request->getValue('objectPHIDs');
if ($object_phids) {
$query->withObjectPHIDs($object_phids);
}
$token_phids = $request->getValue('tokenPHIDs');
if ($token_phids) {
$query->withTokenPHIDs($token_phids);
}
$given = $query->execute();
return $this->buildTokenGivenDicts($given);
}
}
diff --git a/src/applications/tokens/conduit/TokenQueryConduitAPIMethod.php b/src/applications/tokens/conduit/TokenQueryConduitAPIMethod.php
index 3168feab87..ec0dcfb873 100644
--- a/src/applications/tokens/conduit/TokenQueryConduitAPIMethod.php
+++ b/src/applications/tokens/conduit/TokenQueryConduitAPIMethod.php
@@ -1,34 +1,30 @@
<?php
final class TokenQueryConduitAPIMethod extends TokenConduitAPIMethod {
public function getAPIMethodName() {
return 'token.query';
}
public function getMethodDescription() {
return pht('Query tokens.');
}
- public function defineParamTypes() {
+ protected function defineParamTypes() {
return array();
}
- public function defineReturnType() {
+ protected function defineReturnType() {
return 'list<dict>';
}
- public function defineErrorTypes() {
- return array();
- }
-
protected function execute(ConduitAPIRequest $request) {
$query = id(new PhabricatorTokenQuery())
->setViewer($request->getUser());
$tokens = $query->execute();
return $this->buildTokenDicts($tokens);
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Apr 29, 8:15 PM (1 d, 2 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
108479
Default Alt Text
(438 KB)

Event Timeline