mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 08:42: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',
|
'AlmanacBindingDeletePropertyTransaction' => 'applications/almanac/xaction/AlmanacBindingDeletePropertyTransaction.php',
|
||||||
'AlmanacBindingDisableController' => 'applications/almanac/controller/AlmanacBindingDisableController.php',
|
'AlmanacBindingDisableController' => 'applications/almanac/controller/AlmanacBindingDisableController.php',
|
||||||
'AlmanacBindingDisableTransaction' => 'applications/almanac/xaction/AlmanacBindingDisableTransaction.php',
|
'AlmanacBindingDisableTransaction' => 'applications/almanac/xaction/AlmanacBindingDisableTransaction.php',
|
||||||
|
'AlmanacBindingEditConduitAPIMethod' => 'applications/almanac/conduit/AlmanacBindingEditConduitAPIMethod.php',
|
||||||
'AlmanacBindingEditController' => 'applications/almanac/controller/AlmanacBindingEditController.php',
|
'AlmanacBindingEditController' => 'applications/almanac/controller/AlmanacBindingEditController.php',
|
||||||
|
'AlmanacBindingEditEngine' => 'applications/almanac/editor/AlmanacBindingEditEngine.php',
|
||||||
'AlmanacBindingEditor' => 'applications/almanac/editor/AlmanacBindingEditor.php',
|
'AlmanacBindingEditor' => 'applications/almanac/editor/AlmanacBindingEditor.php',
|
||||||
'AlmanacBindingInterfaceTransaction' => 'applications/almanac/xaction/AlmanacBindingInterfaceTransaction.php',
|
'AlmanacBindingInterfaceTransaction' => 'applications/almanac/xaction/AlmanacBindingInterfaceTransaction.php',
|
||||||
'AlmanacBindingPHIDType' => 'applications/almanac/phid/AlmanacBindingPHIDType.php',
|
'AlmanacBindingPHIDType' => 'applications/almanac/phid/AlmanacBindingPHIDType.php',
|
||||||
'AlmanacBindingPropertyEditEngine' => 'applications/almanac/editor/AlmanacBindingPropertyEditEngine.php',
|
'AlmanacBindingPropertyEditEngine' => 'applications/almanac/editor/AlmanacBindingPropertyEditEngine.php',
|
||||||
'AlmanacBindingQuery' => 'applications/almanac/query/AlmanacBindingQuery.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',
|
'AlmanacBindingSetPropertyTransaction' => 'applications/almanac/xaction/AlmanacBindingSetPropertyTransaction.php',
|
||||||
'AlmanacBindingTableView' => 'applications/almanac/view/AlmanacBindingTableView.php',
|
'AlmanacBindingTableView' => 'applications/almanac/view/AlmanacBindingTableView.php',
|
||||||
'AlmanacBindingTransaction' => 'applications/almanac/storage/AlmanacBindingTransaction.php',
|
'AlmanacBindingTransaction' => 'applications/almanac/storage/AlmanacBindingTransaction.php',
|
||||||
|
@ -5206,16 +5211,22 @@ phutil_register_library_map(array(
|
||||||
'AlmanacPropertyInterface',
|
'AlmanacPropertyInterface',
|
||||||
'PhabricatorDestructibleInterface',
|
'PhabricatorDestructibleInterface',
|
||||||
'PhabricatorExtendedPolicyInterface',
|
'PhabricatorExtendedPolicyInterface',
|
||||||
|
'PhabricatorConduitResultInterface',
|
||||||
),
|
),
|
||||||
'AlmanacBindingDeletePropertyTransaction' => 'AlmanacBindingTransactionType',
|
'AlmanacBindingDeletePropertyTransaction' => 'AlmanacBindingTransactionType',
|
||||||
'AlmanacBindingDisableController' => 'AlmanacServiceController',
|
'AlmanacBindingDisableController' => 'AlmanacServiceController',
|
||||||
'AlmanacBindingDisableTransaction' => 'AlmanacBindingTransactionType',
|
'AlmanacBindingDisableTransaction' => 'AlmanacBindingTransactionType',
|
||||||
|
'AlmanacBindingEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
|
||||||
'AlmanacBindingEditController' => 'AlmanacServiceController',
|
'AlmanacBindingEditController' => 'AlmanacServiceController',
|
||||||
|
'AlmanacBindingEditEngine' => 'PhabricatorEditEngine',
|
||||||
'AlmanacBindingEditor' => 'AlmanacEditor',
|
'AlmanacBindingEditor' => 'AlmanacEditor',
|
||||||
'AlmanacBindingInterfaceTransaction' => 'AlmanacBindingTransactionType',
|
'AlmanacBindingInterfaceTransaction' => 'AlmanacBindingTransactionType',
|
||||||
'AlmanacBindingPHIDType' => 'PhabricatorPHIDType',
|
'AlmanacBindingPHIDType' => 'PhabricatorPHIDType',
|
||||||
'AlmanacBindingPropertyEditEngine' => 'AlmanacPropertyEditEngine',
|
'AlmanacBindingPropertyEditEngine' => 'AlmanacPropertyEditEngine',
|
||||||
'AlmanacBindingQuery' => 'AlmanacQuery',
|
'AlmanacBindingQuery' => 'AlmanacQuery',
|
||||||
|
'AlmanacBindingSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
||||||
|
'AlmanacBindingSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
'AlmanacBindingServiceTransaction' => 'AlmanacBindingTransactionType',
|
||||||
'AlmanacBindingSetPropertyTransaction' => 'AlmanacBindingTransactionType',
|
'AlmanacBindingSetPropertyTransaction' => 'AlmanacBindingTransactionType',
|
||||||
'AlmanacBindingTableView' => 'AphrontView',
|
'AlmanacBindingTableView' => 'AphrontView',
|
||||||
'AlmanacBindingTransaction' => 'AlmanacModularTransaction',
|
'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,
|
PhabricatorApplicationTransactionInterface,
|
||||||
AlmanacPropertyInterface,
|
AlmanacPropertyInterface,
|
||||||
PhabricatorDestructibleInterface,
|
PhabricatorDestructibleInterface,
|
||||||
PhabricatorExtendedPolicyInterface {
|
PhabricatorExtendedPolicyInterface,
|
||||||
|
PhabricatorConduitResultInterface {
|
||||||
|
|
||||||
protected $servicePHID;
|
protected $servicePHID;
|
||||||
protected $devicePHID;
|
protected $devicePHID;
|
||||||
|
@ -23,6 +24,7 @@ final class AlmanacBinding
|
||||||
public static function initializeNewBinding(AlmanacService $service) {
|
public static function initializeNewBinding(AlmanacService $service) {
|
||||||
return id(new AlmanacBinding())
|
return id(new AlmanacBinding())
|
||||||
->setServicePHID($service->getPHID())
|
->setServicePHID($service->getPHID())
|
||||||
|
->attachService($service)
|
||||||
->attachAlmanacProperties(array())
|
->attachAlmanacProperties(array())
|
||||||
->setIsDisabled(0);
|
->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