Path: blob/master/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php
12256 views
<?php12final class DifferentialRevisionAcceptTransaction3extends DifferentialRevisionReviewTransaction {45const TRANSACTIONTYPE = 'differential.revision.accept';6const ACTIONKEY = 'accept';78protected function getRevisionActionLabel(9DifferentialRevision $revision,10PhabricatorUser $viewer) {11return pht('Accept Revision');12}1314protected function getRevisionActionDescription(15DifferentialRevision $revision,16PhabricatorUser $viewer) {17return pht('These changes will be approved.');18}1920public function getIcon() {21return 'fa-check-circle-o';22}2324public function getColor() {25return 'green';26}2728protected function getRevisionActionOrder() {29return 500;30}3132public function getActionName() {33return pht('Accepted');34}3536public function getCommandKeyword() {37$accept_key = 'differential.enable-email-accept';38$allow_email_accept = PhabricatorEnv::getEnvConfig($accept_key);39if (!$allow_email_accept) {40return null;41}4243return 'accept';44}4546public function getCommandAliases() {47return array();48}4950public function getCommandSummary() {51return pht('Accept a revision.');52}5354protected function getActionOptions(55PhabricatorUser $viewer,56DifferentialRevision $revision,57$include_accepted = false) {5859$reviewers = $revision->getReviewers();6061$options = array();62$value = array();6364// Put the viewer's user reviewer first, if it exists, so that "Accept as65// yourself" is always at the top.66$head = array();67$tail = array();68foreach ($reviewers as $key => $reviewer) {69if ($reviewer->isUser()) {70$head[$key] = $reviewer;71} else {72$tail[$key] = $reviewer;73}74}75$reviewers = $head + $tail;7677$diff_phid = $this->getActiveDiffPHID($revision);78$reviewer_phids = array();7980// If the viewer isn't a reviewer, add them to the list of options first.81// This happens when you navigate to some revision you aren't involved in:82// you can accept and become a reviewer.8384$viewer_phid = $viewer->getPHID();85if ($viewer_phid) {86if (!isset($reviewers[$viewer_phid])) {87$reviewer_phids[$viewer_phid] = $viewer_phid;88}89}9091$default_unchecked = array();92foreach ($reviewers as $reviewer) {93$reviewer_phid = $reviewer->getReviewerPHID();9495if (!$reviewer->hasAuthority($viewer)) {96// If the viewer doesn't have authority to act on behalf of a reviewer,97// we check if they can accept by force.98if ($revision->canReviewerForceAccept($viewer, $reviewer)) {99$default_unchecked[$reviewer_phid] = true;100} else {101continue;102}103}104105if (!$include_accepted) {106if ($reviewer->isAccepted($diff_phid)) {107// If a reviewer is already in a full "accepted" state, don't108// include that reviewer as an option unless we're listing all109// reviewers, including reviewers who have already accepted.110continue;111}112}113114$reviewer_phids[$reviewer_phid] = $reviewer_phid;115}116117$handles = $viewer->loadHandles($reviewer_phids);118119$head = array();120$tail = array();121foreach ($reviewer_phids as $reviewer_phid) {122$is_force = isset($default_unchecked[$reviewer_phid]);123124if ($is_force) {125$tail[] = $reviewer_phid;126127$options[$reviewer_phid] = pht(128'Force accept as %s',129$viewer->renderHandle($reviewer_phid));130} else {131$head[] = $reviewer_phid;132$value[] = $reviewer_phid;133134$options[$reviewer_phid] = pht(135'Accept as %s',136$viewer->renderHandle($reviewer_phid));137}138}139140// Reorder reviewers so "force accept" reviewers come at the end.141$options =142array_select_keys($options, $head) +143array_select_keys($options, $tail);144145return array($options, $value);146}147148public function generateOldValue($object) {149$actor = $this->getActor();150return $this->isViewerFullyAccepted($object, $actor);151}152153public function applyExternalEffects($object, $value) {154$status = DifferentialReviewerStatus::STATUS_ACCEPTED;155$actor = $this->getActor();156$this->applyReviewerEffect($object, $actor, $value, $status);157}158159protected function validateAction($object, PhabricatorUser $viewer) {160if ($object->isClosed()) {161throw new Exception(162pht(163'You can not accept this revision because it has already been '.164'closed. Only open revisions can be accepted.'));165}166167if ($object->isDraft() || !$object->getShouldBroadcast()) {168throw new Exception(169pht('You can not accept a draft revision.'));170}171172$config_key = 'differential.allow-self-accept';173if (!PhabricatorEnv::getEnvConfig($config_key)) {174if ($this->isViewerRevisionAuthor($object, $viewer)) {175throw new Exception(176pht(177'You can not accept this revision because you are the revision '.178'author. You can only accept revisions you do not own. You can '.179'change this behavior by adjusting the "%s" setting in Config.',180$config_key));181}182}183184if ($this->isViewerFullyAccepted($object, $viewer)) {185throw new Exception(186pht(187'You can not accept this revision because you have already '.188'accepted it.'));189}190}191192protected function validateOptionValue($object, $actor, array $value) {193if (!$value) {194throw new Exception(195pht(196'When accepting a revision, you must accept on behalf of at '.197'least one reviewer.'));198}199200// NOTE: We're including reviewers who have already been accepted in this201// check. Legitimate users may race one another to accept on behalf of202// packages. If we get a form submission which includes a reviewer which203// someone has already accepted, that's fine. See T12757.204205list($options) = $this->getActionOptions($actor, $object, true);206foreach ($value as $phid) {207if (!isset($options[$phid])) {208throw new Exception(209pht(210'Reviewer "%s" is not a valid reviewer which you have authority '.211'to accept on behalf of.',212$phid));213}214}215}216217public function getTitle() {218$new = $this->getNewValue();219if (is_array($new) && $new) {220return pht(221'%s accepted this revision as %s reviewer(s): %s.',222$this->renderAuthor(),223phutil_count($new),224$this->renderHandleList($new));225} else {226return pht(227'%s accepted this revision.',228$this->renderAuthor());229}230}231232public function getTitleForFeed() {233return pht(234'%s accepted %s.',235$this->renderAuthor(),236$this->renderObject());237}238239public function getTransactionTypeForConduit($xaction) {240return 'accept';241}242243public function getFieldValuesForConduit($object, $data) {244return array();245}246247}248249250