Something went wrong. Try again.
@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
Something went wrong. Try again.
PHP
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399<?php
final class AphrontFormPolicyControl extends AphrontFormControl {
private $object; private $capability; private $policies; private $spacePHID; private $templatePHIDType; private $templateObject;
public function setPolicyObject(PhabricatorPolicyInterface $object) { $this->object = $object; return $this; }
/** * @param array<PhabricatorPolicy> $policies */ public function setPolicies(array $policies) { assert_instances_of($policies, PhabricatorPolicy::class); $this->policies = $policies; return $this; }
public function setSpacePHID($space_phid) { $this->spacePHID = $space_phid; return $this; }
public function getSpacePHID() { return $this->spacePHID; }
public function setTemplatePHIDType($type) { $this->templatePHIDType = $type; return $this; }
public function setTemplateObject($object) { $this->templateObject = $object; return $this; }
public function getSerializedValue() { return json_encode(array( $this->getValue(), $this->getSpacePHID(), )); }
public function readSerializedValue($value) { $decoded = phutil_json_decode($value); $policy_value = $decoded[0]; $space_phid = $decoded[1]; $this->setValue($policy_value); $this->setSpacePHID($space_phid); return $this; }
public function readValueFromDictionary(array $dictionary) { // TODO: This is a little hacky but will only get us into trouble if we // have multiple view policy controls in multiple paged form views on the // same page, which seems unlikely. $this->setSpacePHID(idx($dictionary, 'spacePHID'));
return parent::readValueFromDictionary($dictionary); }
public function readValueFromRequest(AphrontRequest $request) { // See note in readValueFromDictionary(). $this->setSpacePHID($request->getStr('spacePHID'));
return parent::readValueFromRequest($request); }
public function setCapability($capability) { $this->capability = $capability;
$labels = array( PhabricatorPolicyCapability::CAN_VIEW => pht('Visible To'), PhabricatorPolicyCapability::CAN_EDIT => pht('Editable By'), PhabricatorPolicyCapability::CAN_JOIN => pht('Joinable By'), );
if (isset($labels[$capability])) { $label = $labels[$capability]; } else { $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); if ($capobj) { $label = $capobj->getCapabilityName(); } else { $label = pht('Capability "%s"', $capability); } }
$this->setLabel($label);
return $this; }
protected function getCustomControlClass() { return 'aphront-form-control-policy'; }
protected function getOptions() { $capability = $this->capability; $policies = $this->policies; $viewer = $this->getUser();
// Check if we're missing the policy for the current control value. This // is unusual, but can occur if the user is submitting a form and selected // an unusual project as a policy but the change has not been saved yet. $policy_map = mpull($policies, null, 'getPHID'); $value = $this->getValue(); if ($value && empty($policy_map[$value])) { $handle = id(new PhabricatorHandleQuery()) ->setViewer($viewer) ->withPHIDs(array($value)) ->executeOne(); if ($handle->isComplete()) { $policies[] = PhabricatorPolicy::newFromPolicyAndHandle( $value, $handle); } }
// Exclude object policies which don't make sense here. This primarily // filters object policies associated from template capabilities (like // "Default Task View Policy" being set to "Task Author") so they aren't // made available on non-template capabilities (like "Can Bulk Edit"). foreach ($policies as $key => $policy) { if ($policy->getType() != PhabricatorPolicyType::TYPE_OBJECT) { continue; }
$rule = PhabricatorPolicyQuery::getObjectPolicyRule($policy->getPHID()); if (!$rule) { continue; }
$target = nonempty($this->templateObject, $this->object); if (!$rule->canApplyToObject($target)) { unset($policies[$key]); continue; } }
$options = array(); foreach ($policies as $policy) { if ($policy->getPHID() == PhabricatorPolicies::POLICY_PUBLIC) { // Never expose "Public" for capabilities which don't support it. $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); if (!$capobj || !$capobj->shouldAllowPublicPolicySetting()) { continue; } }
$options[$policy->getType()][$policy->getPHID()] = array( 'name' => $policy->getName(), 'full' => $policy->getName(), 'icon' => $policy->getIcon(), 'sort' => phutil_utf8_strtolower($policy->getName()), ); }
$type_project = PhabricatorPolicyType::TYPE_PROJECT;
// Make sure we have a "Projects" group before we adjust it. if (empty($options[$type_project])) { $options[$type_project] = array(); }
$options[$type_project] = isort($options[$type_project], 'sort');
$placeholder = id(new PhabricatorPolicy()) ->setName(pht('Other Project...')) ->setIcon('fa-search');
$options[$type_project][$this->getSelectProjectKey()] = array( 'name' => $placeholder->getName(), 'full' => $placeholder->getName(), 'icon' => $placeholder->getIcon(), );
// If we were passed several custom policy options, throw away the ones // which aren't the value for this capability. For example, an object might // have a custom view policy and a custom edit policy. When we render // the selector for "Can View", we don't want to show the "Can Edit" // custom policy -- if we did, the menu would look like this: // // Custom // Custom Policy // Custom Policy // // ...where one is the "view" custom policy, and one is the "edit" custom // policy.
$type_custom = PhabricatorPolicyType::TYPE_CUSTOM; if (!empty($options[$type_custom])) { $options[$type_custom] = array_select_keys( $options[$type_custom], array($this->getValue())); }
// If there aren't any custom policies, add a placeholder policy so we // render a menu item. This allows the user to switch to a custom policy.
if (empty($options[$type_custom])) { $placeholder = new PhabricatorPolicy(); $placeholder->setName(pht('Custom Policy...')); $options[$type_custom][$this->getSelectCustomKey()] = array( 'name' => $placeholder->getName(), 'full' => $placeholder->getName(), 'icon' => $placeholder->getIcon(), ); }
$options = array_select_keys( $options, array( PhabricatorPolicyType::TYPE_GLOBAL, PhabricatorPolicyType::TYPE_OBJECT, PhabricatorPolicyType::TYPE_USER, PhabricatorPolicyType::TYPE_CUSTOM, PhabricatorPolicyType::TYPE_PROJECT, ));
return $options; }
protected function renderInput() { if (!$this->object) { throw new PhutilInvalidStateException('setPolicyObject'); } if (!$this->capability) { throw new PhutilInvalidStateException('setCapability'); }
$policy = $this->object->getPolicy($this->capability); if (!$policy) { // TODO: Make this configurable. $policy = PhabricatorPolicies::POLICY_USER; }
if (!$this->getValue()) { $this->setValue($policy); }
if ($this->getID()) { $control_id = $this->getID(); } else { $control_id = celerity_generate_unique_node_id(); } $input_id = celerity_generate_unique_node_id();
$caret = phutil_tag( 'span', array( 'class' => 'caret', ));
$input = phutil_tag( 'input', array( 'type' => 'hidden', 'id' => $input_id, 'name' => $this->getName(), 'value' => $this->getValue(), ));
$options = $this->getOptions();
$order = array(); $labels = array(); foreach ($options as $key => $values) { $order[$key] = array_keys($values); $labels[$key] = PhabricatorPolicyType::getPolicyTypeName($key); }
$flat_options = array_mergev($options);
$icons = array(); foreach (igroup($flat_options, 'icon') as $icon => $ignored) { $icons[$icon] = id(new PHUIIconView()) ->setIcon($icon); }
if ($this->templatePHIDType) { $context_path = 'template/'.$this->templatePHIDType.'/'; } else { $object_phid = $this->object->getPHID(); if ($object_phid) { $context_path = 'object/'.$object_phid.'/'; } else { $object_type = phid_get_type($this->object->generatePHID()); $context_path = 'type/'.$object_type.'/'; } }
Javelin::initBehavior( 'policy-control', array( 'controlID' => $control_id, 'inputID' => $input_id, 'options' => $flat_options, 'groups' => array_keys($options), 'order' => $order, 'labels' => $labels, 'value' => $this->getValue(), 'capability' => $this->capability, 'editURI' => '/policy/edit/'.$context_path, 'customKey' => $this->getSelectCustomKey(), 'projectKey' => $this->getSelectProjectKey(), 'disabled' => $this->getDisabled(), ));
$selected = idx($flat_options, $this->getValue(), array()); $selected_icon = idx($selected, 'icon'); $selected_name = idx($selected, 'name');
$spaces_control = $this->buildSpacesControl();
return phutil_tag( 'div', array( ), array( $spaces_control, javelin_tag( 'a', array( 'class' => 'button button-grey dropdown has-icon has-text '. 'policy-control', 'href' => '#', 'mustcapture' => true, 'sigil' => 'policy-control', 'id' => $control_id, ), array( $caret, javelin_tag( 'span', array( 'sigil' => 'policy-label', 'class' => 'phui-button-text', ), array( idx($icons, $selected_icon), $selected_name, )), )), $input, )); }
public static function getSelectCustomKey() { return 'select:custom'; }
public static function getSelectProjectKey() { return 'select:project'; }
private function buildSpacesControl() { if ($this->capability != PhabricatorPolicyCapability::CAN_VIEW) { return null; }
if (!($this->object instanceof PhabricatorSpacesInterface)) { return null; }
$viewer = $this->getUser(); if (!PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer)) { return null; }
$space_phid = $this->getSpacePHID(); if ($space_phid === null) { $space_phid = $viewer->getDefaultSpacePHID(); }
$select = AphrontFormSelectControl::renderSelectTag( $space_phid, PhabricatorSpacesNamespaceQuery::getSpaceOptionsForViewer( $viewer, $space_phid), array( 'disabled' => ($this->getDisabled() ? 'disabled' : null), 'name' => 'spacePHID', 'class' => 'aphront-space-select-control-knob', ));
return $select; }
}