mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 05:50:55 +01:00
Allow "transaction.search" to be called on an object type
Summary: Ref T13631. This supports a more robust version of "poll for updates by using dateModified window queries" that uses transactions as a logical clock. This is particularly relevant for commits, since they don't have a "dateModified" at time of writing. Test Plan: - Queried for transactions by type and object. - Issued various invalid transaction queries, got appropriate errors. Maniphest Tasks: T13631 Differential Revision: https://secure.phabricator.com/D21601
This commit is contained in:
parent
404b55ce57
commit
afdef332fb
1 changed files with 92 additions and 32 deletions
|
@ -8,7 +8,9 @@ final class TransactionSearchConduitAPIMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMethodDescription() {
|
public function getMethodDescription() {
|
||||||
return pht('Read transactions and comments for an object.');
|
return pht(
|
||||||
|
'Read transactions and comments for a particular object '.
|
||||||
|
'or an entire object type.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMethodDocumentation() {
|
public function getMethodDocumentation() {
|
||||||
|
@ -23,6 +25,26 @@ One common reason to call this method is that you're implmenting a webhook and
|
||||||
just received a notification that an object has changed. See the Webhooks
|
just received a notification that an object has changed. See the Webhooks
|
||||||
documentation for more detailed discussion of this use case.
|
documentation for more detailed discussion of this use case.
|
||||||
|
|
||||||
|
One Object Type at a Time
|
||||||
|
=========================
|
||||||
|
|
||||||
|
This API method can query transactions for any type of object which supports
|
||||||
|
transactions, but only one type of object can be queried per call. For example:
|
||||||
|
you can retrieve transactions affecting Tasks, or you can retrieve transactions
|
||||||
|
affecting Revisions, but a single call can not retrieve both.
|
||||||
|
|
||||||
|
This is a technical limitation arising because (among other reasons) there is
|
||||||
|
no global ordering on transactions.
|
||||||
|
|
||||||
|
To find transactions for a specific object (like a particular task), pass the
|
||||||
|
object PHID or an appropriate object identifier (like `T123`) as an
|
||||||
|
`objectIdentifier`.
|
||||||
|
|
||||||
|
To find all transactions for an object type, pass the object type constant as
|
||||||
|
an `objectType`. For example, the correct identifier for tasks is `TASK`. (You
|
||||||
|
can quickly find an unknown type constant by looking at the PHID of an object
|
||||||
|
of that type.)
|
||||||
|
|
||||||
Constraints
|
Constraints
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
@ -64,8 +86,9 @@ EOREMARKUP
|
||||||
|
|
||||||
protected function defineParamTypes() {
|
protected function defineParamTypes() {
|
||||||
return array(
|
return array(
|
||||||
'objectIdentifier' => 'phid|string',
|
'objectIdentifier' => 'optional phid|string',
|
||||||
'constraints' => 'map<string, wild>',
|
'objectType' => 'optional string',
|
||||||
|
'constraints' => 'optional map<string, wild>',
|
||||||
) + $this->getPagerParamTypes();
|
) + $this->getPagerParamTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,43 +104,19 @@ EOREMARKUP
|
||||||
$viewer = $request->getUser();
|
$viewer = $request->getUser();
|
||||||
$pager = $this->newPager($request);
|
$pager = $this->newPager($request);
|
||||||
|
|
||||||
$object_name = $request->getValue('objectIdentifier', null);
|
$object = $this->loadTemplateObject($request);
|
||||||
if (!strlen($object_name)) {
|
|
||||||
throw new Exception(
|
|
||||||
pht(
|
|
||||||
'When calling "transaction.search", you must provide an object to '.
|
|
||||||
'retrieve transactions for.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$object = id(new PhabricatorObjectQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withNames(array($object_name))
|
|
||||||
->executeOne();
|
|
||||||
if (!$object) {
|
|
||||||
throw new Exception(
|
|
||||||
pht(
|
|
||||||
'No object "%s" exists.',
|
|
||||||
$object_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!($object instanceof PhabricatorApplicationTransactionInterface)) {
|
|
||||||
throw new Exception(
|
|
||||||
pht(
|
|
||||||
'Object "%s" (of type "%s") does not implement "%s", so '.
|
|
||||||
'transactions can not be loaded for it.',
|
|
||||||
$object_name,
|
|
||||||
get_class($object),
|
|
||||||
'PhabricatorApplicationTransactionInterface'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$xaction_query = PhabricatorApplicationTransactionQuery::newQueryForObject(
|
$xaction_query = PhabricatorApplicationTransactionQuery::newQueryForObject(
|
||||||
$object);
|
$object);
|
||||||
|
|
||||||
$xaction_query
|
$xaction_query
|
||||||
->needHandles(false)
|
->needHandles(false)
|
||||||
->withObjectPHIDs(array($object->getPHID()))
|
|
||||||
->setViewer($viewer);
|
->setViewer($viewer);
|
||||||
|
|
||||||
|
if ($object->getPHID()) {
|
||||||
|
$xaction_query->withObjectPHIDs(array($object->getPHID()));
|
||||||
|
}
|
||||||
|
|
||||||
$constraints = $request->getValue('constraints', array());
|
$constraints = $request->getValue('constraints', array());
|
||||||
|
|
||||||
$xaction_query = $this->applyConstraints($constraints, $xaction_query);
|
$xaction_query = $this->applyConstraints($constraints, $xaction_query);
|
||||||
|
@ -355,4 +354,65 @@ EOREMARKUP
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function loadTemplateObject(ConduitAPIRequest $request) {
|
||||||
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
|
$object_identifier = $request->getValue('objectIdentifier');
|
||||||
|
$object_type = $request->getValue('objectType');
|
||||||
|
|
||||||
|
$has_identifier = ($object_identifier !== null);
|
||||||
|
$has_type = ($object_type !== null);
|
||||||
|
|
||||||
|
if (!$has_type && !$has_identifier) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Calls to "transaction.search" must specify either an "objectType" '.
|
||||||
|
'or an "objectIdentifier"'));
|
||||||
|
} else if ($has_type && $has_identifier) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Calls to "transaction.search" must not specify both an '.
|
||||||
|
'"objectType" and an "objectIdentifier".'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($has_type) {
|
||||||
|
$all_types = PhabricatorPHIDType::getAllTypes();
|
||||||
|
|
||||||
|
if (!isset($all_types[$object_type])) {
|
||||||
|
ksort($all_types);
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'In call to "transaction.search", specified "objectType" ("%s") '.
|
||||||
|
'is unknown. Valid object types are: %s.',
|
||||||
|
$object_type,
|
||||||
|
implode(', ', array_keys($all_types))));
|
||||||
|
}
|
||||||
|
|
||||||
|
$object = $all_types[$object_type]->newObject();
|
||||||
|
} else {
|
||||||
|
$object = id(new PhabricatorObjectQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withNames(array($object_identifier))
|
||||||
|
->executeOne();
|
||||||
|
if (!$object) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'In call to "transaction.search", specified "objectIdentifier" '.
|
||||||
|
'("%s") does not exist.',
|
||||||
|
$object_identifier));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($object instanceof PhabricatorApplicationTransactionInterface)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'In call to "transaction.search", selected object (of type "%s") '.
|
||||||
|
'does not implement "%s", so transactions can not be loaded for it.',
|
||||||
|
get_class($object),
|
||||||
|
'PhabricatorApplicationTransactionInterface'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue