Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/config/option/PhabricatorApplicationConfigOptions.php b/src/applications/config/option/PhabricatorApplicationConfigOptions.php
index d99cdf3101..491852eab6 100644
--- a/src/applications/config/option/PhabricatorApplicationConfigOptions.php
+++ b/src/applications/config/option/PhabricatorApplicationConfigOptions.php
@@ -1,249 +1,256 @@
<?php
abstract class PhabricatorApplicationConfigOptions extends Phobject {
abstract public function getName();
abstract public function getDescription();
abstract public function getGroup();
abstract public function getOptions();
public function getFontIcon() {
return 'fa-sliders';
}
public function validateOption(PhabricatorConfigOption $option, $value) {
if ($value === $option->getDefault()) {
return;
}
if ($value === null) {
return;
}
if ($option->isCustomType()) {
- return $option->getCustomObject()->validateOption($option, $value);
+ try {
+ return $option->getCustomObject()->validateOption($option, $value);
+ } catch (Exception $ex) {
+ // If custom validators threw exceptions, convert them to configuation
+ // validation exceptions so we repair the configuration and raise
+ // an error.
+ throw new PhabricatorConfigValidationException($ex->getMessage());
+ }
}
switch ($option->getType()) {
case 'bool':
if ($value !== true &&
$value !== false) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' is of type bool, but value is not true or false.",
$option->getKey()));
}
break;
case 'int':
if (!is_int($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' is of type int, but value is not an integer.",
$option->getKey()));
}
break;
case 'string':
if (!is_string($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' is of type string, but value is not a string.",
$option->getKey()));
}
break;
case 'class':
$symbols = id(new PhutilSymbolLoader())
->setType('class')
->setAncestorClass($option->getBaseClass())
->setConcreteOnly(true)
->selectSymbolsWithoutLoading();
$names = ipull($symbols, 'name', 'name');
if (empty($names[$value])) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' value must name a class extending '%s'.",
$option->getKey(),
$option->getBaseClass()));
}
break;
case 'set':
$valid = true;
if (!is_array($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a set, but value is not an array.",
$option->getKey()));
}
foreach ($value as $v) {
if ($v !== true) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a set, but array contains values other ".
"than 'true'.",
$option->getKey()));
}
}
break;
case 'list<regex>':
$valid = true;
if (!is_array($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of regular expressions, but value ".
"is not an array.",
$option->getKey()));
}
if ($value && array_keys($value) != range(0, count($value) - 1)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of regular expressions, but the ".
"value is a map with unnatural keys.",
$option->getKey()));
}
foreach ($value as $v) {
$ok = @preg_match($v, '');
if ($ok === false) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of regular expressions, but the ".
"value '%s' is not a valid regular expression.",
$option->getKey(),
$v));
}
}
break;
case 'list<string>':
$valid = true;
if (!is_array($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of strings, but value is not ".
"an array.",
$option->getKey()));
}
if ($value && array_keys($value) != range(0, count($value) - 1)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of strings, but the value is a ".
"map with unnatural keys.",
$option->getKey()));
}
foreach ($value as $v) {
if (!is_string($v)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of strings, but it contains one ".
"or more non-strings.",
$option->getKey()));
}
}
break;
case 'wild':
default:
break;
}
$this->didValidateOption($option, $value);
}
protected function didValidateOption(
PhabricatorConfigOption $option,
$value) {
// Hook for subclasses to do complex validation.
return;
}
/**
* Hook to render additional hints based on, e.g., the viewing user, request,
* or other context. For example, this is used to show workspace IDs when
* configuring `asana.workspace-id`.
*
* @param PhabricatorConfigOption Option being rendered.
* @param AphrontRequest Active request.
* @return wild Additional contextual description
* information.
*/
public function renderContextualDescription(
PhabricatorConfigOption $option,
AphrontRequest $request) {
return null;
}
public function getKey() {
$class = get_class($this);
$matches = null;
if (preg_match('/^Phabricator(.*)ConfigOptions$/', $class, $matches)) {
return strtolower($matches[1]);
}
return strtolower(get_class($this));
}
final protected function newOption($key, $type, $default) {
return id(new PhabricatorConfigOption())
->setKey($key)
->setType($type)
->setDefault($default)
->setGroup($this);
}
final public static function loadAll($external_only = false) {
$symbols = id(new PhutilSymbolLoader())
->setAncestorClass(__CLASS__)
->setConcreteOnly(true)
->selectAndLoadSymbols();
$groups = array();
foreach ($symbols as $symbol) {
if ($external_only && $symbol['library'] == 'phabricator') {
continue;
}
$obj = newv($symbol['name'], array());
$key = $obj->getKey();
if (isset($groups[$key])) {
$pclass = get_class($groups[$key]);
$nclass = $symbol['name'];
throw new Exception(
pht(
"Multiple %s subclasses have the same key ('%s'): %s, %s.",
__CLASS__,
$key,
$pclass,
$nclass));
}
$groups[$key] = $obj;
}
return $groups;
}
final public static function loadAllOptions($external_only = false) {
$groups = self::loadAll($external_only);
$options = array();
foreach ($groups as $group) {
foreach ($group->getOptions() as $option) {
$key = $option->getKey();
if (isset($options[$key])) {
throw new Exception(
pht(
"Mulitple %s subclasses contain an option named '%s'!",
__CLASS__,
$key));
}
$options[$key] = $option;
}
}
return $options;
}
/**
* Deformat a HEREDOC for use in remarkup by converting line breaks to
* spaces.
*/
final protected function deformat($string) {
return preg_replace('/(?<=\S)\n(?=\S)/', ' ', $string);
}
}
diff --git a/src/applications/maniphest/constants/ManiphestTaskPriority.php b/src/applications/maniphest/constants/ManiphestTaskPriority.php
index 6bd1460628..16a35a9e83 100644
--- a/src/applications/maniphest/constants/ManiphestTaskPriority.php
+++ b/src/applications/maniphest/constants/ManiphestTaskPriority.php
@@ -1,148 +1,156 @@
<?php
final class ManiphestTaskPriority extends ManiphestConstants {
/**
* Get the priorities and their full descriptions.
*
* @return map Priorities to descriptions.
*/
public static function getTaskPriorityMap() {
$map = self::getConfig();
foreach ($map as $key => $spec) {
$map[$key] = idx($spec, 'name', $key);
}
return $map;
}
/**
* Get the priorities and their command keywords.
*
* @return map Priorities to lists of command keywords.
*/
public static function getTaskPriorityKeywordsMap() {
$map = self::getConfig();
foreach ($map as $key => $spec) {
$words = idx($spec, 'keywords', array());
if (!is_array($words)) {
$words = array($words);
}
foreach ($words as $word_key => $word) {
$words[$word_key] = phutil_utf8_strtolower($word);
}
$words = array_unique($words);
$map[$key] = $words;
}
return $map;
}
/**
* Get the priorities and their related short (one-word) descriptions.
*
* @return map Priorities to short descriptions.
*/
public static function getShortNameMap() {
$map = self::getConfig();
foreach ($map as $key => $spec) {
$map[$key] = idx($spec, 'short', idx($spec, 'name', $key));
}
return $map;
}
/**
* Get a map from priority constants to their colors.
*
* @return map<int, string> Priorities to colors.
*/
public static function getColorMap() {
$map = self::getConfig();
foreach ($map as $key => $spec) {
$map[$key] = idx($spec, 'color', 'grey');
}
return $map;
}
/**
* Return the default priority for this instance of Phabricator.
*
* @return int The value of the default priority constant.
*/
public static function getDefaultPriority() {
return PhabricatorEnv::getEnvConfig('maniphest.default-priority');
}
/**
* Retrieve the full name of the priority level provided.
*
* @param int A priority level.
* @return string The priority name if the level is a valid one.
*/
public static function getTaskPriorityName($priority) {
return idx(self::getTaskPriorityMap(), $priority, $priority);
}
/**
* Retrieve the color of the priority level given
*
* @param int A priority level.
* @return string The color of the priority if the level is valid,
* or black if it is not.
*/
public static function getTaskPriorityColor($priority) {
return idx(self::getColorMap(), $priority, 'black');
}
public static function getTaskPriorityIcon($priority) {
return 'fa-arrow-right';
}
public static function isDisabledPriority($priority) {
$config = idx(self::getConfig(), $priority, array());
return idx($config, 'disabled', false);
}
private static function getConfig() {
$config = PhabricatorEnv::getEnvConfig('maniphest.priorities');
krsort($config);
return $config;
}
- public static function validateConfiguration(array $config) {
+ public static function validateConfiguration($config) {
+ if (!is_array($config)) {
+ throw new Exception(
+ pht(
+ 'Configuration is not valid. Maniphest priority configurations '.
+ 'must be dictionaries.',
+ $config));
+ }
+
foreach ($config as $key => $value) {
if (!ctype_digit((string)$key)) {
throw new Exception(
pht(
'Key "%s" is not a valid priority constant. Priority constants '.
'must be nonnegative integers.',
$key));
}
if (!is_array($value)) {
throw new Exception(
pht(
'Value for key "%s" should be a dictionary.',
$key));
}
PhutilTypeSpec::checkMap(
$value,
array(
'name' => 'string',
'short' => 'optional string',
'color' => 'optional string',
'keywords' => 'optional list<string>',
'disabled' => 'optional bool',
));
}
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Aug 14, 7:06 PM (1 d, 6 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
194567
Default Alt Text
(12 KB)

Event Timeline