Differential D19372 Diff 46346 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 77 Lines • ▼ Show 20 Lines | abstract class PhabricatorApplicationTransactionEditor | ||||
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; | |||||
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. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 201 Lines • ▼ Show 20 Lines | public function getTransactionTypesForObject($object) { | ||||
} | } | ||||
return $result; | return $result; | ||||
} | } | ||||
public function getTransactionTypes() { | public function getTransactionTypes() { | ||||
$types = array(); | $types = array(); | ||||
$types[] = PhabricatorTransactions::TYPE_CREATE; | $types[] = PhabricatorTransactions::TYPE_CREATE; | ||||
$types[] = PhabricatorTransactions::TYPE_HISTORY; | |||||
if ($this->object instanceof PhabricatorEditEngineSubtypeInterface) { | if ($this->object instanceof PhabricatorEditEngineSubtypeInterface) { | ||||
$types[] = PhabricatorTransactions::TYPE_SUBTYPE; | $types[] = PhabricatorTransactions::TYPE_SUBTYPE; | ||||
} | } | ||||
if ($this->object instanceof PhabricatorSubscribableInterface) { | if ($this->object instanceof PhabricatorSubscribableInterface) { | ||||
$types[] = PhabricatorTransactions::TYPE_SUBSCRIBERS; | $types[] = PhabricatorTransactions::TYPE_SUBSCRIBERS; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | private function getTransactionOldValue( | ||||
if ($xtype) { | if ($xtype) { | ||||
$xtype = clone $xtype; | $xtype = clone $xtype; | ||||
$xtype->setStorage($xaction); | $xtype->setStorage($xaction); | ||||
return $xtype->generateOldValue($object); | return $xtype->generateOldValue($object); | ||||
} | } | ||||
switch ($type) { | switch ($type) { | ||||
case PhabricatorTransactions::TYPE_CREATE: | case PhabricatorTransactions::TYPE_CREATE: | ||||
case PhabricatorTransactions::TYPE_HISTORY: | |||||
return null; | return null; | ||||
case PhabricatorTransactions::TYPE_SUBTYPE: | case PhabricatorTransactions::TYPE_SUBTYPE: | ||||
return $object->getEditEngineSubtype(); | return $object->getEditEngineSubtype(); | ||||
case PhabricatorTransactions::TYPE_SUBSCRIBERS: | case PhabricatorTransactions::TYPE_SUBSCRIBERS: | ||||
return array_values($this->subscribers); | return array_values($this->subscribers); | ||||
case PhabricatorTransactions::TYPE_VIEW_POLICY: | case PhabricatorTransactions::TYPE_VIEW_POLICY: | ||||
if ($this->getIsNewObject()) { | if ($this->getIsNewObject()) { | ||||
return null; | return null; | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | switch ($type) { | ||||
case PhabricatorTransactions::TYPE_SUBSCRIBERS: | case PhabricatorTransactions::TYPE_SUBSCRIBERS: | ||||
return $this->getPHIDTransactionNewValue($xaction); | return $this->getPHIDTransactionNewValue($xaction); | ||||
case PhabricatorTransactions::TYPE_VIEW_POLICY: | case PhabricatorTransactions::TYPE_VIEW_POLICY: | ||||
case PhabricatorTransactions::TYPE_EDIT_POLICY: | case PhabricatorTransactions::TYPE_EDIT_POLICY: | ||||
case PhabricatorTransactions::TYPE_JOIN_POLICY: | case PhabricatorTransactions::TYPE_JOIN_POLICY: | ||||
case PhabricatorTransactions::TYPE_TOKEN: | case PhabricatorTransactions::TYPE_TOKEN: | ||||
case PhabricatorTransactions::TYPE_INLINESTATE: | case PhabricatorTransactions::TYPE_INLINESTATE: | ||||
case PhabricatorTransactions::TYPE_SUBTYPE: | case PhabricatorTransactions::TYPE_SUBTYPE: | ||||
case PhabricatorTransactions::TYPE_HISTORY: | |||||
return $xaction->getNewValue(); | return $xaction->getNewValue(); | ||||
case PhabricatorTransactions::TYPE_SPACE: | case PhabricatorTransactions::TYPE_SPACE: | ||||
$space_phid = $xaction->getNewValue(); | $space_phid = $xaction->getNewValue(); | ||||
if (!strlen($space_phid)) { | if (!strlen($space_phid)) { | ||||
// If an install has no Spaces or the Spaces controls are not visible | // If an install has no Spaces or the Spaces controls are not visible | ||||
// to the viewer, we might end up with the empty string here instead | // to the viewer, we might end up with the empty string here instead | ||||
// of a strict `null`, because some controller just used `getStr()` | // of a strict `null`, because some controller just used `getStr()` | ||||
// to read the space PHID from the request. | // to read the space PHID from the request. | ||||
Show All 36 Lines | abstract class PhabricatorApplicationTransactionEditor | ||||
} | } | ||||
protected function transactionHasEffect( | protected function transactionHasEffect( | ||||
PhabricatorLiskDAO $object, | PhabricatorLiskDAO $object, | ||||
PhabricatorApplicationTransaction $xaction) { | PhabricatorApplicationTransaction $xaction) { | ||||
switch ($xaction->getTransactionType()) { | switch ($xaction->getTransactionType()) { | ||||
case PhabricatorTransactions::TYPE_CREATE: | case PhabricatorTransactions::TYPE_CREATE: | ||||
case PhabricatorTransactions::TYPE_HISTORY: | |||||
return true; | return true; | ||||
case PhabricatorTransactions::TYPE_CUSTOMFIELD: | case PhabricatorTransactions::TYPE_CUSTOMFIELD: | ||||
$field = $this->getCustomFieldForTransaction($object, $xaction); | $field = $this->getCustomFieldForTransaction($object, $xaction); | ||||
return $field->getApplicationTransactionHasEffect($xaction); | return $field->getApplicationTransactionHasEffect($xaction); | ||||
case PhabricatorTransactions::TYPE_EDGE: | case PhabricatorTransactions::TYPE_EDGE: | ||||
// A straight value comparison here doesn't always get the right | // A straight value comparison here doesn't always get the right | ||||
// result, because newly added edges aren't fully populated. Instead, | // result, because newly added edges aren't fully populated. Instead, | ||||
// compare the changes in a more granular way. | // compare the changes in a more granular way. | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | if ($xtype) { | ||||
return $xtype->applyInternalEffects($object, $xaction->getNewValue()); | return $xtype->applyInternalEffects($object, $xaction->getNewValue()); | ||||
} | } | ||||
switch ($type) { | switch ($type) { | ||||
case PhabricatorTransactions::TYPE_CUSTOMFIELD: | case PhabricatorTransactions::TYPE_CUSTOMFIELD: | ||||
$field = $this->getCustomFieldForTransaction($object, $xaction); | $field = $this->getCustomFieldForTransaction($object, $xaction); | ||||
return $field->applyApplicationTransactionInternalEffects($xaction); | return $field->applyApplicationTransactionInternalEffects($xaction); | ||||
case PhabricatorTransactions::TYPE_CREATE: | case PhabricatorTransactions::TYPE_CREATE: | ||||
case PhabricatorTransactions::TYPE_HISTORY: | |||||
case PhabricatorTransactions::TYPE_SUBTYPE: | case PhabricatorTransactions::TYPE_SUBTYPE: | ||||
case PhabricatorTransactions::TYPE_TOKEN: | case PhabricatorTransactions::TYPE_TOKEN: | ||||
case PhabricatorTransactions::TYPE_VIEW_POLICY: | case PhabricatorTransactions::TYPE_VIEW_POLICY: | ||||
case PhabricatorTransactions::TYPE_EDIT_POLICY: | case PhabricatorTransactions::TYPE_EDIT_POLICY: | ||||
case PhabricatorTransactions::TYPE_JOIN_POLICY: | case PhabricatorTransactions::TYPE_JOIN_POLICY: | ||||
case PhabricatorTransactions::TYPE_SUBSCRIBERS: | case PhabricatorTransactions::TYPE_SUBSCRIBERS: | ||||
case PhabricatorTransactions::TYPE_INLINESTATE: | case PhabricatorTransactions::TYPE_INLINESTATE: | ||||
case PhabricatorTransactions::TYPE_EDGE: | case PhabricatorTransactions::TYPE_EDGE: | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | switch ($type) { | ||||
$xaction->getNewValue())); | $xaction->getNewValue())); | ||||
$this->subscribers = $subscribers; | $this->subscribers = $subscribers; | ||||
return $this->applyBuiltinExternalTransaction($object, $xaction); | return $this->applyBuiltinExternalTransaction($object, $xaction); | ||||
case PhabricatorTransactions::TYPE_CUSTOMFIELD: | case PhabricatorTransactions::TYPE_CUSTOMFIELD: | ||||
$field = $this->getCustomFieldForTransaction($object, $xaction); | $field = $this->getCustomFieldForTransaction($object, $xaction); | ||||
return $field->applyApplicationTransactionExternalEffects($xaction); | return $field->applyApplicationTransactionExternalEffects($xaction); | ||||
case PhabricatorTransactions::TYPE_CREATE: | case PhabricatorTransactions::TYPE_CREATE: | ||||
case PhabricatorTransactions::TYPE_HISTORY: | |||||
case PhabricatorTransactions::TYPE_SUBTYPE: | case PhabricatorTransactions::TYPE_SUBTYPE: | ||||
case PhabricatorTransactions::TYPE_EDGE: | case PhabricatorTransactions::TYPE_EDGE: | ||||
case PhabricatorTransactions::TYPE_TOKEN: | case PhabricatorTransactions::TYPE_TOKEN: | ||||
case PhabricatorTransactions::TYPE_VIEW_POLICY: | case PhabricatorTransactions::TYPE_VIEW_POLICY: | ||||
case PhabricatorTransactions::TYPE_EDIT_POLICY: | case PhabricatorTransactions::TYPE_EDIT_POLICY: | ||||
case PhabricatorTransactions::TYPE_JOIN_POLICY: | case PhabricatorTransactions::TYPE_JOIN_POLICY: | ||||
case PhabricatorTransactions::TYPE_INLINESTATE: | case PhabricatorTransactions::TYPE_INLINESTATE: | ||||
case PhabricatorTransactions::TYPE_SPACE: | case PhabricatorTransactions::TYPE_SPACE: | ||||
▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | switch ($xaction->getTransactionType()) { | ||||
$editor->save(); | $editor->save(); | ||||
$this->updateWorkboardColumns($object, $const, $old, $new); | $this->updateWorkboardColumns($object, $const, $old, $new); | ||||
break; | break; | ||||
case PhabricatorTransactions::TYPE_VIEW_POLICY: | case PhabricatorTransactions::TYPE_VIEW_POLICY: | ||||
case PhabricatorTransactions::TYPE_SPACE: | case PhabricatorTransactions::TYPE_SPACE: | ||||
$this->scrambleFileSecrets($object); | $this->scrambleFileSecrets($object); | ||||
break; | break; | ||||
case PhabricatorTransactions::TYPE_HISTORY: | |||||
$this->sendHistory = true; | |||||
break; | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Fill in a transaction's common values, like author and content source. | * Fill in a transaction's common values, like author and content source. | ||||
*/ | */ | ||||
protected function populateTransaction( | protected function populateTransaction( | ||||
PhabricatorLiskDAO $object, | PhabricatorLiskDAO $object, | ||||
▲ Show 20 Lines • Show All 501 Lines • ▼ Show 20 Lines | if ($this->feedShouldPublish) { | ||||
foreach ($mail->buildRecipientList() as $phid) { | foreach ($mail->buildRecipientList() as $phid) { | ||||
$mailed[$phid] = $phid; | $mailed[$phid] = $phid; | ||||
} | } | ||||
} | } | ||||
$this->publishFeedStory($object, $xactions, $mailed); | $this->publishFeedStory($object, $xactions, $mailed); | ||||
} | } | ||||
if ($this->sendHistory) { | |||||
$history_mail = $this->buildHistoryMail($object); | |||||
if ($history_mail) { | |||||
$messages[] = $history_mail; | |||||
} | |||||
} | |||||
// NOTE: This actually sends the mail. We do this last to reduce the chance | // NOTE: This actually sends the mail. We do this last to reduce the chance | ||||
// that we send some mail, hit an exception, then send the mail again when | // that we send some mail, hit an exception, then send the mail again when | ||||
// retrying. | // retrying. | ||||
foreach ($messages as $mail) { | foreach ($messages as $mail) { | ||||
$mail->save(); | $mail->save(); | ||||
} | } | ||||
$this->queueWebhooks($object, $xactions); | $this->queueWebhooks($object, $xactions); | ||||
▲ Show 20 Lines • Show All 1,224 Lines • ▼ Show 20 Lines | private function buildMail( | ||||
$email_cc = $this->mailCCPHIDs; | $email_cc = $this->mailCCPHIDs; | ||||
$email_cc = array_merge($email_cc, $this->heraldEmailPHIDs); | $email_cc = array_merge($email_cc, $this->heraldEmailPHIDs); | ||||
$unexpandable = $this->mailUnexpandablePHIDs; | $unexpandable = $this->mailUnexpandablePHIDs; | ||||
if (!is_array($unexpandable)) { | if (!is_array($unexpandable)) { | ||||
$unexpandable = array(); | $unexpandable = array(); | ||||
} | } | ||||
$messages = $this->buildMailWithRecipients( | |||||
$object, | |||||
$xactions, | |||||
$email_to, | |||||
$email_cc, | |||||
$unexpandable); | |||||
$this->runHeraldMailRules($messages); | |||||
return $messages; | |||||
} | |||||
private function buildMailWithRecipients( | |||||
PhabricatorLiskDAO $object, | |||||
array $xactions, | |||||
array $email_to, | |||||
array $email_cc, | |||||
array $unexpandable) { | |||||
$targets = $this->buildReplyHandler($object) | $targets = $this->buildReplyHandler($object) | ||||
->setUnexpandablePHIDs($unexpandable) | ->setUnexpandablePHIDs($unexpandable) | ||||
->getMailTargets($email_to, $email_cc); | ->getMailTargets($email_to, $email_cc); | ||||
// Set this explicitly before we start swapping out the effective actor. | // Set this explicitly before we start swapping out the effective actor. | ||||
$this->setActingAsPHID($this->getActingAsPHID()); | $this->setActingAsPHID($this->getActingAsPHID()); | ||||
$messages = array(); | $messages = array(); | ||||
Show All 30 Lines | foreach ($targets as $target) { | ||||
throw $ex; | throw $ex; | ||||
} | } | ||||
if ($mail) { | if ($mail) { | ||||
$messages[] = $mail; | $messages[] = $mail; | ||||
} | } | ||||
} | } | ||||
$this->runHeraldMailRules($messages); | |||||
return $messages; | return $messages; | ||||
} | } | ||||
protected function getTransactionsForMail( | protected function getTransactionsForMail( | ||||
PhabricatorLiskDAO $object, | PhabricatorLiskDAO $object, | ||||
array $xactions) { | array $xactions) { | ||||
return $xactions; | return $xactions; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,050 Lines • ▼ Show 20 Lines | return array( | ||||
'feedShouldPublish', | 'feedShouldPublish', | ||||
'mailShouldSend', | 'mailShouldSend', | ||||
'mustEncrypt', | 'mustEncrypt', | ||||
'mailStamps', | 'mailStamps', | ||||
'mailUnexpandablePHIDs', | 'mailUnexpandablePHIDs', | ||||
'mailMutedPHIDs', | 'mailMutedPHIDs', | ||||
'webhookMap', | 'webhookMap', | ||||
'silent', | 'silent', | ||||
'sendHistory', | |||||
); | ); | ||||
} | } | ||||
/** | /** | ||||
* Apply encodings prior to storage. | * Apply encodings prior to storage. | ||||
* | * | ||||
* See @{method:getCustomWorkerStateEncoding}. | * See @{method:getCustomWorkerStateEncoding}. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 641 Lines • ▼ Show 20 Lines | private function hasWarnings($object, $xaction) { | ||||
} | } | ||||
// NOTE: This will currently warn even if you're only removing | // NOTE: This will currently warn even if you're only removing | ||||
// subscribers. | // subscribers. | ||||
return true; | return true; | ||||
} | } | ||||
private function buildHistoryMail(PhabricatorLiskDAO $object) { | |||||
$viewer = $this->requireActor(); | |||||
$recipient_phid = $this->getActingAsPHID(); | |||||
// Load every transaction so we can build a mail message with a complete | |||||
// history for the object. | |||||
$query = PhabricatorApplicationTransactionQuery::newQueryForObject($object); | |||||
$xactions = $query | |||||
->setViewer($viewer) | |||||
->withObjectPHIDs(array($object->getPHID())) | |||||
->execute(); | |||||
$xactions = array_reverse($xactions); | |||||
$mail_messages = $this->buildMailWithRecipients( | |||||
$object, | |||||
$xactions, | |||||
array($recipient_phid), | |||||
array(), | |||||
array()); | |||||
$mail = head($mail_messages); | |||||
// Since the user explicitly requested "!history", force delivery of this | |||||
// message regardless of their other mail settings. | |||||
$mail->setForceDelivery(true); | |||||
return $mail; | |||||
} | |||||
} | } |