protected function readValueFromRevision(DifferentialRevision $revision)
 {
     if (!$revision->getPHID()) {
         return array();
     }
     return PhabricatorEdgeQuery::loadDestinationPHIDs($revision->getPHID(), DifferentialRevisionHasTaskEdgeType::EDGECONST);
 }
 protected function readValueFromRevision(DifferentialRevision $revision)
 {
     if (!$revision->getPHID()) {
         return array();
     }
     return PhabricatorSubscribersQuery::loadSubscribersForPHID($revision->getPHID());
 }
 protected function readValueFromRevision(DifferentialRevision $revision)
 {
     if (!$revision->getPHID()) {
         return array();
     }
     $projects = PhabricatorEdgeQuery::loadDestinationPHIDs($revision->getPHID(), PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
     $projects = array_reverse($projects);
     return $projects;
 }
 public static function indexRevision(DifferentialRevision $rev)
 {
     $doc = new PhabricatorSearchAbstractDocument();
     $doc->setPHID($rev->getPHID());
     $doc->setDocumentType(PhabricatorPHIDConstants::PHID_TYPE_DREV);
     $doc->setDocumentTitle($rev->getTitle());
     $doc->setDocumentCreated($rev->getDateCreated());
     $doc->setDocumentModified($rev->getDateModified());
     $doc->addField(PhabricatorSearchField::FIELD_BODY, $rev->getSummary());
     $doc->addField(PhabricatorSearchField::FIELD_TEST_PLAN, $rev->getTestPlan());
     $doc->addRelationship(PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR, $rev->getAuthorPHID(), PhabricatorPHIDConstants::PHID_TYPE_USER, $rev->getDateCreated());
     if ($rev->getStatus() != ArcanistDifferentialRevisionStatus::CLOSED && $rev->getStatus() != ArcanistDifferentialRevisionStatus::ABANDONED) {
         $doc->addRelationship(PhabricatorSearchRelationship::RELATIONSHIP_OPEN, $rev->getPHID(), PhabricatorPHIDConstants::PHID_TYPE_DREV, time());
     }
     $comments = id(new DifferentialComment())->loadAllWhere('revisionID = %d', $rev->getID());
     $inlines = id(new DifferentialInlineComment())->loadAllWhere('revisionID = %d AND commentID IS NOT NULL', $rev->getID());
     $touches = array();
     foreach (array_merge($comments, $inlines) as $comment) {
         if (strlen($comment->getContent())) {
             $doc->addField(PhabricatorSearchField::FIELD_COMMENT, $comment->getContent());
         }
         $author = $comment->getAuthorPHID();
         $touches[$author] = $comment->getDateCreated();
     }
     foreach ($touches as $touch => $time) {
         $doc->addRelationship(PhabricatorSearchRelationship::RELATIONSHIP_TOUCH, $touch, PhabricatorPHIDConstants::PHID_TYPE_USER, $time);
     }
     $rev->loadRelationships();
     // If a revision needs review, the owners are the reviewers. Otherwise, the
     // owner is the author (e.g., accepted, rejected, closed).
     if ($rev->getStatus() == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) {
         foreach ($rev->getReviewers() as $phid) {
             $doc->addRelationship(PhabricatorSearchRelationship::RELATIONSHIP_OWNER, $phid, PhabricatorPHIDConstants::PHID_TYPE_USER, $rev->getDateModified());
             // Bogus timestamp.
         }
     } else {
         $doc->addRelationship(PhabricatorSearchRelationship::RELATIONSHIP_OWNER, $rev->getAuthorPHID(), PhabricatorPHIDConstants::PHID_TYPE_USER, $rev->getDateCreated());
     }
     $ccphids = $rev->getCCPHIDs();
     $handles = id(new PhabricatorObjectHandleData($ccphids))->loadHandles();
     foreach ($handles as $phid => $handle) {
         $doc->addRelationship(PhabricatorSearchRelationship::RELATIONSHIP_SUBSCRIBER, $phid, $handle->getType(), $rev->getDateModified());
         // Bogus timestamp.
     }
     self::reindexAbstractDocument($doc);
 }
 public static function loadFromStorage(DifferentialRevision $revision, array $aux_fields)
 {
     $storage_keys = array_filter(mpull($aux_fields, 'getStorageKey'));
     $field_data = array();
     if ($storage_keys) {
         $field_data = id(new DifferentialAuxiliaryField())->loadAllWhere('revisionPHID = %s AND name IN (%Ls)', $revision->getPHID(), $storage_keys);
         $field_data = mpull($field_data, 'getValue', 'getName');
     }
     foreach ($aux_fields as $aux_field) {
         $aux_field->setRevision($revision);
         $key = $aux_field->getStorageKey();
         if ($key) {
             $aux_field->setValueFromStorage(idx($field_data, $key));
         }
     }
     return $aux_fields;
 }
 public static function loadUnsubmittedInlineComments(PhabricatorUser $viewer, DifferentialRevision $revision)
 {
     // TODO: This probably needs to move somewhere more central as we move
     // away from DifferentialInlineCommentQuery, but
     // PhabricatorApplicationTransactionCommentQuery is currently `final` and
     // I'm not yet decided on how to approach that. For now, just get the PHIDs
     // and then execute a PHID-based query through the standard stack.
     $table = new DifferentialTransactionComment();
     $conn_r = $table->establishConnection('r');
     $phids = queryfx_all($conn_r, 'SELECT phid FROM %T
     WHERE revisionPHID = %s
       AND authorPHID = %s
       AND transactionPHID IS NULL', $table->getTableName(), $revision->getPHID(), $viewer->getPHID());
     $phids = ipull($phids, 'phid');
     if (!$phids) {
         return array();
     }
     return id(new PhabricatorApplicationTransactionCommentQuery())->setTemplate(new DifferentialTransactionComment())->setViewer($viewer)->withPHIDs($phids)->execute();
 }
 /**
  * Note this code is somewhat similar to the buildPatch method in
  * @{class:DifferentialReviewRequestMail}.
  *
  * @return @{class:AphrontRedirectResponse}
  */
 private function buildRawDiffResponse(DifferentialRevision $revision, array $changesets, array $vs_changesets, array $vs_map, PhabricatorRepository $repository = null)
 {
     assert_instances_of($changesets, 'DifferentialChangeset');
     assert_instances_of($vs_changesets, 'DifferentialChangeset');
     $viewer = $this->getRequest()->getUser();
     id(new DifferentialHunkQuery())->setViewer($viewer)->withChangesets($changesets)->needAttachToChangesets(true)->execute();
     $diff = new DifferentialDiff();
     $diff->attachChangesets($changesets);
     $raw_changes = $diff->buildChangesList();
     $changes = array();
     foreach ($raw_changes as $changedict) {
         $changes[] = ArcanistDiffChange::newFromDictionary($changedict);
     }
     $loader = id(new PhabricatorFileBundleLoader())->setViewer($viewer);
     $bundle = ArcanistBundle::newFromChanges($changes);
     $bundle->setLoadFileDataCallback(array($loader, 'loadFileData'));
     $vcs = $repository ? $repository->getVersionControlSystem() : null;
     switch ($vcs) {
         case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
         case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
             $raw_diff = $bundle->toGitPatch();
             break;
         case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
         default:
             $raw_diff = $bundle->toUnifiedDiff();
             break;
     }
     $request_uri = $this->getRequest()->getRequestURI();
     // this ends up being something like
     //   D123.diff
     // or the verbose
     //   D123.vs123.id123.whitespaceignore-all.diff
     // lame but nice to include these options
     $file_name = ltrim($request_uri->getPath(), '/') . '.';
     foreach ($request_uri->getQueryParams() as $key => $value) {
         if ($key == 'download') {
             continue;
         }
         $file_name .= $key . $value . '.';
     }
     $file_name .= 'diff';
     $file = PhabricatorFile::buildFromFileDataOrHash($raw_diff, array('name' => $file_name, 'ttl' => 60 * 60 * 24, 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE));
     $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
     $file->attachToObject($revision->getPHID());
     unset($unguarded);
     return $file->getRedirectResponse();
 }
 private function buildOperationsBox(DifferentialRevision $revision)
 {
     $viewer = $this->getViewer();
     // Save a query if we can't possibly have pending operations.
     $repository = $revision->getRepository();
     if (!$repository || !$repository->canPerformAutomation()) {
         return null;
     }
     $operations = id(new DrydockRepositoryOperationQuery())->setViewer($viewer)->withObjectPHIDs(array($revision->getPHID()))->withOperationStates(array(DrydockRepositoryOperation::STATE_WAIT, DrydockRepositoryOperation::STATE_WORK, DrydockRepositoryOperation::STATE_FAIL))->execute();
     if (!$operations) {
         return null;
     }
     $operation = head(msort($operations, 'getID'));
     $box_view = id(new PHUIObjectBoxView())->setHeaderText(pht('Active Operations'));
     return id(new DrydockRepositoryOperationStatusView())->setUser($viewer)->setBoxView($box_view)->setOperation($operation);
 }
 private function buildTransactions(DifferentialRevision $revision, DifferentialDiff $left_diff, DifferentialDiff $right_diff, array $changesets)
 {
     $viewer = $this->getRequest()->getUser();
     $xactions = id(new DifferentialTransactionQuery())->setViewer($viewer)->withObjectPHIDs(array($revision->getPHID()))->needComments(true)->execute();
     $timeline = id(new DifferentialTransactionView())->setUser($viewer)->setObjectPHID($revision->getPHID())->setChangesets($changesets)->setRevision($revision)->setLeftDiff($left_diff)->setRightDiff($right_diff)->setTransactions($xactions);
     return $timeline;
 }
 private function buildOperationsBox(DifferentialRevision $revision)
 {
     $viewer = $this->getViewer();
     // Save a query if we can't possibly have pending operations.
     $repository = $revision->getRepository();
     if (!$repository || !$repository->canPerformAutomation()) {
         return null;
     }
     $operations = id(new DrydockRepositoryOperationQuery())->setViewer($viewer)->withObjectPHIDs(array($revision->getPHID()))->withIsDismissed(false)->withOperationTypes(array(DrydockLandRepositoryOperation::OPCONST))->execute();
     if (!$operations) {
         return null;
     }
     $state_fail = DrydockRepositoryOperation::STATE_FAIL;
     // We're going to show the oldest operation which hasn't failed, or the
     // most recent failure if they're all failures.
     $operations = msort($operations, 'getID');
     foreach ($operations as $operation) {
         if ($operation->getOperationState() != $state_fail) {
             break;
         }
     }
     // If we found a completed operation, don't render anything. We don't want
     // to show an older error after the thing worked properly.
     if ($operation->isDone()) {
         return null;
     }
     $box_view = id(new PHUIObjectBoxView())->setHeaderText(pht('Active Operations'));
     return id(new DrydockRepositoryOperationStatusView())->setUser($viewer)->setBoxView($box_view)->setOperation($operation);
 }
 public function getBarrierToLanding(PhabricatorUser $viewer, DifferentialRevision $revision)
 {
     $repository = $revision->getRepository();
     if (!$repository) {
         return array('title' => pht('No Repository'), 'body' => pht('This revision is not associated with a known repository. Only ' . 'revisions associated with a tracked repository can be landed ' . 'automatically.'));
     }
     if (!$repository->canPerformAutomation()) {
         return array('title' => pht('No Repository Automation'), 'body' => pht('The repository this revision is associated with ("%s") is not ' . 'configured to support automation. Configure automation for the ' . 'repository to enable revisions to be landed automatically.', $repository->getMonogram()));
     }
     // TODO: At some point we should allow installs to give "land reviewed
     // code" permission to more users than "push any commit", because it is
     // a much less powerful operation. For now, just require push so this
     // doesn't do anything users can't do on their own.
     $can_push = PhabricatorPolicyFilter::hasCapability($viewer, $repository, DiffusionPushCapability::CAPABILITY);
     if (!$can_push) {
         return array('title' => pht('Unable to Push'), 'body' => pht('You do not have permission to push to the repository this ' . 'revision is associated with ("%s"), so you can not land it.', $repository->getMonogram()));
     }
     $status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED;
     if ($revision->getStatus() != $status_accepted) {
         switch ($revision->getStatus()) {
             case ArcanistDifferentialRevisionStatus::CLOSED:
                 return array('title' => pht('Revision Closed'), 'body' => pht('This revision has already been closed. Only open, accepted ' . 'revisions may land.'));
             case ArcanistDifferentialRevisionStatus::ABANDONED:
                 return array('title' => pht('Revision Abandoned'), 'body' => pht('This revision has been abandoned. Only accepted revisions ' . 'may land.'));
             default:
                 return array('title' => pht('Revision Not Accepted'), 'body' => pht('This revision is still under review. Only revisions which ' . 'have been accepted may land.'));
         }
     }
     // Check for other operations. Eventually this should probably be more
     // general (e.g., it's OK to land to multiple different branches
     // simultaneously) but just put this in as a sanity check for now.
     $other_operations = id(new DrydockRepositoryOperationQuery())->setViewer($viewer)->withObjectPHIDs(array($revision->getPHID()))->withOperationTypes(array($this->getOperationConstant()))->withOperationStates(array(DrydockRepositoryOperation::STATE_WAIT, DrydockRepositoryOperation::STATE_WORK, DrydockRepositoryOperation::STATE_DONE))->execute();
     if ($other_operations) {
         $any_done = false;
         foreach ($other_operations as $operation) {
             if ($operation->isDone()) {
                 $any_done = true;
                 break;
             }
         }
         if ($any_done) {
             return array('title' => pht('Already Complete'), 'body' => pht('This revision has already landed.'));
         } else {
             return array('title' => pht('Already In Flight'), 'body' => pht('This revision is already landing.'));
         }
     }
     return null;
 }
 private function getRevisionActions(DifferentialRevision $revision)
 {
     $user = $this->getRequest()->getUser();
     $viewer_phid = $user->getPHID();
     $viewer_is_owner = $revision->getAuthorPHID() == $viewer_phid;
     $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers());
     $viewer_is_cc = in_array($viewer_phid, $revision->getCCPHIDs());
     $viewer_is_anonymous = !$this->getRequest()->getUser()->isLoggedIn();
     $status = $revision->getStatus();
     $revision_id = $revision->getID();
     $revision_phid = $revision->getPHID();
     $links = array();
     if ($viewer_is_owner) {
         $links[] = array('class' => 'revision-edit', 'href' => "/differential/revision/edit/{$revision_id}/", 'name' => 'Edit Revision');
     }
     if (!$viewer_is_anonymous) {
         require_celerity_resource('phabricator-flag-css');
         $flag = PhabricatorFlagQuery::loadUserFlag($user, $revision_phid);
         if ($flag) {
             $class = PhabricatorFlagColor::getCSSClass($flag->getColor());
             $color = PhabricatorFlagColor::getColorName($flag->getColor());
             $links[] = array('class' => 'flag-clear ' . $class, 'href' => '/flag/delete/' . $flag->getID() . '/', 'name' => phutil_escape_html('Remove ' . $color . ' Flag'), 'sigil' => 'workflow');
         } else {
             $links[] = array('class' => 'flag-add phabricator-flag-ghost', 'href' => '/flag/edit/' . $revision_phid . '/', 'name' => 'Flag Revision', 'sigil' => 'workflow');
         }
         if (!$viewer_is_owner && !$viewer_is_reviewer) {
             $action = $viewer_is_cc ? 'rem' : 'add';
             $links[] = array('class' => $viewer_is_cc ? 'subscribe-rem' : 'subscribe-add', 'href' => "/differential/subscribe/{$action}/{$revision_id}/", 'name' => $viewer_is_cc ? 'Unsubscribe' : 'Subscribe', 'instant' => true);
         } else {
             $links[] = array('class' => 'subscribe-rem unavailable', 'name' => 'Automatically Subscribed');
         }
         require_celerity_resource('phabricator-object-selector-css');
         require_celerity_resource('javelin-behavior-phabricator-object-selector');
         $links[] = array('class' => 'action-dependencies', 'name' => 'Edit Dependencies', 'href' => "/search/attach/{$revision_phid}/DREV/dependencies/", 'sigil' => 'workflow');
         if (PhabricatorEnv::getEnvConfig('maniphest.enabled')) {
             $links[] = array('class' => 'attach-maniphest', 'name' => 'Edit Maniphest Tasks', 'href' => "/search/attach/{$revision_phid}/TASK/", 'sigil' => 'workflow');
         }
         if ($user->getIsAdmin()) {
             $links[] = array('class' => 'transcripts-metamta', 'name' => 'MetaMTA Transcripts', 'href' => "/mail/?phid={$revision_phid}");
         }
         $links[] = array('class' => 'transcripts-herald', 'name' => 'Herald Transcripts', 'href' => "/herald/transcript/?phid={$revision_phid}");
     }
     $request_uri = $this->getRequest()->getRequestURI();
     $links[] = array('class' => 'action-download', 'name' => 'Download Raw Diff', 'href' => $request_uri->alter('download', 'true'));
     return $links;
 }
 public static function loadUnsubmittedInlineComments(PhabricatorUser $viewer, DifferentialRevision $revision)
 {
     return id(new DifferentialDiffInlineCommentQuery())->setViewer($viewer)->withRevisionPHIDs(array($revision->getPHID()))->withAuthorPHIDs(array($viewer->getPHID()))->withHasTransaction(false)->withIsDeleted(false)->needReplyToComments(true)->execute();
 }
 public function setRevision(DifferentialRevision $revision)
 {
     $this->proxy->setRevisionPHID($revision->getPHID());
     return $this;
 }
 private function getRevisionActions(DifferentialRevision $revision)
 {
     $viewer_phid = $this->getRequest()->getUser()->getPHID();
     $viewer_is_owner = $revision->getAuthorPHID() == $viewer_phid;
     $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers());
     $viewer_is_cc = in_array($viewer_phid, $revision->getCCPHIDs());
     $viewer_is_anonymous = !$this->getRequest()->getUser()->isLoggedIn();
     $status = $revision->getStatus();
     $revision_id = $revision->getID();
     $revision_phid = $revision->getPHID();
     $links = array();
     if ($viewer_is_owner) {
         $links[] = array('class' => 'revision-edit', 'href' => "/differential/revision/edit/{$revision_id}/", 'name' => 'Edit Revision');
     }
     if (!$viewer_is_anonymous) {
         if (!$viewer_is_owner && !$viewer_is_reviewer) {
             $action = $viewer_is_cc ? 'rem' : 'add';
             $links[] = array('class' => $viewer_is_cc ? 'subscribe-rem' : 'subscribe-add', 'href' => "/differential/subscribe/{$action}/{$revision_id}/", 'name' => $viewer_is_cc ? 'Unsubscribe' : 'Subscribe', 'instant' => true);
         } else {
             $links[] = array('class' => 'subscribe-rem unavailable', 'name' => 'Automatically Subscribed');
         }
         require_celerity_resource('phabricator-object-selector-css');
         require_celerity_resource('javelin-behavior-phabricator-object-selector');
         $links[] = array('class' => 'action-dependencies', 'name' => 'Edit Dependencies', 'href' => "/search/attach/{$revision_phid}/DREV/dependencies/", 'sigil' => 'workflow');
         if (PhabricatorEnv::getEnvConfig('maniphest.enabled')) {
             $links[] = array('class' => 'attach-maniphest', 'name' => 'Edit Maniphest Tasks', 'href' => "/search/attach/{$revision_phid}/TASK/", 'sigil' => 'workflow');
         }
         $links[] = array('class' => 'transcripts-metamta', 'name' => 'MetaMTA Transcripts', 'href' => "/mail/?phid={$revision_phid}");
         $links[] = array('class' => 'transcripts-herald', 'name' => 'Herald Transcripts', 'href' => "/herald/transcript/?phid={$revision_phid}");
     }
     return $links;
 }
 private function buildOperationsBox(DifferentialRevision $revision)
 {
     $viewer = $this->getViewer();
     // Save a query if we can't possibly have pending operations.
     $repository = $revision->getRepository();
     if (!$repository || !$repository->canPerformAutomation()) {
         return null;
     }
     $operations = id(new DrydockRepositoryOperationQuery())->setViewer($viewer)->withObjectPHIDs(array($revision->getPHID()))->withOperationStates(array(DrydockRepositoryOperation::STATE_WAIT, DrydockRepositoryOperation::STATE_WORK, DrydockRepositoryOperation::STATE_FAIL))->execute();
     if (!$operations) {
         return null;
     }
     $operation = head(msort($operations, 'getID'));
     // TODO: This is completely made up for now, give it useful information and
     // a sweet progress bar.
     switch ($operation->getOperationState()) {
         case DrydockRepositoryOperation::STATE_WAIT:
         case DrydockRepositoryOperation::STATE_WORK:
             $severity = PHUIInfoView::SEVERITY_NOTICE;
             $text = pht('Some sort of repository operation is currently running.');
             break;
         default:
             $severity = PHUIInfoView::SEVERITY_ERROR;
             $text = pht('Some sort of repository operation failed.');
             break;
     }
     $info_view = id(new PHUIInfoView())->setSeverity($severity)->appendChild($text);
     return id(new PHUIObjectBoxView())->setHeaderText(pht('Active Operations (EXPERIMENTAL!)'))->setInfoView($info_view);
 }