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; | |||||
| } | |||||
| } | } | ||||