Path: blob/master/src/applications/differential/xaction/DifferentialRevisionActionTransaction.php
12256 views
<?php12abstract class DifferentialRevisionActionTransaction3extends DifferentialRevisionTransactionType {45final public function getRevisionActionKey() {6return $this->getPhobjectClassConstant('ACTIONKEY', 32);7}89public function isActionAvailable($object, PhabricatorUser $viewer) {10try {11$this->validateAction($object, $viewer);12return true;13} catch (Exception $ex) {14return false;15}16}1718abstract protected function validateAction($object, PhabricatorUser $viewer);19abstract protected function getRevisionActionLabel(20DifferentialRevision $revision,21PhabricatorUser $viewer);2223protected function validateOptionValue($object, $actor, array $value) {24return null;25}2627public function getCommandKeyword() {28return null;29}3031public function getCommandAliases() {32return array();33}3435public function getCommandSummary() {36return null;37}3839protected function getRevisionActionOrder() {40return 1000;41}4243public function getActionStrength() {44return 300;45}4647public function getRevisionActionOrderVector() {48return id(new PhutilSortVector())49->addInt($this->getRevisionActionOrder());50}5152protected function getRevisionActionGroupKey() {53return DifferentialRevisionEditEngine::ACTIONGROUP_REVISION;54}5556protected function getRevisionActionDescription(57DifferentialRevision $revision,58PhabricatorUser $viewer) {59return null;60}6162protected function getRevisionActionSubmitButtonText(63DifferentialRevision $revision,64PhabricatorUser $viewer) {65return null;66}6768protected function getRevisionActionMetadata(69DifferentialRevision $revision,70PhabricatorUser $viewer) {71return array();72}7374public static function loadAllActions() {75return id(new PhutilClassMapQuery())76->setAncestorClass(__CLASS__)77->setUniqueMethod('getRevisionActionKey')78->execute();79}8081protected function isViewerRevisionAuthor(82DifferentialRevision $revision,83PhabricatorUser $viewer) {8485if (!$viewer->getPHID()) {86return false;87}8889return ($viewer->getPHID() === $revision->getAuthorPHID());90}9192protected function getActionOptions(93PhabricatorUser $viewer,94DifferentialRevision $revision) {95return array(96array(),97array(),98);99}100101public function newEditField(102DifferentialRevision $revision,103PhabricatorUser $viewer) {104105// Actions in the "review" group, like "Accept Revision", do not require106// that the actor be able to edit the revision.107$group_review = DifferentialRevisionEditEngine::ACTIONGROUP_REVIEW;108$is_review = ($this->getRevisionActionGroupKey() == $group_review);109110$field = id(new PhabricatorApplyEditField())111->setKey($this->getRevisionActionKey())112->setTransactionType($this->getTransactionTypeConstant())113->setCanApplyWithoutEditCapability($is_review)114->setValue(true);115116if ($this->isActionAvailable($revision, $viewer)) {117$label = $this->getRevisionActionLabel($revision, $viewer);118if ($label !== null) {119$field->setCommentActionLabel($label);120121$description = $this->getRevisionActionDescription($revision, $viewer);122$field->setActionDescription($description);123124$group_key = $this->getRevisionActionGroupKey();125$field->setCommentActionGroupKey($group_key);126127$button_text = $this->getRevisionActionSubmitButtonText(128$revision,129$viewer);130$field->setActionSubmitButtonText($button_text);131132// Currently, every revision action conflicts with every other133// revision action: for example, you can not simultaneously Accept and134// Reject a revision.135136// Under some configurations, some combinations of actions are sort of137// technically permissible. For example, you could reasonably Reject138// and Abandon a revision if "anyone can abandon anything" is enabled.139140// It's not clear that these combinations are actually useful, so just141// keep things simple for now.142$field->setActionConflictKey('revision.action');143144list($options, $value) = $this->getActionOptions($viewer, $revision);145146// Show the options if the user can select on behalf of two or more147// reviewers, or can force-accept on behalf of one or more reviewers,148// or can accept on behalf of a reviewer other than themselves (see149// T12533).150$can_multi = (count($options) > 1);151$can_force = (count($value) < count($options));152$not_self = (head_key($options) != $viewer->getPHID());153154if ($can_multi || $can_force || $not_self) {155$field->setOptions($options);156$field->setValue($value);157}158159$metadata = $this->getRevisionActionMetadata($revision, $viewer);160foreach ($metadata as $metadata_key => $metadata_value) {161$field->setMetadataValue($metadata_key, $metadata_value);162}163}164}165166return $field;167}168169public function validateTransactions($object, array $xactions) {170$errors = array();171$actor = $this->getActor();172173$action_exception = null;174foreach ($xactions as $xaction) {175// If this is a draft demotion action, let it skip all the normal176// validation. This is a little hacky and should perhaps move down177// into the actual action implementations, but currently we can not178// apply this rule in validateAction() because it doesn't operate on179// the actual transaction.180if ($xaction->getMetadataValue('draft.demote')) {181continue;182}183184try {185$this->validateAction($object, $actor);186} catch (Exception $ex) {187$action_exception = $ex;188}189190break;191}192193foreach ($xactions as $xaction) {194if ($action_exception) {195$errors[] = $this->newInvalidError(196$action_exception->getMessage(),197$xaction);198continue;199}200201$new = $xaction->getNewValue();202if (!is_array($new)) {203continue;204}205206try {207$this->validateOptionValue($object, $actor, $new);208} catch (Exception $ex) {209$errors[] = $this->newInvalidError(210$ex->getMessage(),211$xaction);212}213}214215return $errors;216}217218}219220221