mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +01:00
Provide "almanac.binding.search" and "almanac.binding.edit"
Summary: Depends on D19338. Ref T13120. Ref T12414. These are the last of the new API methods. This stuff still doesn't work: - You can't actually enable/disable bindings yet. I want to take a look at the use cases and consider changing "disabled" to "status", or providing a different way to solve the problem. - You can't edit properties via the API. I expect to enable this for all `AlmanacPropertyInterface` objects with an extension in a future change. Test Plan: - Searched for bindings via API. - Viewed binding web UI for API methods. - Created bindings via API. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13120, T12414 Differential Revision: https://secure.phabricator.com/D19340
This commit is contained in:
parent
e502df509d
commit
208504a5e3
7 changed files with 385 additions and 1 deletions
|
@ -14,12 +14,17 @@ phutil_register_library_map(array(
|
|||
'AlmanacBindingDeletePropertyTransaction' => 'applications/almanac/xaction/AlmanacBindingDeletePropertyTransaction.php',
|
||||
'AlmanacBindingDisableController' => 'applications/almanac/controller/AlmanacBindingDisableController.php',
|
||||
'AlmanacBindingDisableTransaction' => 'applications/almanac/xaction/AlmanacBindingDisableTransaction.php',
|
||||
'AlmanacBindingEditConduitAPIMethod' => 'applications/almanac/conduit/AlmanacBindingEditConduitAPIMethod.php',
|
||||
'AlmanacBindingEditController' => 'applications/almanac/controller/AlmanacBindingEditController.php',
|
||||
'AlmanacBindingEditEngine' => 'applications/almanac/editor/AlmanacBindingEditEngine.php',
|
||||
'AlmanacBindingEditor' => 'applications/almanac/editor/AlmanacBindingEditor.php',
|
||||
'AlmanacBindingInterfaceTransaction' => 'applications/almanac/xaction/AlmanacBindingInterfaceTransaction.php',
|
||||
'AlmanacBindingPHIDType' => 'applications/almanac/phid/AlmanacBindingPHIDType.php',
|
||||
'AlmanacBindingPropertyEditEngine' => 'applications/almanac/editor/AlmanacBindingPropertyEditEngine.php',
|
||||
'AlmanacBindingQuery' => 'applications/almanac/query/AlmanacBindingQuery.php',
|
||||
'AlmanacBindingSearchConduitAPIMethod' => 'applications/almanac/conduit/AlmanacBindingSearchConduitAPIMethod.php',
|
||||
'AlmanacBindingSearchEngine' => 'applications/almanac/query/AlmanacBindingSearchEngine.php',
|
||||
'AlmanacBindingServiceTransaction' => 'applications/almanac/xaction/AlmanacBindingServiceTransaction.php',
|
||||
'AlmanacBindingSetPropertyTransaction' => 'applications/almanac/xaction/AlmanacBindingSetPropertyTransaction.php',
|
||||
'AlmanacBindingTableView' => 'applications/almanac/view/AlmanacBindingTableView.php',
|
||||
'AlmanacBindingTransaction' => 'applications/almanac/storage/AlmanacBindingTransaction.php',
|
||||
|
@ -5206,16 +5211,22 @@ phutil_register_library_map(array(
|
|||
'AlmanacPropertyInterface',
|
||||
'PhabricatorDestructibleInterface',
|
||||
'PhabricatorExtendedPolicyInterface',
|
||||
'PhabricatorConduitResultInterface',
|
||||
),
|
||||
'AlmanacBindingDeletePropertyTransaction' => 'AlmanacBindingTransactionType',
|
||||
'AlmanacBindingDisableController' => 'AlmanacServiceController',
|
||||
'AlmanacBindingDisableTransaction' => 'AlmanacBindingTransactionType',
|
||||
'AlmanacBindingEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
|
||||
'AlmanacBindingEditController' => 'AlmanacServiceController',
|
||||
'AlmanacBindingEditEngine' => 'PhabricatorEditEngine',
|
||||
'AlmanacBindingEditor' => 'AlmanacEditor',
|
||||
'AlmanacBindingInterfaceTransaction' => 'AlmanacBindingTransactionType',
|
||||
'AlmanacBindingPHIDType' => 'PhabricatorPHIDType',
|
||||
'AlmanacBindingPropertyEditEngine' => 'AlmanacPropertyEditEngine',
|
||||
'AlmanacBindingQuery' => 'AlmanacQuery',
|
||||
'AlmanacBindingSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
||||
'AlmanacBindingSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'AlmanacBindingServiceTransaction' => 'AlmanacBindingTransactionType',
|
||||
'AlmanacBindingSetPropertyTransaction' => 'AlmanacBindingTransactionType',
|
||||
'AlmanacBindingTableView' => 'AphrontView',
|
||||
'AlmanacBindingTransaction' => 'AlmanacModularTransaction',
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
final class AlmanacBindingEditConduitAPIMethod
|
||||
extends PhabricatorEditEngineAPIMethod {
|
||||
|
||||
public function getAPIMethodName() {
|
||||
return 'almanac.binding.edit';
|
||||
}
|
||||
|
||||
public function newEditEngine() {
|
||||
return new AlmanacBindingEditEngine();
|
||||
}
|
||||
|
||||
public function getMethodSummary() {
|
||||
return pht(
|
||||
'Apply transactions to create a new binding or edit an existing one.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
final class AlmanacBindingSearchConduitAPIMethod
|
||||
extends PhabricatorSearchEngineAPIMethod {
|
||||
|
||||
public function getAPIMethodName() {
|
||||
return 'almanac.binding.search';
|
||||
}
|
||||
|
||||
public function newSearchEngine() {
|
||||
return new AlmanacBindingSearchEngine();
|
||||
}
|
||||
|
||||
public function getMethodSummary() {
|
||||
return pht('Read information about Almanac bindings.');
|
||||
}
|
||||
|
||||
}
|
158
src/applications/almanac/editor/AlmanacBindingEditEngine.php
Normal file
158
src/applications/almanac/editor/AlmanacBindingEditEngine.php
Normal file
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
final class AlmanacBindingEditEngine
|
||||
extends PhabricatorEditEngine {
|
||||
|
||||
const ENGINECONST = 'almanac.binding';
|
||||
|
||||
private $service;
|
||||
|
||||
public function setService(AlmanacService $service) {
|
||||
$this->service = $service;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getService() {
|
||||
if (!$this->service) {
|
||||
throw new PhutilInvalidStateException('setService');
|
||||
}
|
||||
return $this->service;
|
||||
}
|
||||
|
||||
public function isEngineConfigurable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getEngineName() {
|
||||
return pht('Almanac Bindings');
|
||||
}
|
||||
|
||||
public function getSummaryHeader() {
|
||||
return pht('Edit Almanac Binding Configurations');
|
||||
}
|
||||
|
||||
public function getSummaryText() {
|
||||
return pht('This engine is used to edit Almanac bindings.');
|
||||
}
|
||||
|
||||
public function getEngineApplicationClass() {
|
||||
return 'PhabricatorAlmanacApplication';
|
||||
}
|
||||
|
||||
protected function newEditableObject() {
|
||||
$service = $this->getService();
|
||||
return AlmanacBinding::initializeNewBinding($service);
|
||||
}
|
||||
|
||||
protected function newEditableObjectForDocumentation() {
|
||||
$service_type = AlmanacCustomServiceType::SERVICETYPE;
|
||||
$service = AlmanacService::initializeNewService($service_type);
|
||||
$this->setService($service);
|
||||
return $this->newEditableObject();
|
||||
}
|
||||
|
||||
protected function newEditableObjectFromConduit(array $raw_xactions) {
|
||||
$service_phid = null;
|
||||
foreach ($raw_xactions as $raw_xaction) {
|
||||
if ($raw_xaction['type'] !== 'service') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$service_phid = $raw_xaction['value'];
|
||||
}
|
||||
|
||||
if ($service_phid === null) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'When creating a new Almanac binding via the Conduit API, you '.
|
||||
'must provide a "service" transaction to select a service to bind.'));
|
||||
}
|
||||
|
||||
$service = id(new AlmanacServiceQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs(array($service_phid))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$service) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Service "%s" is unrecognized, restricted, or you do not have '.
|
||||
'permission to edit it.',
|
||||
$service_phid));
|
||||
}
|
||||
|
||||
$this->setService($service);
|
||||
|
||||
return $this->newEditableObject();
|
||||
}
|
||||
|
||||
protected function newObjectQuery() {
|
||||
return new AlmanacBindingQuery();
|
||||
}
|
||||
|
||||
protected function getObjectCreateTitleText($object) {
|
||||
return pht('Create Binding');
|
||||
}
|
||||
|
||||
protected function getObjectCreateButtonText($object) {
|
||||
return pht('Create Binding');
|
||||
}
|
||||
|
||||
protected function getObjectEditTitleText($object) {
|
||||
return pht('Edit Binding');
|
||||
}
|
||||
|
||||
protected function getObjectEditShortText($object) {
|
||||
return pht('Edit Binding');
|
||||
}
|
||||
|
||||
protected function getObjectCreateShortText() {
|
||||
return pht('Create Binding');
|
||||
}
|
||||
|
||||
protected function getObjectName() {
|
||||
return pht('Binding');
|
||||
}
|
||||
|
||||
protected function getEditorURI() {
|
||||
return '/almanac/binding/edit/';
|
||||
}
|
||||
|
||||
protected function getObjectCreateCancelURI($object) {
|
||||
return '/almanac/binding/';
|
||||
}
|
||||
|
||||
protected function getObjectViewURI($object) {
|
||||
return $object->getURI();
|
||||
}
|
||||
|
||||
protected function buildCustomEditFields($object) {
|
||||
return array(
|
||||
id(new PhabricatorTextEditField())
|
||||
->setKey('service')
|
||||
->setLabel(pht('Service'))
|
||||
->setIsConduitOnly(true)
|
||||
->setTransactionType(
|
||||
AlmanacBindingServiceTransaction::TRANSACTIONTYPE)
|
||||
->setDescription(pht('Service to create a binding for.'))
|
||||
->setConduitDescription(pht('Select the service to bind.'))
|
||||
->setConduitTypeDescription(pht('Service PHID.'))
|
||||
->setValue($object->getServicePHID()),
|
||||
id(new PhabricatorTextEditField())
|
||||
->setKey('interface')
|
||||
->setLabel(pht('Interface'))
|
||||
->setIsConduitOnly(true)
|
||||
->setTransactionType(
|
||||
AlmanacBindingInterfaceTransaction::TRANSACTIONTYPE)
|
||||
->setDescription(pht('Interface to bind the service to.'))
|
||||
->setConduitDescription(pht('Set the interface to bind.'))
|
||||
->setConduitTypeDescription(pht('Interface PHID.'))
|
||||
->setValue($object->getInterfacePHID()),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
final class AlmanacBindingSearchEngine
|
||||
extends PhabricatorApplicationSearchEngine {
|
||||
|
||||
public function getResultTypeDescription() {
|
||||
return pht('Almanac Bindings');
|
||||
}
|
||||
|
||||
public function getApplicationClassName() {
|
||||
return 'PhabricatorAlmanacApplication';
|
||||
}
|
||||
|
||||
public function newQuery() {
|
||||
return new AlmanacBindingQuery();
|
||||
}
|
||||
|
||||
protected function buildCustomSearchFields() {
|
||||
return array(
|
||||
id(new PhabricatorPHIDsSearchField())
|
||||
->setLabel(pht('Services'))
|
||||
->setKey('servicePHIDs')
|
||||
->setAliases(array('service', 'servicePHID', 'services'))
|
||||
->setDescription(pht('Search for bindings on particular services.')),
|
||||
id(new PhabricatorPHIDsSearchField())
|
||||
->setLabel(pht('Devices'))
|
||||
->setKey('devicePHIDs')
|
||||
->setAliases(array('device', 'devicePHID', 'devices'))
|
||||
->setDescription(pht('Search for bindings on particular devices.')),
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildQueryFromParameters(array $map) {
|
||||
$query = $this->newQuery();
|
||||
|
||||
if ($map['servicePHIDs']) {
|
||||
$query->withServicePHIDs($map['servicePHIDs']);
|
||||
}
|
||||
|
||||
if ($map['devicePHIDs']) {
|
||||
$query->withDevicePHIDs($map['devicePHIDs']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
protected function getURI($path) {
|
||||
return '/almanac/binding/'.$path;
|
||||
}
|
||||
|
||||
protected function getBuiltinQueryNames() {
|
||||
$names = array(
|
||||
'all' => pht('All Bindings'),
|
||||
);
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
public function buildSavedQueryFromBuiltin($query_key) {
|
||||
$query = $this->newSavedQuery();
|
||||
$query->setQueryKey($query_key);
|
||||
|
||||
switch ($query_key) {
|
||||
case 'all':
|
||||
return $query;
|
||||
}
|
||||
|
||||
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||
}
|
||||
|
||||
protected function renderResultList(
|
||||
array $devices,
|
||||
PhabricatorSavedQuery $query,
|
||||
array $handles) {
|
||||
|
||||
// For now, this SearchEngine just supports API access via Conduit.
|
||||
throw new PhutilMethodNotImplementedException();
|
||||
}
|
||||
|
||||
}
|
|
@ -7,7 +7,8 @@ final class AlmanacBinding
|
|||
PhabricatorApplicationTransactionInterface,
|
||||
AlmanacPropertyInterface,
|
||||
PhabricatorDestructibleInterface,
|
||||
PhabricatorExtendedPolicyInterface {
|
||||
PhabricatorExtendedPolicyInterface,
|
||||
PhabricatorConduitResultInterface {
|
||||
|
||||
protected $servicePHID;
|
||||
protected $devicePHID;
|
||||
|
@ -23,6 +24,7 @@ final class AlmanacBinding
|
|||
public static function initializeNewBinding(AlmanacService $service) {
|
||||
return id(new AlmanacBinding())
|
||||
->setServicePHID($service->getPHID())
|
||||
->attachService($service)
|
||||
->attachAlmanacProperties(array())
|
||||
->setIsDisabled(0);
|
||||
}
|
||||
|
@ -225,4 +227,36 @@ final class AlmanacBinding
|
|||
}
|
||||
|
||||
|
||||
/* -( PhabricatorConduitResultInterface )---------------------------------- */
|
||||
|
||||
|
||||
public function getFieldSpecificationsForConduit() {
|
||||
return array(
|
||||
id(new PhabricatorConduitSearchFieldSpecification())
|
||||
->setKey('servicePHID')
|
||||
->setType('phid')
|
||||
->setDescription(pht('The bound service.')),
|
||||
id(new PhabricatorConduitSearchFieldSpecification())
|
||||
->setKey('devicePHID')
|
||||
->setType('phid')
|
||||
->setDescription(pht('The device the service is bound to.')),
|
||||
id(new PhabricatorConduitSearchFieldSpecification())
|
||||
->setKey('interfacePHID')
|
||||
->setType('phid')
|
||||
->setDescription(pht('The interface the service is bound to.')),
|
||||
);
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit() {
|
||||
return array(
|
||||
'servicePHID' => $this->getServicePHID(),
|
||||
'devicePHID' => $this->getDevicePHID(),
|
||||
'interfacePHID' => $this->getInterfacePHID(),
|
||||
);
|
||||
}
|
||||
|
||||
public function getConduitSearchAttachments() {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
final class AlmanacBindingServiceTransaction
|
||||
extends AlmanacBindingTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'almanac:binding:service';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getServicePHID();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setServicePHID($value);
|
||||
}
|
||||
|
||||
public function validateTransactions($object, array $xactions) {
|
||||
$errors = array();
|
||||
|
||||
$service_phid = $object->getServicePHID();
|
||||
if ($this->isEmptyTextTransaction($service_phid, $xactions)) {
|
||||
$errors[] = $this->newRequiredError(
|
||||
pht('Bindings must have a service.'));
|
||||
}
|
||||
|
||||
foreach ($xactions as $xaction) {
|
||||
if (!$this->isNewObject()) {
|
||||
$errors[] = $this->newInvalidError(
|
||||
pht(
|
||||
'The service for a binding can not be changed once it has '.
|
||||
'been created.'),
|
||||
$xaction);
|
||||
continue;
|
||||
}
|
||||
|
||||
$service_phid = $xaction->getNewValue();
|
||||
$services = id(new AlmanacServiceQuery())
|
||||
->setViewer($this->getActor())
|
||||
->withPHIDs(array($service_phid))
|
||||
->execute();
|
||||
if (!$services) {
|
||||
$errors[] = $this->newInvalidError(
|
||||
pht('You can not bind a nonexistent or restricted service.'),
|
||||
$xaction);
|
||||
continue;
|
||||
}
|
||||
|
||||
$service = head($services);
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$this->getActor(),
|
||||
$service,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
if (!$can_edit) {
|
||||
$errors[] = $this->newInvalidError(
|
||||
pht(
|
||||
'You can not bind a service which you do not have permission '.
|
||||
'to edit.'));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue