Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15381206
D17235.id41450.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
17 KB
Referenced Files
None
Subscribers
None
D17235.id41450.diff
View Options
diff --git a/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php b/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php
--- a/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php
+++ b/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php
@@ -149,4 +149,47 @@
return $fields;
}
+ protected function getValidationExceptionShortMessage(
+ PhabricatorApplicationTransactionValidationException $ex,
+ PhabricatorEditField $field) {
+
+ // Menu item properties all have the same transaction type, so we need
+ // to make sure errors about a specific property (like the URI for a
+ // link) are only applied to the field for that particular property. If
+ // we don't do this, the red error text like "Required" will display
+ // next to every field.
+
+ $property_type =
+ PhabricatorProfileMenuItemConfigurationTransaction::TYPE_PROPERTY;
+
+ $xaction_type = $field->getTransactionType();
+ if ($xaction_type == $property_type) {
+ $field_key = $field->getKey();
+ foreach ($ex->getErrors() as $error) {
+ if ($error->getType() !== $xaction_type) {
+ continue;
+ }
+
+ $xaction = $error->getTransaction();
+ if (!$xaction) {
+ continue;
+ }
+
+ $xaction_setting = $xaction->getMetadataValue('property.key');
+ if ($xaction_setting != $field_key) {
+ continue;
+ }
+
+ $short_message = $error->getShortMessage();
+ if ($short_message !== null) {
+ return $short_message;
+ }
+ }
+
+ return null;
+ }
+
+ return parent::getValidationExceptionShortMessage($ex, $field);
+ }
+
}
diff --git a/src/applications/search/editor/PhabricatorProfileMenuEditor.php b/src/applications/search/editor/PhabricatorProfileMenuEditor.php
--- a/src/applications/search/editor/PhabricatorProfileMenuEditor.php
+++ b/src/applications/search/editor/PhabricatorProfileMenuEditor.php
@@ -87,4 +87,39 @@
return parent::applyCustomExternalTransaction($object, $xaction);
}
+ protected function validateTransaction(
+ PhabricatorLiskDAO $object,
+ $type,
+ array $xactions) {
+
+ $errors = parent::validateTransaction($object, $type, $xactions);
+
+ $actor = $this->getActor();
+ $menu_item = $object->getMenuItem();
+ $menu_item->setViewer($actor);
+
+ switch ($type) {
+ case PhabricatorProfileMenuItemConfigurationTransaction::TYPE_PROPERTY:
+ $key_map = array();
+ foreach ($xactions as $xaction) {
+ $xaction_key = $xaction->getMetadataValue('property.key');
+ $old = $this->getCustomTransactionOldValue($object, $xaction);
+ $new = $xaction->getNewValue();
+ $key_map[$xaction_key][] = array(
+ 'xaction' => $xaction,
+ 'old' => $old,
+ 'new' => $new,
+ );
+ }
+
+ foreach ($object->validateTransactions($key_map) as $error) {
+ $errors[] = $error;
+ }
+ break;
+ }
+
+ return $errors;
+ }
+
+
}
diff --git a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php
--- a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php
+++ b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php
@@ -5,6 +5,8 @@
const MENUITEMKEY = 'application';
+ const FIELD_APPLICATION = 'application';
+
public function getMenuItemTypeIcon() {
return 'fa-globe';
}
@@ -32,10 +34,11 @@
PhabricatorProfileMenuItemConfiguration $config) {
return array(
id(new PhabricatorDatasourceEditField())
- ->setKey('application')
+ ->setKey(self::FIELD_APPLICATION)
->setLabel(pht('Application'))
->setIsRequired(true)
->setDatasource(new PhabricatorApplicationDatasource())
+ ->setIsRequired(true)
->setSingleValue($config->getMenuItemProperty('application')),
);
}
@@ -44,6 +47,7 @@
PhabricatorProfileMenuItemConfiguration $config) {
$viewer = $this->getViewer();
$phid = $config->getMenuItemProperty('application');
+
$app = id(new PhabricatorApplicationQuery())
->setViewer($viewer)
->withPHIDs(array($phid))
@@ -77,4 +81,49 @@
);
}
+ public function validateTransactions(
+ PhabricatorProfileMenuItemConfiguration $config,
+ $field_key,
+ $value,
+ array $xactions) {
+
+ $viewer = $this->getViewer();
+ $errors = array();
+
+ if ($field_key == self::FIELD_APPLICATION) {
+ if ($this->isEmptyTransaction($value, $xactions)) {
+ $errors[] = $this->newRequiredError(
+ pht('You must choose an application.'),
+ $field_key);
+ }
+
+ foreach ($xactions as $xaction) {
+ $new = $xaction['new'];
+
+ if (!$new) {
+ continue;
+ }
+
+ if ($new === $value) {
+ continue;
+ }
+
+ $applications = id(new PhabricatorApplicationQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($new))
+ ->execute();
+ if (!$applications) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Application "%s" is not a valid application which you have '.
+ 'permission to see.',
+ $new),
+ $xaction['xaction']);
+ }
+ }
+ }
+
+ return $errors;
+ }
+
}
diff --git a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php
--- a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php
+++ b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php
@@ -5,6 +5,8 @@
const MENUITEMKEY = 'dashboard';
+ const FIELD_DASHBOARD = 'dashboardPHID';
+
private $dashboard;
public function getMenuItemTypeIcon() {
@@ -75,7 +77,7 @@
->setLabel(pht('Name'))
->setValue($this->getName($config)),
id(new PhabricatorDatasourceEditField())
- ->setKey('dashboardPHID')
+ ->setKey(self::FIELD_DASHBOARD)
->setLabel(pht('Dashboard'))
->setIsRequired(true)
->setDatasource(new PhabricatorDashboardDatasource())
@@ -110,4 +112,49 @@
);
}
+ public function validateTransactions(
+ PhabricatorProfileMenuItemConfiguration $config,
+ $field_key,
+ $value,
+ array $xactions) {
+
+ $viewer = $this->getViewer();
+ $errors = array();
+
+ if ($field_key == self::FIELD_DASHBOARD) {
+ if ($this->isEmptyTransaction($value, $xactions)) {
+ $errors[] = $this->newRequiredError(
+ pht('You must choose a dashboard.'),
+ $field_key);
+ }
+
+ foreach ($xactions as $xaction) {
+ $new = $xaction['new'];
+
+ if (!$new) {
+ continue;
+ }
+
+ if ($new === $value) {
+ continue;
+ }
+
+ $dashboards = id(new PhabricatorDashboardQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($new))
+ ->execute();
+ if (!$dashboards) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Dashboard "%s" is not a valid dashboard which you have '.
+ 'permission to see.',
+ $new),
+ $xaction['xaction']);
+ }
+ }
+ }
+
+ return $errors;
+ }
+
}
diff --git a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php
--- a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php
+++ b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php
@@ -5,6 +5,8 @@
const MENUITEMKEY = 'editengine';
+ const FIELD_FORM = 'formKey';
+
private $form;
public function getMenuItemTypeIcon() {
@@ -51,7 +53,8 @@
foreach ($items as $item) {
$key = $item->getMenuItemProperty('formKey');
- list($engine_key, $form_key) = explode('/', $key);
+ list($engine_key, $form_key) = PhabricatorEditEngine::splitFullKey($key);
+
if (is_numeric($form_key)) {
$form = idx($form_ids, $form_key, null);
$item->getMenuItem()->attachForm($form);
@@ -83,7 +86,7 @@
->setLabel(pht('Name'))
->setValue($this->getName($config)),
id(new PhabricatorDatasourceEditField())
- ->setKey('formKey')
+ ->setKey(self::FIELD_FORM)
->setLabel(pht('Form'))
->setIsRequired(true)
->setDatasource(new PhabricatorEditEngineDatasource())
@@ -120,4 +123,53 @@
);
}
+ public function validateTransactions(
+ PhabricatorProfileMenuItemConfiguration $config,
+ $field_key,
+ $value,
+ array $xactions) {
+
+ $viewer = $this->getViewer();
+ $errors = array();
+
+ if ($field_key == self::FIELD_FORM) {
+ if ($this->isEmptyTransaction($value, $xactions)) {
+ $errors[] = $this->newRequiredError(
+ pht('You must choose a form.'),
+ $field_key);
+ }
+
+ foreach ($xactions as $xaction) {
+ $new = $xaction['new'];
+
+ if (!$new) {
+ continue;
+ }
+
+ if ($new === $value) {
+ continue;
+ }
+
+ list($engine_key, $form_key) = PhabricatorEditEngine::splitFullKey(
+ $new);
+
+ $forms = id(new PhabricatorEditEngineConfigurationQuery())
+ ->setViewer($viewer)
+ ->withEngineKeys(array($engine_key))
+ ->withIdentifiers(array($form_key))
+ ->execute();
+ if (!$forms) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Form "%s" is not a valid form which you have permission to '.
+ 'see.',
+ $new),
+ $xaction['xaction']);
+ }
+ }
+ }
+
+ return $errors;
+ }
+
}
diff --git a/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php
--- a/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php
+++ b/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php
@@ -5,6 +5,9 @@
const MENUITEMKEY = 'link';
+ const FIELD_URI = 'uri';
+ const FIELD_NAME = 'name';
+
public function getMenuItemTypeIcon() {
return 'fa-link';
}
@@ -26,12 +29,12 @@
PhabricatorProfileMenuItemConfiguration $config) {
return array(
id(new PhabricatorTextEditField())
- ->setKey('name')
+ ->setKey(self::FIELD_NAME)
->setLabel(pht('Name'))
->setIsRequired(true)
->setValue($this->getLinkName($config)),
id(new PhabricatorTextEditField())
- ->setKey('uri')
+ ->setKey(self::FIELD_URI)
->setLabel(pht('URI'))
->setIsRequired(true)
->setValue($this->getLinkURI($config)),
@@ -91,4 +94,53 @@
);
}
+ public function validateTransactions(
+ PhabricatorProfileMenuItemConfiguration $config,
+ $field_key,
+ $value,
+ array $xactions) {
+
+ $viewer = $this->getViewer();
+ $errors = array();
+
+ if ($field_key == self::FIELD_NAME) {
+ if ($this->isEmptyTransaction($value, $xactions)) {
+ $errors[] = $this->newRequiredError(
+ pht('You must choose a link name.'),
+ $field_key);
+ }
+ }
+
+ if ($field_key == self::FIELD_URI) {
+ if ($this->isEmptyTransaction($value, $xactions)) {
+ $errors[] = $this->newRequiredError(
+ pht('You must choose a URI to link to.'),
+ $field_key);
+ }
+
+ foreach ($xactions as $xaction) {
+ $new = $xaction['new'];
+
+ if (!$new) {
+ continue;
+ }
+
+ if ($new === $value) {
+ continue;
+ }
+
+ if (!$this->isValidLinkURI($new)) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'URI "%s" is not a valid link URI. It should be a full, valid '.
+ 'URI beginning with a protocol like "%s".',
+ $new,
+ 'https://'),
+ $xaction['xaction']);
+ }
+ }
+ }
+
+ return $errors;
+ }
}
diff --git a/src/applications/search/menuitem/PhabricatorProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorProfileMenuItem.php
--- a/src/applications/search/menuitem/PhabricatorProfileMenuItem.php
+++ b/src/applications/search/menuitem/PhabricatorProfileMenuItem.php
@@ -70,4 +70,41 @@
return new PHUIListItemView();
}
+ public function valdateTransactions(
+ PhabricatorProfileMenuItemConfiguration $config,
+ $field_key,
+ $value,
+ array $xactions) {
+ return array();
+ }
+
+ final protected function isEmptyTransaction($value, array $xactions) {
+ $result = $value;
+ foreach ($xactions as $xaction) {
+ $result = $xaction['new'];
+ }
+
+ return !strlen($result);
+ }
+
+ final protected function newError($title, $message, $xaction = null) {
+ return new PhabricatorApplicationTransactionValidationError(
+ PhabricatorProfileMenuItemConfigurationTransaction::TYPE_PROPERTY,
+ $title,
+ $message,
+ $xaction);
+ }
+
+ final protected function newRequiredError($message, $type) {
+ $xaction = id(new PhabricatorProfileMenuItemConfigurationTransaction())
+ ->setMetadataValue('property.key', $type);
+
+ return $this->newError(pht('Required'), $message, $xaction)
+ ->setIsMissingFieldError(true);
+ }
+
+ final protected function newInvalidError($message, $xaction = null) {
+ return $this->newError(pht('Invalid'), $message, $xaction);
+ }
+
}
diff --git a/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php
--- a/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php
+++ b/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php
@@ -4,6 +4,7 @@
extends PhabricatorProfileMenuItem {
const MENUITEMKEY = 'project';
+ const FIELD_PROJECT = 'project';
private $project;
@@ -76,7 +77,7 @@
->setLabel(pht('Name'))
->setValue($this->getName($config)),
id(new PhabricatorDatasourceEditField())
- ->setKey('project')
+ ->setKey(self::FIELD_PROJECT)
->setLabel(pht('Project'))
->setIsRequired(true)
->setDatasource(new PhabricatorProjectDatasource())
@@ -111,4 +112,49 @@
);
}
+ public function validateTransactions(
+ PhabricatorProfileMenuItemConfiguration $config,
+ $field_key,
+ $value,
+ array $xactions) {
+
+ $viewer = $this->getViewer();
+ $errors = array();
+
+ if ($field_key == self::FIELD_PROJECT) {
+ if ($this->isEmptyTransaction($value, $xactions)) {
+ $errors[] = $this->newRequiredError(
+ pht('You must choose a project.'),
+ $field_key);
+ }
+
+ foreach ($xactions as $xaction) {
+ $new = $xaction['new'];
+
+ if (!$new) {
+ continue;
+ }
+
+ if ($new === $value) {
+ continue;
+ }
+
+ $projects = id(new PhabricatorProjectQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($new))
+ ->execute();
+ if (!$projects) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Project "%s" is not a valid project which you have '.
+ 'permission to see.',
+ $new),
+ $xaction['xaction']);
+ }
+ }
+ }
+
+ return $errors;
+ }
+
}
diff --git a/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php b/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php
--- a/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php
+++ b/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php
@@ -126,6 +126,30 @@
return $this->getMenuItem()->willBuildNavigationItems($items);
}
+ public function validateTransactions(array $map) {
+ $item = $this->getMenuItem();
+
+ $fields = $item->buildEditEngineFields($this);
+ $errors = array();
+ foreach ($fields as $field) {
+ $field_key = $field->getKey();
+
+ $xactions = idx($map, $field_key, array());
+ $value = $this->getMenuItemProperty($field_key);
+
+ $field_errors = $item->validateTransactions(
+ $this,
+ $field_key,
+ $value,
+ $xactions);
+ foreach ($field_errors as $error) {
+ $errors[] = $error;
+ }
+ }
+
+ return $errors;
+ }
+
public function getSortVector() {
// Sort custom items above global items.
if ($this->getCustomPHID()) {
diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php
--- a/src/applications/transactions/editengine/PhabricatorEditEngine.php
+++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php
@@ -95,6 +95,10 @@
return $keys;
}
+ public static function splitFullKey($full_key) {
+ return explode('/', $full_key, 2);
+ }
+
public function getQuickCreateOrderVector() {
return id(new PhutilSortVector())
->addString($this->getObjectCreateShortText());
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Mar 15, 6:29 AM (1 w, 23 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7441077
Default Alt Text
D17235.id41450.diff (17 KB)
Attached To
Mode
D17235: Validate menu item fields (links, projects, dashboards, applications, forms, etc)
Attached
Detach File
Event Timeline
Log In to Comment