mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-15 11:22:40 +01:00
411331469a
Summary: Ref T10246. Ref T6741. When you have a namespace like "phacility.net", require users creating services and devices within it to have edit permission on the namespace. This primarily allows us to lock down future device names in the cluster, so instances can't break themselves once they get access to Almanac. Test Plan: - Configured a `phacility.net` namespace, locked myself out of it. - Could not create new `stuff.phacility.net` services/devices. - Could still edit existing devices I had permission for. - Configured a `free.phacility.net` namespace with more liberal policies. - Could create `me.free.phacility.net`. - Still could not create `other.phacility.net`. Reviewers: chad Reviewed By: chad Maniphest Tasks: T6741, T10246 Differential Revision: https://secure.phabricator.com/D15325
182 lines
5.1 KiB
PHP
182 lines
5.1 KiB
PHP
<?php
|
|
|
|
final class AlmanacNamespaceEditor
|
|
extends PhabricatorApplicationTransactionEditor {
|
|
|
|
public function getEditorApplicationClass() {
|
|
return 'PhabricatorAlmanacApplication';
|
|
}
|
|
|
|
public function getEditorObjectsDescription() {
|
|
return pht('Almanac Namespace');
|
|
}
|
|
|
|
protected function supportsSearch() {
|
|
return true;
|
|
}
|
|
|
|
public function getTransactionTypes() {
|
|
$types = parent::getTransactionTypes();
|
|
|
|
$types[] = AlmanacNamespaceTransaction::TYPE_NAME;
|
|
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
|
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
|
|
|
return $types;
|
|
}
|
|
|
|
protected function getCustomTransactionOldValue(
|
|
PhabricatorLiskDAO $object,
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
switch ($xaction->getTransactionType()) {
|
|
case AlmanacNamespaceTransaction::TYPE_NAME:
|
|
return $object->getName();
|
|
}
|
|
|
|
return parent::getCustomTransactionOldValue($object, $xaction);
|
|
}
|
|
|
|
protected function getCustomTransactionNewValue(
|
|
PhabricatorLiskDAO $object,
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
case AlmanacNamespaceTransaction::TYPE_NAME:
|
|
return $xaction->getNewValue();
|
|
}
|
|
|
|
return parent::getCustomTransactionNewValue($object, $xaction);
|
|
}
|
|
|
|
protected function applyCustomInternalTransaction(
|
|
PhabricatorLiskDAO $object,
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
case AlmanacNamespaceTransaction::TYPE_NAME:
|
|
$object->setName($xaction->getNewValue());
|
|
return;
|
|
}
|
|
|
|
return parent::applyCustomInternalTransaction($object, $xaction);
|
|
}
|
|
|
|
protected function applyCustomExternalTransaction(
|
|
PhabricatorLiskDAO $object,
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
case AlmanacNamespaceTransaction::TYPE_NAME:
|
|
return;
|
|
}
|
|
|
|
return parent::applyCustomExternalTransaction($object, $xaction);
|
|
}
|
|
|
|
protected function validateTransaction(
|
|
PhabricatorLiskDAO $object,
|
|
$type,
|
|
array $xactions) {
|
|
|
|
$errors = parent::validateTransaction($object, $type, $xactions);
|
|
|
|
switch ($type) {
|
|
case AlmanacNamespaceTransaction::TYPE_NAME:
|
|
$missing = $this->validateIsEmptyTextField(
|
|
$object->getName(),
|
|
$xactions);
|
|
|
|
if ($missing) {
|
|
$error = new PhabricatorApplicationTransactionValidationError(
|
|
$type,
|
|
pht('Required'),
|
|
pht('Namespace name is required.'),
|
|
nonempty(last($xactions), null));
|
|
|
|
$error->setIsMissingFieldError(true);
|
|
$errors[] = $error;
|
|
} else {
|
|
foreach ($xactions as $xaction) {
|
|
$name = $xaction->getNewValue();
|
|
|
|
$message = null;
|
|
try {
|
|
AlmanacNames::validateName($name);
|
|
} catch (Exception $ex) {
|
|
$message = $ex->getMessage();
|
|
}
|
|
|
|
if ($message !== null) {
|
|
$error = new PhabricatorApplicationTransactionValidationError(
|
|
$type,
|
|
pht('Invalid'),
|
|
$message,
|
|
$xaction);
|
|
$errors[] = $error;
|
|
continue;
|
|
}
|
|
|
|
$other = id(new AlmanacNamespaceQuery())
|
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
->withNames(array($name))
|
|
->executeOne();
|
|
if ($other && ($other->getID() != $object->getID())) {
|
|
$error = new PhabricatorApplicationTransactionValidationError(
|
|
$type,
|
|
pht('Not Unique'),
|
|
pht(
|
|
'The namespace name "%s" is already in use by another '.
|
|
'namespace. Each namespace must have a unique name.',
|
|
$name),
|
|
$xaction);
|
|
$errors[] = $error;
|
|
continue;
|
|
}
|
|
|
|
if ($name === $object->getName()) {
|
|
continue;
|
|
}
|
|
|
|
$namespace = AlmanacNamespace::loadRestrictedNamespace(
|
|
$this->getActor(),
|
|
$name);
|
|
if ($namespace) {
|
|
$error = new PhabricatorApplicationTransactionValidationError(
|
|
$type,
|
|
pht('Restricted'),
|
|
pht(
|
|
'You do not have permission to create Almanac namespaces '.
|
|
'within the "%s" namespace.',
|
|
$namespace->getName()),
|
|
$xaction);
|
|
$errors[] = $error;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return $errors;
|
|
}
|
|
|
|
protected function didCatchDuplicateKeyException(
|
|
PhabricatorLiskDAO $object,
|
|
array $xactions,
|
|
Exception $ex) {
|
|
|
|
$errors = array();
|
|
|
|
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
|
null,
|
|
pht('Invalid'),
|
|
pht(
|
|
'Another namespace with this name already exists. Each namespace '.
|
|
'must have a unique name.'),
|
|
null);
|
|
|
|
throw new PhabricatorApplicationTransactionValidationException($errors);
|
|
}
|
|
|
|
}
|