mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-27 09:12:41 +01:00
Add "owners.search" Conduit API endpoint, with CustomField support
Summary: Ref T9964. Adds a new-style "owners.search" endpoint, and an extension for customfields. Puts enough indirection in place to give us nice, consistent "custom.key" user-facing keys instead of "std:custom:owners:na0shf9a8dfdsafl" junk. Test Plan: - Searched Owners via API. - Searched by ID. - Ordered by custom fields. - Reviewed API docs. - Used normal search with ordering. - Viewed custom field values in search results. Reviewers: chad Reviewed By: chad Maniphest Tasks: T9964 Differential Revision: https://secure.phabricator.com/D14758
This commit is contained in:
parent
32a7674c22
commit
9499987cfe
12 changed files with 198 additions and 14 deletions
|
@ -1417,6 +1417,7 @@ phutil_register_library_map(array(
|
|||
'OwnersEditConduitAPIMethod' => 'applications/owners/conduit/OwnersEditConduitAPIMethod.php',
|
||||
'OwnersPackageReplyHandler' => 'applications/owners/mail/OwnersPackageReplyHandler.php',
|
||||
'OwnersQueryConduitAPIMethod' => 'applications/owners/conduit/OwnersQueryConduitAPIMethod.php',
|
||||
'OwnersSearchConduitAPIMethod' => 'applications/owners/conduit/OwnersSearchConduitAPIMethod.php',
|
||||
'PHIDConduitAPIMethod' => 'applications/phid/conduit/PHIDConduitAPIMethod.php',
|
||||
'PHIDInfoConduitAPIMethod' => 'applications/phid/conduit/PHIDInfoConduitAPIMethod.php',
|
||||
'PHIDLookupConduitAPIMethod' => 'applications/phid/conduit/PHIDLookupConduitAPIMethod.php',
|
||||
|
@ -1993,7 +1994,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCustomFieldAttachment' => 'infrastructure/customfield/field/PhabricatorCustomFieldAttachment.php',
|
||||
'PhabricatorCustomFieldConfigOptionType' => 'infrastructure/customfield/config/PhabricatorCustomFieldConfigOptionType.php',
|
||||
'PhabricatorCustomFieldDataNotAvailableException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldDataNotAvailableException.php',
|
||||
'PhabricatorCustomFieldEditEngineExtension' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditEngineExtension.php',
|
||||
'PhabricatorCustomFieldEditEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php',
|
||||
'PhabricatorCustomFieldEditField' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php',
|
||||
'PhabricatorCustomFieldEditType' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditType.php',
|
||||
'PhabricatorCustomFieldHeraldField' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldField.php',
|
||||
|
@ -2006,6 +2007,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCustomFieldNotAttachedException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldNotAttachedException.php',
|
||||
'PhabricatorCustomFieldNotProxyException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldNotProxyException.php',
|
||||
'PhabricatorCustomFieldNumericIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldNumericIndexStorage.php',
|
||||
'PhabricatorCustomFieldSearchEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldSearchEngineExtension.php',
|
||||
'PhabricatorCustomFieldStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStorage.php',
|
||||
'PhabricatorCustomFieldStringIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStringIndexStorage.php',
|
||||
'PhabricatorCustomHeaderConfigType' => 'applications/config/custom/PhabricatorCustomHeaderConfigType.php',
|
||||
|
@ -5439,6 +5441,7 @@ phutil_register_library_map(array(
|
|||
'OwnersEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
|
||||
'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler',
|
||||
'OwnersQueryConduitAPIMethod' => 'OwnersConduitAPIMethod',
|
||||
'OwnersSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
||||
'PHIDConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'PHIDInfoConduitAPIMethod' => 'PHIDConduitAPIMethod',
|
||||
'PHIDLookupConduitAPIMethod' => 'PHIDConduitAPIMethod',
|
||||
|
@ -6116,6 +6119,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCustomFieldNotAttachedException' => 'Exception',
|
||||
'PhabricatorCustomFieldNotProxyException' => 'Exception',
|
||||
'PhabricatorCustomFieldNumericIndexStorage' => 'PhabricatorCustomFieldIndexStorage',
|
||||
'PhabricatorCustomFieldSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
||||
'PhabricatorCustomFieldStorage' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorCustomFieldStringIndexStorage' => 'PhabricatorCustomFieldIndexStorage',
|
||||
'PhabricatorCustomHeaderConfigType' => 'PhabricatorConfigOptionType',
|
||||
|
@ -6791,6 +6795,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationTransactionInterface',
|
||||
'PhabricatorCustomFieldInterface',
|
||||
'PhabricatorDestructibleInterface',
|
||||
'PhabricatorConduitResultInterface',
|
||||
),
|
||||
'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'PhabricatorOwnersPackageEditEngine' => 'PhabricatorEditEngine',
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
final class OwnersSearchConduitAPIMethod
|
||||
extends PhabricatorSearchEngineAPIMethod {
|
||||
|
||||
public function getAPIMethodName() {
|
||||
return 'owners.search';
|
||||
}
|
||||
|
||||
public function newSearchEngine() {
|
||||
return new PhabricatorOwnersPackageSearchEngine();
|
||||
}
|
||||
|
||||
public function getMethodSummary() {
|
||||
return pht('Read information about Owners packages.');
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,8 @@ final class PhabricatorOwnersPackage
|
|||
PhabricatorPolicyInterface,
|
||||
PhabricatorApplicationTransactionInterface,
|
||||
PhabricatorCustomFieldInterface,
|
||||
PhabricatorDestructibleInterface {
|
||||
PhabricatorDestructibleInterface,
|
||||
PhabricatorConduitResultInterface {
|
||||
|
||||
protected $name;
|
||||
protected $originalName;
|
||||
|
@ -365,4 +366,33 @@ final class PhabricatorOwnersPackage
|
|||
$this->saveTransaction();
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorConduitResultInterface )---------------------------------- */
|
||||
|
||||
|
||||
public function getFieldSpecificationsForConduit() {
|
||||
return array(
|
||||
'name' => array(
|
||||
'type' => 'string',
|
||||
'description' => pht('The name of the package.'),
|
||||
),
|
||||
'description' => array(
|
||||
'type' => 'string',
|
||||
'description' => pht('The package description.'),
|
||||
),
|
||||
'status' => array(
|
||||
'type' => 'string',
|
||||
'description' => pht('Active or archived status of the package.'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit() {
|
||||
return array(
|
||||
'name' => $this->getName(),
|
||||
'description' => $this->getDescription(),
|
||||
'status' => $this->getStatus(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1174,6 +1174,14 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
|
||||
public function getSearchFieldsForConduit() {
|
||||
$fields = $this->buildSearchFields();
|
||||
|
||||
// These are handled separately for Conduit, so don't show them as
|
||||
// supported.
|
||||
unset($fields['ids']);
|
||||
unset($fields['phids']);
|
||||
unset($fields['order']);
|
||||
unset($fields['limit']);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
@ -1220,6 +1228,7 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
$query = $this->buildQueryFromSavedQuery($saved_query);
|
||||
$pager = $this->newPagerForSavedQuery($saved_query);
|
||||
|
||||
$this->setAutomaticConstraintsForConduit($query, $request, $constraints);
|
||||
$this->setQueryOrderForConduit($query, $request);
|
||||
$this->setPagerLimitForConduit($pager, $request);
|
||||
$this->setPagerOffsetsForConduit($pager, $request);
|
||||
|
@ -1269,6 +1278,12 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
|
||||
$field_extensions = array();
|
||||
foreach ($extensions as $key => $extension) {
|
||||
$extension->setViewer($this->requireViewer());
|
||||
|
||||
if (!$extension->supportsObject($object)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($extension->getFieldSpecificationsForConduit($object)) {
|
||||
$field_extensions[$key] = $extension;
|
||||
}
|
||||
|
@ -1277,6 +1292,22 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
return $field_extensions;
|
||||
}
|
||||
|
||||
private function setAutomaticConstraintsForConduit(
|
||||
$query,
|
||||
ConduitAPIRequest $request,
|
||||
array $constraints) {
|
||||
|
||||
$with_ids = idx($constraints, 'ids');
|
||||
if ($with_ids) {
|
||||
$query->withIDs($with_ids);
|
||||
}
|
||||
|
||||
$with_phids = idx($constraints, 'phids');
|
||||
if ($with_phids) {
|
||||
$query->withPHIDs($with_phids);
|
||||
}
|
||||
}
|
||||
|
||||
private function setQueryOrderForConduit($query, ConduitAPIRequest $request) {
|
||||
$order = $request->getValue('order');
|
||||
if ($order === null) {
|
||||
|
|
|
@ -143,13 +143,18 @@ EOTEXT
|
|||
$head_type = pht('Type');
|
||||
$head_desc = pht('Description');
|
||||
|
||||
$desc_ids = pht('Search for specific objects by ID.');
|
||||
$desc_phids = pht('Search for specific objects by PHID.');
|
||||
|
||||
$fields = $engine->getSearchFieldsForConduit();
|
||||
|
||||
$table = array();
|
||||
$table[] = "| {$head_key} | {$head_label} | {$head_type} | {$head_desc} |";
|
||||
$table[] = '|-------------|---------------|--------------|--------------|';
|
||||
$table[] = "| `ids` | **IDs** | `list<int>` | {$desc_ids} |";
|
||||
$table[] = "| `phids` | **PHIDs** | `list<phid>` | {$desc_phids} |";
|
||||
foreach ($fields as $field) {
|
||||
$key = $field->getKey();
|
||||
$key = $field->getKeyForConduit();
|
||||
$label = $field->getLabel();
|
||||
|
||||
// TODO: Support generating and surfacing this information.
|
||||
|
|
|
@ -26,6 +26,10 @@ final class PhabricatorSearchCustomFieldProxyField
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getLabel() {
|
||||
return $this->getCustomField()->getFieldName();
|
||||
}
|
||||
|
||||
public function getCustomField() {
|
||||
return $this->customField;
|
||||
}
|
||||
|
@ -34,6 +38,10 @@ final class PhabricatorSearchCustomFieldProxyField
|
|||
return null;
|
||||
}
|
||||
|
||||
public function getKeyForConduit() {
|
||||
return $this->getCustomField()->getModernFieldKey();
|
||||
}
|
||||
|
||||
protected function getValueExistsInRequest(AphrontRequest $request, $key) {
|
||||
// TODO: For historical reasons, the keys we look for don't line up with
|
||||
// the keys that CustomFields use. Just skip the check for existence and
|
||||
|
|
|
@ -271,4 +271,14 @@ abstract class PhabricatorSearchField extends Phobject {
|
|||
|
||||
return $list;
|
||||
}
|
||||
|
||||
|
||||
public function getKeyForConduit() {
|
||||
// TODO: This shouldn't really be different, but internal handling of
|
||||
// custom field keys is a bit of a mess for now.
|
||||
return $this->getKey();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCustomFieldSearchEngineExtension
|
||||
extends PhabricatorSearchEngineExtension {
|
||||
|
||||
const EXTENSIONKEY = 'customfield';
|
||||
|
||||
public function isExtensionEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getExtensionName() {
|
||||
return pht('Support for Custom Fields');
|
||||
}
|
||||
|
||||
public function supportsObject($object) {
|
||||
return ($object instanceof PhabricatorCustomFieldInterface);
|
||||
}
|
||||
|
||||
public function getFieldSpecificationsForConduit($object) {
|
||||
$fields = PhabricatorCustomField::getObjectFields(
|
||||
$object,
|
||||
PhabricatorCustomField::ROLE_CONDUIT);
|
||||
|
||||
$map = array();
|
||||
foreach ($fields->getFields() as $field) {
|
||||
$key = $field->getModernFieldKey();
|
||||
$map[$key] = array(
|
||||
'type' => 'wild',
|
||||
'description' => $field->getFieldDescription(),
|
||||
);
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit($object) {
|
||||
// TODO: This is currently very inefficient. We should bulk-load these
|
||||
// field values instead.
|
||||
|
||||
$fields = PhabricatorCustomField::getObjectFields(
|
||||
$object,
|
||||
PhabricatorCustomField::ROLE_CONDUIT);
|
||||
|
||||
$fields
|
||||
->setViewer($this->getViewer())
|
||||
->readFieldsFromStorage($object);
|
||||
|
||||
$map = array();
|
||||
foreach ($fields->getFields() as $field) {
|
||||
$key = $field->getModernFieldKey();
|
||||
$map[$key] = $field->getConduitDictionaryValue();
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
}
|
|
@ -188,6 +188,13 @@ abstract class PhabricatorCustomField extends Phobject {
|
|||
$field_key_is_incomplete = true);
|
||||
}
|
||||
|
||||
public function getModernFieldKey() {
|
||||
if ($this->proxy) {
|
||||
return $this->proxy->getModernFieldKey();
|
||||
}
|
||||
return $this->getFieldKey();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a human-readable field name.
|
||||
|
@ -199,7 +206,7 @@ abstract class PhabricatorCustomField extends Phobject {
|
|||
if ($this->proxy) {
|
||||
return $this->proxy->getFieldName();
|
||||
}
|
||||
return $this->getFieldKey();
|
||||
return $this->getModernFieldKey();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1109,7 +1116,7 @@ abstract class PhabricatorCustomField extends Phobject {
|
|||
|
||||
return $this->newEditField()
|
||||
->setKey($this->getFieldKey())
|
||||
->setEditTypeKey('custom.'.$this->getFieldKey())
|
||||
->setEditTypeKey($this->getModernFieldKey())
|
||||
->setLabel($this->getFieldName())
|
||||
->setDescription($this->getFieldDescription())
|
||||
->setTransactionType($this->getApplicationTransactionType())
|
||||
|
|
|
@ -440,7 +440,7 @@ abstract class PhabricatorStandardCustomField
|
|||
}
|
||||
|
||||
protected function newStandardEditField() {
|
||||
$short = 'custom.'.$this->getRawStandardFieldKey();
|
||||
$short = $this->getModernFieldKey();
|
||||
|
||||
return parent::newStandardEditField()
|
||||
->setEditTypeKey($short)
|
||||
|
@ -451,4 +451,16 @@ abstract class PhabricatorStandardCustomField
|
|||
return true;
|
||||
}
|
||||
|
||||
public function shouldAppearInConduitDictionary() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getModernFieldKey() {
|
||||
return 'custom.'.$this->getRawStandardFieldKey();
|
||||
}
|
||||
|
||||
public function getConduitDictionaryValue() {
|
||||
return $this->getFieldValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -716,13 +716,13 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
|
|||
continue;
|
||||
}
|
||||
|
||||
$key = $field->getFieldKey();
|
||||
$digest = $field->getFieldIndex();
|
||||
$legacy_key = 'custom:'.$field->getFieldKey();
|
||||
$modern_key = $field->getModernFieldKey();
|
||||
|
||||
$full_key = 'custom:'.$key;
|
||||
$orders[$full_key] = array(
|
||||
'vector' => array($full_key, 'id'),
|
||||
$orders[$modern_key] = array(
|
||||
'vector' => array($modern_key, 'id'),
|
||||
'name' => $field->getFieldName(),
|
||||
'aliases' => array($legacy_key),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -903,11 +903,11 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
|
|||
continue;
|
||||
}
|
||||
|
||||
$key = $field->getFieldKey();
|
||||
$digest = $field->getFieldIndex();
|
||||
|
||||
$full_key = 'custom:'.$key;
|
||||
$columns[$full_key] = array(
|
||||
$key = $field->getModernFieldKey();
|
||||
|
||||
$columns[$key] = array(
|
||||
'table' => 'appsearch_order_'.$digest,
|
||||
'column' => 'indexValue',
|
||||
'type' => $index->getIndexValueType(),
|
||||
|
|
Loading…
Reference in a new issue