Differential D20283 Diff 48438 src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
Changeset View
Changeset View
Standalone View
Standalone View
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
Show First 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | abstract class PhabricatorApplicationTransactionEditor | ||||
private $mailToPHIDs = array(); | private $mailToPHIDs = array(); | ||||
private $mailCCPHIDs = array(); | private $mailCCPHIDs = array(); | ||||
private $feedNotifyPHIDs = array(); | private $feedNotifyPHIDs = array(); | ||||
private $feedRelatedPHIDs = array(); | private $feedRelatedPHIDs = array(); | ||||
private $feedShouldPublish = false; | private $feedShouldPublish = false; | ||||
private $mailShouldSend = false; | private $mailShouldSend = false; | ||||
private $modularTypes; | private $modularTypes; | ||||
private $silent; | private $silent; | ||||
private $mustEncrypt; | private $mustEncrypt = array(); | ||||
private $stampTemplates = array(); | private $stampTemplates = array(); | ||||
private $mailStamps = array(); | private $mailStamps = array(); | ||||
private $oldTo = array(); | private $oldTo = array(); | ||||
private $oldCC = array(); | private $oldCC = array(); | ||||
private $mailRemovedPHIDs = array(); | private $mailRemovedPHIDs = array(); | ||||
private $mailUnexpandablePHIDs = array(); | private $mailUnexpandablePHIDs = array(); | ||||
private $mailMutedPHIDs = array(); | private $mailMutedPHIDs = array(); | ||||
private $webhookMap = array(); | private $webhookMap = array(); | ||||
private $transactionQueue = array(); | private $transactionQueue = array(); | ||||
private $sendHistory = false; | private $sendHistory = false; | ||||
private $shouldRequireMFA = false; | private $shouldRequireMFA = false; | ||||
private $hasRequiredMFA = false; | private $hasRequiredMFA = false; | ||||
private $request; | private $request; | ||||
private $cancelURI; | private $cancelURI; | ||||
private $extensions; | private $extensions; | ||||
private $parentEditor; | |||||
private $subEditors = array(); | |||||
private $publishableObject; | |||||
private $publishableTransactions; | |||||
const STORAGE_ENCODING_BINARY = 'binary'; | const STORAGE_ENCODING_BINARY = 'binary'; | ||||
/** | /** | ||||
* Get the class name for the application this editor is a part of. | * Get the class name for the application this editor is a part of. | ||||
* | * | ||||
* Uninstalling the application will disable the editor. | * Uninstalling the application will disable the editor. | ||||
* | * | ||||
* @return string Editor's application class name. | * @return string Editor's application class name. | ||||
▲ Show 20 Lines • Show All 1,166 Lines • ▼ Show 20 Lines | if ($this->getIsHeraldEditor()) { | ||||
// TODO: It would be nice to give transactions a more specific source | // TODO: It would be nice to give transactions a more specific source | ||||
// which points at the rule which generated them. You can figure this | // which points at the rule which generated them. You can figure this | ||||
// out from transcripts, but it would be cleaner if you didn't have to. | // out from transcripts, but it would be cleaner if you didn't have to. | ||||
$herald_source = PhabricatorContentSource::newForSource( | $herald_source = PhabricatorContentSource::newForSource( | ||||
PhabricatorHeraldContentSource::SOURCECONST); | PhabricatorHeraldContentSource::SOURCECONST); | ||||
$herald_editor = newv(get_class($this), array()) | $herald_editor = $this->newEditorCopy() | ||||
->setContinueOnNoEffect(true) | ->setContinueOnNoEffect(true) | ||||
->setContinueOnMissingFields(true) | ->setContinueOnMissingFields(true) | ||||
->setParentMessageID($this->getParentMessageID()) | |||||
->setIsHeraldEditor(true) | ->setIsHeraldEditor(true) | ||||
->setActor($herald_actor) | ->setActor($herald_actor) | ||||
->setActingAsPHID($herald_phid) | ->setActingAsPHID($herald_phid) | ||||
->setContentSource($herald_source); | ->setContentSource($herald_source); | ||||
$herald_xactions = $herald_editor->applyTransactions( | $herald_xactions = $herald_editor->applyTransactions( | ||||
$object, | $object, | ||||
$herald_xactions); | $herald_xactions); | ||||
Show All 38 Lines | if ($herald_xscript) { | ||||
$object->getPHID(), | $object->getPHID(), | ||||
$herald_header); | $herald_header); | ||||
} else { | } else { | ||||
$herald_header = HeraldTranscript::loadXHeraldRulesHeader( | $herald_header = HeraldTranscript::loadXHeraldRulesHeader( | ||||
$object->getPHID()); | $object->getPHID()); | ||||
} | } | ||||
$this->heraldHeader = $herald_header; | $this->heraldHeader = $herald_header; | ||||
// See PHI1134. If we're a subeditor, we don't publish information about | |||||
// the edit yet. Our parent editor still needs to finish applying | |||||
// transactions and execute Herald, which may change the information we | |||||
amckinley: All hail Herlad! | |||||
// publish. | |||||
// For example, Herald actions may change the parent object's title or | |||||
// visibility, or Herald may apply rules like "Must Encrypt" that affect | |||||
// email. | |||||
// Once the parent finishes work, it will queue its own publish step and | |||||
// then queue publish steps for its children. | |||||
$this->publishableObject = $object; | |||||
$this->publishableTransactions = $xactions; | |||||
if (!$this->parentEditor) { | |||||
$this->queuePublishing(); | |||||
} | |||||
return $xactions; | |||||
} | |||||
final private function queuePublishing() { | |||||
$object = $this->publishableObject; | |||||
$xactions = $this->publishableTransactions; | |||||
if (!$object) { | |||||
throw new Exception( | |||||
pht( | |||||
'Editor method "queuePublishing()" was called, but no publishable '. | |||||
'object is present. This Editor is not ready to publish.')); | |||||
} | |||||
// We're going to compute some of the data we'll use to publish these | // We're going to compute some of the data we'll use to publish these | ||||
// transactions here, before queueing a worker. | // transactions here, before queueing a worker. | ||||
// | // | ||||
// Primarily, this is more correct: we want to publish the object as it | // Primarily, this is more correct: we want to publish the object as it | ||||
// exists right now. The worker may not execute for some time, and we want | // exists right now. The worker may not execute for some time, and we want | ||||
// to use the current To/CC list, not respect any changes which may occur | // to use the current To/CC list, not respect any changes which may occur | ||||
// between now and when the worker executes. | // between now and when the worker executes. | ||||
// | // | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | PhabricatorWorker::scheduleTask( | ||||
'xactionPHIDs' => mpull($xactions, 'getPHID'), | 'xactionPHIDs' => mpull($xactions, 'getPHID'), | ||||
'state' => $this->getWorkerState(), | 'state' => $this->getWorkerState(), | ||||
), | ), | ||||
array( | array( | ||||
'objectPHID' => $object->getPHID(), | 'objectPHID' => $object->getPHID(), | ||||
'priority' => PhabricatorWorker::PRIORITY_ALERTS, | 'priority' => PhabricatorWorker::PRIORITY_ALERTS, | ||||
)); | )); | ||||
$this->flushTransactionQueue($object); | foreach ($this->subEditors as $sub_editor) { | ||||
$sub_editor->queuePublishing(); | |||||
} | |||||
return $xactions; | $this->flushTransactionQueue($object); | ||||
} | } | ||||
protected function didCatchDuplicateKeyException( | protected function didCatchDuplicateKeyException( | ||||
PhabricatorLiskDAO $object, | PhabricatorLiskDAO $object, | ||||
array $xactions, | array $xactions, | ||||
Exception $ex) { | Exception $ex) { | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,407 Lines • ▼ Show 20 Lines | if ($adapter instanceof HarbormasterBuildableAdapterInterface) { | ||||
$this->getActor(), | $this->getActor(), | ||||
HarbormasterMessageType::BUILDABLE_BUILD, | HarbormasterMessageType::BUILDABLE_BUILD, | ||||
true); | true); | ||||
} | } | ||||
} | } | ||||
$this->mustEncrypt = $adapter->getMustEncryptReasons(); | $this->mustEncrypt = $adapter->getMustEncryptReasons(); | ||||
// See PHI1134. Propagate "Must Encrypt" state to sub-editors. | |||||
foreach ($this->subEditors as $sub_editor) { | |||||
$sub_editor->mustEncrypt = $this->mustEncrypt; | |||||
} | |||||
$apply_xactions = $this->didApplyHeraldRules($object, $adapter, $xscript); | $apply_xactions = $this->didApplyHeraldRules($object, $adapter, $xscript); | ||||
assert_instances_of($apply_xactions, 'PhabricatorApplicationTransaction'); | assert_instances_of($apply_xactions, 'PhabricatorApplicationTransaction'); | ||||
$queue_xactions = $adapter->getQueuedTransactions(); | $queue_xactions = $adapter->getQueuedTransactions(); | ||||
return array_merge( | return array_merge( | ||||
array_values($apply_xactions), | array_values($apply_xactions), | ||||
array_values($queue_xactions)); | array_values($queue_xactions)); | ||||
▲ Show 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | foreach ($nodes as $node) { | ||||
} | } | ||||
$template | $template | ||||
->setTransactionType($xaction->getTransactionType()) | ->setTransactionType($xaction->getTransactionType()) | ||||
->setMetadataValue('edge:type', $inverse_type) | ->setMetadataValue('edge:type', $inverse_type) | ||||
->setOldValue($old_phids) | ->setOldValue($old_phids) | ||||
->setNewValue($new_phids); | ->setNewValue($new_phids); | ||||
$editor | $editor = $this->newSubEditor($editor) | ||||
->setContinueOnNoEffect(true) | ->setContinueOnNoEffect(true) | ||||
->setContinueOnMissingFields(true) | ->setContinueOnMissingFields(true) | ||||
->setParentMessageID($this->getParentMessageID()) | ->setIsInverseEdgeEditor(true); | ||||
->setIsInverseEdgeEditor(true) | |||||
->setIsSilent($this->getIsSilent()) | |||||
->setActor($this->requireActor()) | |||||
->setActingAsPHID($this->getActingAsPHID()) | |||||
->setContentSource($this->getContentSource()); | |||||
$editor->applyTransactions($node, array($template)); | $editor->applyTransactions($node, array($template)); | ||||
} | } | ||||
} | } | ||||
/* -( Workers )------------------------------------------------------------ */ | /* -( Workers )------------------------------------------------------------ */ | ||||
▲ Show 20 Lines • Show All 492 Lines • ▼ Show 20 Lines | /* -( Queue )-------------------------------------------------------------- */ | ||||
private function flushTransactionQueue($object) { | private function flushTransactionQueue($object) { | ||||
if (!$this->transactionQueue) { | if (!$this->transactionQueue) { | ||||
return; | return; | ||||
} | } | ||||
$xactions = $this->transactionQueue; | $xactions = $this->transactionQueue; | ||||
$this->transactionQueue = array(); | $this->transactionQueue = array(); | ||||
$editor = $this->newQueueEditor(); | $editor = $this->newEditorCopy(); | ||||
return $editor->applyTransactions($object, $xactions); | return $editor->applyTransactions($object, $xactions); | ||||
} | } | ||||
private function newQueueEditor() { | final protected function newSubEditor( | ||||
$editor = id(newv(get_class($this), array())) | PhabricatorApplicationTransactionEditor $template = null) { | ||||
$editor = $this->newEditorCopy($template); | |||||
$editor->parentEditor = $this; | |||||
$this->subEditors[] = $editor; | |||||
return $editor; | |||||
} | |||||
private function newEditorCopy( | |||||
PhabricatorApplicationTransactionEditor $template = null) { | |||||
if ($template === null) { | |||||
$template = newv(get_class($this), array()); | |||||
} | |||||
$editor = id(clone $template) | |||||
->setActor($this->getActor()) | ->setActor($this->getActor()) | ||||
->setContentSource($this->getContentSource()) | ->setContentSource($this->getContentSource()) | ||||
->setContinueOnNoEffect($this->getContinueOnNoEffect()) | ->setContinueOnNoEffect($this->getContinueOnNoEffect()) | ||||
->setContinueOnMissingFields($this->getContinueOnMissingFields()) | ->setContinueOnMissingFields($this->getContinueOnMissingFields()) | ||||
->setParentMessageID($this->getParentMessageID()) | |||||
->setIsSilent($this->getIsSilent()); | ->setIsSilent($this->getIsSilent()); | ||||
if ($this->actingAsPHID !== null) { | if ($this->actingAsPHID !== null) { | ||||
$editor->setActingAsPHID($this->actingAsPHID); | $editor->setActingAsPHID($this->actingAsPHID); | ||||
} | } | ||||
$editor->mustEncrypt = $this->mustEncrypt; | |||||
return $editor; | return $editor; | ||||
} | } | ||||
/* -( Stamps )------------------------------------------------------------- */ | /* -( Stamps )------------------------------------------------------------- */ | ||||
public function newMailStampTemplates($object) { | public function newMailStampTemplates($object) { | ||||
▲ Show 20 Lines • Show All 613 Lines • Show Last 20 Lines |
All hail Herlad!