@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Allow configuration to be explicitly validated, including validation of complex attributes

Summary:
- Allows us to implement setup warnings for edits which don't go through the web UI, e.g. "you edited a config file and set value X to something goofy".
- Allows us to implement more sophisticated validations, beyond basic type checks (e.g., "phabricator.base-uri" must be a URI).
- Fixes T358 (or, close enough -- fixes it for all options which have been migrated as per T2255.

Test Plan: Set "darkconsole.enabled" to "xyz" in my config, observed setup warning. Added fake validation, observed web UI edit error.

Reviewers: codeblock, btrahan

Reviewed By: codeblock

CC: aran

Maniphest Tasks: T2255, T358

Differential Revision: https://secure.phabricator.com/D4315

+108 -3
+4
src/__phutil_library_map__.php
··· 704 704 'PhabricatorConfigStackSource' => 'infrastructure/env/PhabricatorConfigStackSource.php', 705 705 'PhabricatorConfigTransaction' => 'applications/config/storage/PhabricatorConfigTransaction.php', 706 706 'PhabricatorConfigTransactionQuery' => 'applications/config/query/PhabricatorConfigTransactionQuery.php', 707 + 'PhabricatorConfigValidationException' => 'applications/config/exception/PhabricatorConfigValidationException.php', 707 708 'PhabricatorContentSource' => 'applications/metamta/contentsource/PhabricatorContentSource.php', 708 709 'PhabricatorContentSourceView' => 'applications/metamta/contentsource/PhabricatorContentSourceView.php', 709 710 'PhabricatorController' => 'applications/base/controller/PhabricatorController.php', ··· 1155 1156 'PhabricatorSetupCheck' => 'applications/config/check/PhabricatorSetupCheck.php', 1156 1157 'PhabricatorSetupCheckAPC' => 'applications/config/check/PhabricatorSetupCheckAPC.php', 1157 1158 'PhabricatorSetupCheckExtraConfig' => 'applications/config/check/PhabricatorSetupCheckExtraConfig.php', 1159 + 'PhabricatorSetupCheckInvalidConfig' => 'applications/config/check/PhabricatorSetupCheckInvalidConfig.php', 1158 1160 'PhabricatorSetupCheckTimezone' => 'applications/config/check/PhabricatorSetupCheckTimezone.php', 1159 1161 'PhabricatorSetupIssue' => 'applications/config/issue/PhabricatorSetupIssue.php', 1160 1162 'PhabricatorSetupIssueView' => 'applications/config/view/PhabricatorSetupIssueView.php', ··· 2046 2048 'PhabricatorConfigStackSource' => 'PhabricatorConfigSource', 2047 2049 'PhabricatorConfigTransaction' => 'PhabricatorApplicationTransaction', 2048 2050 'PhabricatorConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 2051 + 'PhabricatorConfigValidationException' => 'Exception', 2049 2052 'PhabricatorContentSourceView' => 'AphrontView', 2050 2053 'PhabricatorController' => 'AphrontController', 2051 2054 'PhabricatorCountdownController' => 'PhabricatorController', ··· 2455 2458 'PhabricatorSettingsPanelSearchPreferences' => 'PhabricatorSettingsPanel', 2456 2459 'PhabricatorSetupCheckAPC' => 'PhabricatorSetupCheck', 2457 2460 'PhabricatorSetupCheckExtraConfig' => 'PhabricatorSetupCheck', 2461 + 'PhabricatorSetupCheckInvalidConfig' => 'PhabricatorSetupCheck', 2458 2462 'PhabricatorSetupCheckTimezone' => 'PhabricatorSetupCheck', 2459 2463 'PhabricatorSetupIssueView' => 'AphrontView', 2460 2464 'PhabricatorSlowvoteChoice' => 'PhabricatorSlowvoteDAO',
+29
src/applications/config/check/PhabricatorSetupCheckInvalidConfig.php
··· 1 + <?php 2 + 3 + final class PhabricatorSetupCheckInvalidConfig extends PhabricatorSetupCheck { 4 + 5 + protected function executeChecks() { 6 + $groups = PhabricatorApplicationConfigOptions::loadAll(); 7 + foreach ($groups as $group) { 8 + $options = $group->getOptions(); 9 + foreach ($options as $option) { 10 + try { 11 + $group->validateOption( 12 + $option, 13 + PhabricatorEnv::getEnvConfig($option->getKey())); 14 + } catch (PhabricatorConfigValidationException $ex) { 15 + $this 16 + ->newIssue('config.invalid.'.$option->getKey()) 17 + ->setName(pht("Config '%s' Invalid", $option->getKey())) 18 + ->setMessage( 19 + pht( 20 + "Configuration option '%s' has invalid value: %s", 21 + $option->getKey(), 22 + $ex->getMessage())) 23 + ->addPhabricatorConfig($option->getKey()); 24 + } 25 + } 26 + } 27 + } 28 + 29 + }
+8 -3
src/applications/config/controller/PhabricatorConfigEditController.php
··· 78 78 PhabricatorContentSource::SOURCE_WEB, 79 79 array( 80 80 'ip' => $request->getRemoteAddr(), 81 - ))) 82 - ->applyTransactions($config_entry, array($xaction)); 81 + ))); 83 82 84 - return id(new AphrontRedirectResponse())->setURI($done_uri); 83 + try { 84 + $editor->applyTransactions($config_entry, array($xaction)); 85 + return id(new AphrontRedirectResponse())->setURI($done_uri); 86 + } catch (PhabricatorConfigValidationException $ex) { 87 + $e_value = pht('Invalid'); 88 + $errors[] = $ex->getMessage(); 89 + } 85 90 } 86 91 } else { 87 92 $display_value = $this->getDisplayValue($option, $config_entry);
+12
src/applications/config/editor/PhabricatorConfigEditor.php
··· 42 42 case PhabricatorConfigTransaction::TYPE_EDIT: 43 43 $v = $xaction->getNewValue(); 44 44 45 + // If this is a defined configuration option (vs a straggler from an 46 + // old version of Phabricator or a configuration file misspelling) 47 + // submit it to the validation gauntlet. 48 + $key = $object->getConfigKey(); 49 + $all_options = PhabricatorApplicationConfigOptions::loadAllOptions(); 50 + $option = idx($all_options, $key); 51 + if ($option) { 52 + $option->getGroup()->validateOption( 53 + $option, 54 + $v['value']); 55 + } 56 + 45 57 $object->setIsDeleted($v['deleted']); 46 58 $object->setValue($v['value']); 47 59 break;
+5
src/applications/config/exception/PhabricatorConfigValidationException.php
··· 1 + <?php 2 + 3 + final class PhabricatorConfigValidationException extends Exception { 4 + 5 + }
+50
src/applications/config/option/PhabricatorApplicationConfigOptions.php
··· 6 6 abstract public function getDescription(); 7 7 abstract public function getOptions(); 8 8 9 + public function validateOption(PhabricatorConfigOption $option, $value) { 10 + if ($value === $option->getDefault()) { 11 + return; 12 + } 13 + 14 + if ($value === null) { 15 + return; 16 + } 17 + 18 + switch ($option->getType()) { 19 + case 'bool': 20 + if ($value !== true && 21 + $value !== false) { 22 + throw new PhabricatorConfigValidationException( 23 + pht( 24 + "Option '%s' is of type bool, but value is not true or false.", 25 + $option->getKey())); 26 + } 27 + break; 28 + case 'int': 29 + if (!is_int($value)) { 30 + throw new PhabricatorConfigValidationException( 31 + pht( 32 + "Option '%s' is of type int, but value is not an integer.", 33 + $option->getKey())); 34 + } 35 + break; 36 + case 'string': 37 + if (!is_string($value)) { 38 + throw new PhabricatorConfigValidationException( 39 + pht( 40 + "Option '%s' is of type string, but value is not a string.", 41 + $option->getKey())); 42 + } 43 + break; 44 + case 'wild': 45 + default: 46 + break; 47 + } 48 + 49 + $this->didValidateOption($option, $value); 50 + } 51 + 52 + protected function didValidateOption( 53 + PhabricatorConfigOption $option, 54 + $value) { 55 + // Hook for subclasses to do complex validation. 56 + return; 57 + } 58 + 9 59 public function getKey() { 10 60 $class = get_class($this); 11 61 $matches = null;