Path: blob/master/src/applications/diffusion/worker/DiffusionUpdateObjectAfterCommitWorker.php
12241 views
<?php12final class DiffusionUpdateObjectAfterCommitWorker3extends PhabricatorWorker {45private $properties;67protected function getViewer() {8return PhabricatorUser::getOmnipotentUser();9}1011protected function doWork() {12$viewer = $this->getViewer();13$data = $this->getTaskData();1415$commit_phid = idx($data, 'commitPHID');16if (!$commit_phid) {17throw new PhabricatorWorkerPermanentFailureException(18pht('No "commitPHID" in task data.'));19}2021$commit = id(new DiffusionCommitQuery())22->setViewer($viewer)23->withPHIDs(array($commit_phid))24->needIdentities(true)25->executeOne();26if (!$commit) {27throw new PhabricatorWorkerPermanentFailureException(28pht(29'Unable to load commit "%s".',30$commit_phid));31}3233$object_phid = idx($data, 'objectPHID');34if (!$object_phid) {35throw new PhabricatorWorkerPermanentFailureException(36pht('No "objectPHID" in task data.'));37}3839$object = id(new PhabricatorObjectQuery())40->setViewer($viewer)41->withPHIDs(array($object_phid))42->executeOne();43if (!$object) {44throw new PhabricatorWorkerPermanentFailureException(45pht(46'Unable to load object "%s".',47$object_phid));48}4950$properties = idx($data, 'properties', array());51$this->properties = $properties;5253if ($object instanceof ManiphestTask) {54$this->updateTask($commit, $object);55} else if ($object instanceof DifferentialRevision) {56$this->updateRevision($commit, $object);57}58}5960protected function getUpdateProperty($key, $default = null) {61return idx($this->properties, $key, $default);62}6364protected function getActingPHID(PhabricatorRepositoryCommit $commit) {65if ($commit->hasCommitterIdentity()) {66return $commit->getCommitterIdentity()->getIdentityDisplayPHID();67}6869if ($commit->hasAuthorIdentity()) {70return $commit->getAuthorIdentity()->getIdentityDisplayPHID();71}7273return id(new PhabricatorDiffusionApplication())->getPHID();74}7576protected function loadActingUser($acting_phid) {77// If we we were able to identify an author or committer for the commit, we78// try to act as that user when affecting other objects, like tasks marked79// with "Fixes Txxx".8081// This helps to prevent mistakes where a user accidentally writes the82// wrong task IDs and affects tasks they can't see (and thus can't undo the83// status changes for).8485// This is just a guard rail, not a security measure. An attacker can still86// forge another user's identity trivially by forging author or committer87// email addresses.8889// We also let commits with unrecognized authors act on any task to make90// behavior less confusing for new installs, and any user can craft a91// commit with an unrecognized author and committer.9293$viewer = $this->getViewer();9495$user_type = PhabricatorPeopleUserPHIDType::TYPECONST;96if (phid_get_type($acting_phid) === $user_type) {97$acting_user = id(new PhabricatorPeopleQuery())98->setViewer($viewer)99->withPHIDs(array($acting_phid))100->executeOne();101if ($acting_user) {102return $acting_user;103}104}105106return $viewer;107}108109private function updateTask(110PhabricatorRepositoryCommit $commit,111ManiphestTask $task) {112113$acting_phid = $this->getActingPHID($commit);114$acting_user = $this->loadActingUser($acting_phid);115116$commit_phid = $commit->getPHID();117118$xactions = array();119120$xactions[] = $this->newEdgeTransaction(121$task,122$commit,123ManiphestTaskHasCommitEdgeType::EDGECONST);124125$status = $this->getUpdateProperty('status');126if ($status) {127$xactions[] = $task->getApplicationTransactionTemplate()128->setTransactionType(ManiphestTaskStatusTransaction::TRANSACTIONTYPE)129->setMetadataValue('commitPHID', $commit_phid)130->setNewValue($status);131}132133$content_source = $this->newContentSource();134135$editor = $task->getApplicationTransactionEditor()136->setActor($acting_user)137->setActingAsPHID($acting_phid)138->setContentSource($content_source)139->setContinueOnNoEffect(true)140->setContinueOnMissingFields(true)141->addUnmentionablePHIDs(array($commit_phid));142143$editor->applyTransactions($task, $xactions);144}145146private function updateRevision(147PhabricatorRepositoryCommit $commit,148DifferentialRevision $revision) {149150$acting_phid = $this->getActingPHID($commit);151$acting_user = $this->loadActingUser($acting_phid);152153// See T13625. The "Acting User" is the author of the commit based on the154// author string, or the Diffusion application PHID if we could not155// identify an author.156157// This user may not be able to view the commit or the revision, and may158// also be unable to make API calls. Here, we execute queries and apply159// transactions as the omnipotent user.160161// It would probably be better to use the acting user everywhere here, and162// exit gracefully if they can't see the revision (this is how the flow163// on tasks works). However, without a positive indicator in the UI164// explaining "no revision was updated because the author of this commit165// can't see anything", this might be fairly confusing, and break workflows166// which have worked historically.167168// This isn't, per se, a policy violation (you can't get access to anything169// you don't already have access to by making commits that reference170// revisions, even if you can't see the commits or revisions), so just171// leave it for now.172173$viewer = $this->getViewer();174175// Reload the revision to get the active diff, which is currently required176// by "updateRevisionWithCommit()".177$revision = id(new DifferentialRevisionQuery())178->setViewer($viewer)179->withIDs(array($revision->getID()))180->needActiveDiffs(true)181->executeOne();182183$xactions = array();184185$xactions[] = $this->newEdgeTransaction(186$revision,187$commit,188DifferentialRevisionHasCommitEdgeType::EDGECONST);189190$match_data = $this->getUpdateProperty('revisionMatchData');191192$type_close = DifferentialRevisionCloseTransaction::TRANSACTIONTYPE;193$xactions[] = $revision->getApplicationTransactionTemplate()194->setTransactionType($type_close)195->setNewValue(true)196->setMetadataValue('isCommitClose', true)197->setMetadataValue('revisionMatchData', $match_data)198->setMetadataValue('commitPHID', $commit->getPHID());199200$extraction_engine = id(new DifferentialDiffExtractionEngine())201->setViewer($viewer)202->setAuthorPHID($acting_phid);203204$content_source = $this->newContentSource();205206$extraction_engine->updateRevisionWithCommit(207$revision,208$commit,209$xactions,210$content_source);211}212213private function newEdgeTransaction(214$object,215PhabricatorRepositoryCommit $commit,216$edge_type) {217218$commit_phid = $commit->getPHID();219220return $object->getApplicationTransactionTemplate()221->setTransactionType(PhabricatorTransactions::TYPE_EDGE)222->setMetadataValue('edge:type', $edge_type)223->setNewValue(224array(225'+' => array(226$commit_phid => $commit_phid,227),228));229}230231232}233234235