Path: blob/master/src/applications/meta/xactions/PhabricatorApplicationPolicyChangeTransaction.php
12256 views
<?php12final class PhabricatorApplicationPolicyChangeTransaction3extends PhabricatorApplicationTransactionType {45const TRANSACTIONTYPE = 'application.policy';6const METADATA_ATTRIBUTE = 'capability.name';78private $policies;910public function generateOldValue($object) {11$application = $object;12$capability = $this->getCapabilityName();13return $application->getPolicy($capability);14}1516public function applyExternalEffects($object, $value) {17$application = $object;18$user = $this->getActor();1920$key = 'phabricator.application-settings';21$config_entry = PhabricatorConfigEntry::loadConfigEntry($key);22$current_value = $config_entry->getValue();2324$phid = $application->getPHID();25if (empty($current_value[$phid])) {26$current_value[$application->getPHID()] = array();27}28if (empty($current_value[$phid]['policy'])) {29$current_value[$phid]['policy'] = array();30}3132$new = array($this->getCapabilityName() => $value);33$current_value[$phid]['policy'] = $new + $current_value[$phid]['policy'];3435$editor = $this->getEditor();36$content_source = $editor->getContentSource();3738// NOTE: We allow applications to have custom edit policies, but they are39// currently stored in the Config application. The ability to edit Config40// values is always restricted to administrators, today. Empower this41// particular edit to punch through possible stricter policies, so normal42// users can change application configuration if the application allows43// them to do so.4445PhabricatorConfigEditor::storeNewValue(46PhabricatorUser::getOmnipotentUser(),47$config_entry,48$current_value,49$content_source,50$user->getPHID());51}5253public function getTitle() {54return pht(55'%s changed the %s policy from %s to %s.',56$this->renderAuthor(),57$this->renderCapability(),58$this->renderOldPolicy(),59$this->renderNewPolicy());60}6162public function getTitleForFeed() {63return pht(64'%s changed the %s policy for application %s from %s to %s.',65$this->renderAuthor(),66$this->renderCapability(),67$this->renderObject(),68$this->renderOldPolicy(),69$this->renderNewPolicy());70}7172public function validateTransactions($object, array $xactions) {73$user = $this->getActor();74$application = $object;75$policies = id(new PhabricatorPolicyQuery())76->setViewer($user)77->setObject($application)78->execute();7980$errors = array();81foreach ($xactions as $xaction) {82$new = $xaction->getNewValue();83$capability = $xaction->getMetadataValue(self::METADATA_ATTRIBUTE);8485if (empty($policies[$new])) {86// Not a standard policy, check for a custom policy.87$policy = id(new PhabricatorPolicyQuery())88->setViewer($user)89->withPHIDs(array($new))90->executeOne();91if (!$policy) {92$errors[] = $this->newInvalidError(93pht('Policy does not exist.'));94continue;95}96} else {97$policy = idx($policies, $new);98}99100if (!$policy->isValidPolicyForEdit()) {101$errors[] = $this->newInvalidError(102pht('Can\'t set the policy to a policy you can\'t view!'));103continue;104}105106if ($new == PhabricatorPolicies::POLICY_PUBLIC) {107$capobj = PhabricatorPolicyCapability::getCapabilityByKey(108$capability);109if (!$capobj || !$capobj->shouldAllowPublicPolicySetting()) {110$errors[] = $this->newInvalidError(111pht('Can\'t set non-public policies to public.'));112continue;113}114}115116if (!$application->isCapabilityEditable($capability)) {117$errors[] = $this->newInvalidError(118pht('Capability "%s" is not editable for this application.',119$capability));120continue;121}122}123124// If we're changing these policies, the viewer needs to still be able to125// view or edit the application under the new policy.126$validate_map = array(127PhabricatorPolicyCapability::CAN_VIEW,128PhabricatorPolicyCapability::CAN_EDIT,129);130$validate_map = array_fill_keys($validate_map, array());131132foreach ($xactions as $xaction) {133$capability = $xaction->getMetadataValue(self::METADATA_ATTRIBUTE);134if (!isset($validate_map[$capability])) {135continue;136}137138$validate_map[$capability][] = $xaction;139}140141foreach ($validate_map as $capability => $cap_xactions) {142if (!$cap_xactions) {143continue;144}145146$editor = $this->getEditor();147$policy_errors = $editor->validatePolicyTransaction(148$object,149$cap_xactions,150self::TRANSACTIONTYPE,151$capability);152153foreach ($policy_errors as $error) {154$errors[] = $error;155}156}157158return $errors;159}160161private function renderCapability() {162$application = $this->getObject();163$capability = $this->getCapabilityName();164$label = $application->getCapabilityLabel($capability);165return $this->renderValue($label);166}167168private function getCapabilityName() {169return $this->getMetadataValue(self::METADATA_ATTRIBUTE);170}171172}173174175