Exemplo n.º 1
0
 protected function applyCustomInternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case PhabricatorRepositoryURITransaction::TYPE_URI:
             if (!$this->getIsNewObject()) {
                 $old_uri = $object->getEffectiveURI();
             } else {
                 $old_uri = null;
                 // When creating a URI via the API, we may not have processed the
                 // repository transaction yet. Attach the repository here to make
                 // sure we have it for the calls below.
                 if ($this->repository) {
                     $object->attachRepository($this->repository);
                 }
             }
             $object->setURI($xaction->getNewValue());
             // If we've changed the domain or protocol of the URI, remove the
             // current credential. This improves behavior in several cases:
             // If a user switches between protocols with different credential
             // types, like HTTP and SSH, the old credential won't be valid anyway.
             // It's cleaner to remove it than leave a bad credential in place.
             // If a user switches hosts, the old credential is probably not
             // correct (and potentially confusing/misleading). Removing it forces
             // users to double check that they have the correct credentials.
             // If an attacker can't see a symmetric credential like a username and
             // password, they could still potentially capture it by changing the
             // host for a URI that uses it to `evil.com`, a server they control,
             // then observing the requests. Removing the credential prevents this
             // kind of escalation.
             // Since port and path changes are less likely to fall among these
             // cases, they don't trigger a credential wipe.
             $new_uri = $object->getEffectiveURI();
             if ($old_uri) {
                 $new_proto = $old_uri->getProtocol() != $new_uri->getProtocol();
                 $new_domain = $old_uri->getDomain() != $new_uri->getDomain();
                 if ($new_proto || $new_domain) {
                     $object->setCredentialPHID(null);
                 }
             }
             break;
         case PhabricatorRepositoryURITransaction::TYPE_IO:
             $object->setIOType($xaction->getNewValue());
             break;
         case PhabricatorRepositoryURITransaction::TYPE_DISPLAY:
             $object->setDisplayType($xaction->getNewValue());
             break;
         case PhabricatorRepositoryURITransaction::TYPE_REPOSITORY:
             $object->setRepositoryPHID($xaction->getNewValue());
             $object->attachRepository($this->repository);
             break;
         case PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL:
             $object->setCredentialPHID($xaction->getNewValue());
             break;
         case PhabricatorRepositoryURITransaction::TYPE_DISABLE:
             $object->setIsDisabled($xaction->getNewValue());
             break;
     }
 }
 protected function applyFinalEffects(PhabricatorLiskDAO $object, array $xactions)
 {
     // Load the most up-to-date version of the revision and its reviewers,
     // so we don't need to try to deduce the state of reviewers by examining
     // all the changes made by the transactions. Then, update the reviewers
     // on the object to make sure we're acting on the current reviewer set
     // (and, for example, sending mail to the right people).
     $new_revision = id(new DifferentialRevisionQuery())->setViewer($this->getActor())->needReviewerStatus(true)->needActiveDiffs(true)->withIDs(array($object->getID()))->executeOne();
     if (!$new_revision) {
         throw new Exception(pht('Failed to load revision from transaction finalization.'));
     }
     $object->attachReviewerStatus($new_revision->getReviewerStatus());
     $object->attachActiveDiff($new_revision->getActiveDiff());
     $object->attachRepository($new_revision->getRepository());
     foreach ($xactions as $xaction) {
         switch ($xaction->getTransactionType()) {
             case DifferentialTransaction::TYPE_UPDATE:
                 $diff = $this->requireDiff($xaction->getNewValue(), true);
                 // Update these denormalized index tables when we attach a new
                 // diff to a revision.
                 $this->updateRevisionHashTable($object, $diff);
                 $this->updateAffectedPathTable($object, $diff);
                 break;
         }
     }
     $status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED;
     $status_revision = ArcanistDifferentialRevisionStatus::NEEDS_REVISION;
     $status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW;
     $old_status = $object->getStatus();
     switch ($old_status) {
         case $status_accepted:
         case $status_revision:
         case $status_review:
             // Try to move a revision to "accepted". We look for:
             //
             //   - at least one accepting reviewer who is a user; and
             //   - no rejects; and
             //   - no rejects of older diffs; and
             //   - no blocking reviewers.
             $has_accepting_user = false;
             $has_rejecting_reviewer = false;
             $has_rejecting_older_reviewer = false;
             $has_blocking_reviewer = false;
             foreach ($object->getReviewerStatus() as $reviewer) {
                 $reviewer_status = $reviewer->getStatus();
                 switch ($reviewer_status) {
                     case DifferentialReviewerStatus::STATUS_REJECTED:
                         $has_rejecting_reviewer = true;
                         break;
                     case DifferentialReviewerStatus::STATUS_REJECTED_OLDER:
                         $has_rejecting_older_reviewer = true;
                         break;
                     case DifferentialReviewerStatus::STATUS_BLOCKING:
                         $has_blocking_reviewer = true;
                         break;
                     case DifferentialReviewerStatus::STATUS_ACCEPTED:
                         if ($reviewer->isUser()) {
                             $has_accepting_user = true;
                         }
                         break;
                 }
             }
             $new_status = null;
             if ($has_accepting_user && !$has_rejecting_reviewer && !$has_rejecting_older_reviewer && !$has_blocking_reviewer) {
                 $new_status = $status_accepted;
             } else {
                 if ($has_rejecting_reviewer) {
                     // This isn't accepted, and there's at least one rejecting reviewer,
                     // so the revision needs changes. This usually happens after a
                     // "reject".
                     $new_status = $status_revision;
                 } else {
                     if ($old_status == $status_accepted) {
                         // This revision was accepted, but it no longer satisfies the
                         // conditions for acceptance. This usually happens after an accepting
                         // reviewer resigns or is removed.
                         $new_status = $status_review;
                     }
                 }
             }
             if ($new_status !== null && $new_status != $old_status) {
                 $xaction = id(new DifferentialTransaction())->setTransactionType(DifferentialTransaction::TYPE_STATUS)->setOldValue($old_status)->setNewValue($new_status);
                 $xaction = $this->populateTransaction($object, $xaction)->save();
                 $xactions[] = $xaction;
                 $object->setStatus($new_status)->save();
             }
             break;
         default:
             // Revisions can't transition out of other statuses (like closed or
             // abandoned) as a side effect of reviewer status changes.
             break;
     }
     return $xactions;
 }