protected function didValidateOption(PhabricatorConfigOption $option, $value)
 {
     $key = $option->getKey();
     if ($key == 'phabricator.base-uri' || $key == 'phabricator.production-uri') {
         $uri = new PhutilURI($value);
         $protocol = $uri->getProtocol();
         if ($protocol !== 'http' && $protocol !== 'https') {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The URI must start with " . "%s' or '%s'.", 'http://', 'https://', $key));
         }
         $domain = $uri->getDomain();
         if (strpos($domain, '.') === false) {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The URI must contain a dot " . "('%s'), like '%s', not just a bare name like '%s'. Some web " . "browsers will not set cookies on domains with no TLD.", '.', 'http://example.com/', 'http://example/', $key));
         }
         $path = $uri->getPath();
         if ($path !== '' && $path !== '/') {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The URI must NOT have a path, " . "e.g. '%s' is OK, but '%s' is not. Phabricator must be installed " . "on an entire domain; it can not be installed on a path.", $key, 'http://phabricator.example.com/', 'http://example.com/phabricator/'));
         }
     }
     if ($key === 'phabricator.timezone') {
         $old = date_default_timezone_get();
         $ok = @date_default_timezone_set($value);
         @date_default_timezone_set($old);
         if (!$ok) {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The timezone identifier must " . "be a valid timezone identifier recognized by PHP, like '%s'. " . "\n            You can find a list of valid identifiers here: %s", $key, 'America/Los_Angeles', 'http://php.net/manual/timezones.php'));
         }
     }
 }
 public function renderControl(PhabricatorConfigOption $option, $display_value, $e_value)
 {
     $field_base_class = $option->getCustomData();
     $field_spec = $display_value;
     if (!is_array($field_spec)) {
         $field_spec = PhabricatorEnv::getEnvConfig($option->getKey());
     }
     // Get all of the fields (including disabled fields) by querying for them
     // with a faux spec where no fields are disabled.
     $faux_spec = $field_spec;
     foreach ($faux_spec as $key => $spec) {
         unset($faux_spec[$key]['disabled']);
     }
     // TODO: We might need to build a real object here eventually.
     $faux_object = null;
     $fields = PhabricatorCustomField::buildFieldList($field_base_class, $faux_spec, $faux_object);
     $list_id = celerity_generate_unique_node_id();
     $input_id = celerity_generate_unique_node_id();
     $list = id(new PHUIObjectItemListView())->setFlush(true)->setID($list_id);
     foreach ($fields as $key => $field) {
         $item = id(new PHUIObjectItemView())->addSigil('field-spec')->setMetadata(array('fieldKey' => $key))->setGrippable(true)->addAttribute($field->getFieldDescription())->setHeader($field->getFieldName());
         $is_disabled = !empty($field_spec[$key]['disabled']);
         $disabled_item = clone $item;
         $enabled_item = clone $item;
         if ($is_disabled) {
             $list->addItem($disabled_item);
         } else {
             $list->addItem($enabled_item);
         }
         $disabled_item->addIcon('none', pht('Disabled'));
         $disabled_item->setDisabled(true);
         $disabled_item->addAction(id(new PHUIListItemView())->setHref('#')->addSigil('field-spec-toggle')->setIcon('fa-plus'));
         $enabled_item->setBarColor('green');
         if (!$field->canDisableField()) {
             $enabled_item->addAction(id(new PHUIListItemView())->setIcon('fa-lock grey'));
             $enabled_item->addIcon('none', pht('Permanent Field'));
         } else {
             $enabled_item->addAction(id(new PHUIListItemView())->setHref('#')->addSigil('field-spec-toggle')->setIcon('fa-times'));
         }
         $fields[$key] = array('disabled' => $is_disabled, 'disabledMarkup' => $disabled_item->render(), 'enabledMarkup' => $enabled_item->render());
     }
     $input = phutil_tag('input', array('id' => $input_id, 'type' => 'hidden', 'name' => 'value', 'value' => json_encode($display_value)));
     Javelin::initBehavior('config-reorder-fields', array('listID' => $list_id, 'inputID' => $input_id, 'fields' => $fields));
     return id(new AphrontFormMarkupControl())->setLabel(pht('Value'))->setError($e_value)->setValue(array($list, $input));
 }
 protected function didValidateOption(PhabricatorConfigOption $option, $value)
 {
     $key = $option->getKey();
     if ($key == 'security.alternate-file-domain') {
         $uri = new PhutilURI($value);
         $protocol = $uri->getProtocol();
         if ($protocol !== 'http' && $protocol !== 'https') {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The URI must start with " . "'%s' or '%s'.", $key, 'http://', 'https://'));
         }
         $domain = $uri->getDomain();
         if (strpos($domain, '.') === false) {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The URI must contain a dot ('.'), " . "like '%s', not just a bare name like '%s'. " . "Some web browsers will not set cookies on domains with no TLD.", $key, 'http://example.com/', 'http://example/'));
         }
         $path = $uri->getPath();
         if ($path !== '' && $path !== '/') {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The URI must NOT have a path, " . "e.g. '%s' is OK, but '%s' is not. Phabricator must be installed " . "on an entire domain; it can not be installed on a path.", $key, 'http://phabricator.example.com/', 'http://example.com/phabricator/'));
         }
     }
 }
 public function renderContextualDescription(PhabricatorConfigOption $option, AphrontRequest $request)
 {
     switch ($option->getKey()) {
         case 'asana.workspace-id':
             break;
         case 'asana.project-ids':
             return $this->renderContextualProjectDescription($option, $request);
         default:
             return parent::renderContextualDescription($option, $request);
     }
     $viewer = $request->getUser();
     $provider = PhabricatorAsanaAuthProvider::getAsanaProvider();
     if (!$provider) {
         return null;
     }
     $account = id(new PhabricatorExternalAccountQuery())->setViewer($viewer)->withUserPHIDs(array($viewer->getPHID()))->withAccountTypes(array($provider->getProviderType()))->withAccountDomains(array($provider->getProviderDomain()))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
     if (!$account) {
         return null;
     }
     $token = $provider->getOAuthAccessToken($account);
     if (!$token) {
         return null;
     }
     try {
         $workspaces = id(new PhutilAsanaFuture())->setAccessToken($token)->setRawAsanaQuery('workspaces')->resolve();
     } catch (Exception $ex) {
         return null;
     }
     if (!$workspaces) {
         return null;
     }
     $out = array();
     $out[] = pht('| Workspace ID | Workspace Name |');
     $out[] = '| ------------ | -------------- |';
     foreach ($workspaces as $workspace) {
         $out[] = sprintf('| `%s` | `%s` |', $workspace['id'], $workspace['name']);
     }
     $out = implode("\n", $out);
     $out = pht("The Asana Workspaces your linked account has access to are:\n\n%s", $out);
     return PhabricatorMarkupEngine::renderOneObject(id(new PhabricatorMarkupOneOff())->setContent($out), 'default', $viewer);
 }
 public function validateOption(PhabricatorConfigOption $option, $value)
 {
     if ($value === $option->getDefault()) {
         return;
     }
     if ($value === null) {
         return;
     }
     if ($option->isCustomType()) {
         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);
 }
 private function renderDefaults(PhabricatorConfigOption $option, PhabricatorConfigEntry $entry)
 {
     $stack = PhabricatorEnv::getConfigSourceStack();
     $stack = $stack->getStack();
     $table = array();
     $table[] = phutil_tag('tr', array('class' => 'column-labels'), array(phutil_tag('th', array(), pht('Source')), phutil_tag('th', array(), pht('Value'))));
     foreach ($stack as $key => $source) {
         $value = $source->getKeys(array($option->getKey()));
         if (!array_key_exists($option->getKey(), $value)) {
             $value = phutil_tag('em', array(), pht('(empty)'));
         } else {
             $value = $this->getDisplayValue($option, $entry, $value[$option->getKey()]);
         }
         $table[] = phutil_tag('tr', array('class' => 'column-labels'), array(phutil_tag('th', array(), $source->getName()), phutil_tag('td', array(), $value)));
     }
     require_celerity_resource('config-options-css');
     return phutil_tag('table', array('class' => 'config-option-table'), $table);
 }