1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-02-03 02:18:24 +01:00
phorge-phorge/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php

172 lines
5 KiB
PHP
Raw Normal View History

<?php
abstract class PhabricatorApplicationTransactionReplyHandler
extends PhabricatorMailReplyHandler {
abstract public function getObjectPrefix();
public function getPrivateReplyHandlerEmailAddress(
Build separate mail for each recipient, honoring recipient access levels Summary: Ref T6367. Removes `multiplexMail()`! We can't pass a single body into a function which splits it anymore: we need to split recipients first, then build bodies for each recipient list. This lets us build separate bodies for each recipient's individual translation/access levels. The new logic does this: - First, split recipients into groups called "targets". - Each target corresponds to one actual mail we're going to build. - Each target has a viewer (whose translation / access levels will be used to generate the mail). - Each target has a to/cc list (the users who we'll ultimately send the mail to). - For each target, build a custom mail body based on the viewer's access levels and settings (language prefs not actually implemented). - Then, deliver the mail. Test Plan: - Read new config help. Then did a bunch of testing, primarily with `bin/mail list-outbound` and `bin/mail show-outbound` (to review generated mail), `bin/phd debug taskmaster` (to run daemons freely) and `bin/worker execute --id <id>` (to repeatedly test a specific piece of code after identifying an issue). With `one-mail-per-recipient` on (default): - Sent mail to multiple users. - Verified mail showed up in `mail list-outbound`. - Examined mail with `mail show-outbound`. - Added a project that a subscriber could not see. - Verified it was not present in `X-Phabricator-Projects`. - Verified it was rendered as "Restricted Project" for the non-permissioned viewer. - Added a subscriber, then changed the object policy so they could not see it and sent mail. - Verified I received mail but the other user did not. - Enabled public replies and verified mail generated with public addresses. - Disabld public replies and verified mail generated with private addresses. With `one-mail-per-recipient` off: - Verified that one mail is sent to all recipients. - Verified users who can not see the object are still filtered. - Verified that partially-visible projects are completely visible in the mail (this violates policies, as documented, as the best available compromise). - Enabled public replies and verified the mail generated with "Reply To". Reviewers: btrahan Reviewed By: btrahan Subscribers: carlsverre, epriestley Maniphest Tasks: T6367 Differential Revision: https://secure.phabricator.com/D13131
2015-06-02 14:29:30 -07:00
PhabricatorUser $user) {
return $this->getDefaultPrivateReplyHandlerEmailAddress(
Build separate mail for each recipient, honoring recipient access levels Summary: Ref T6367. Removes `multiplexMail()`! We can't pass a single body into a function which splits it anymore: we need to split recipients first, then build bodies for each recipient list. This lets us build separate bodies for each recipient's individual translation/access levels. The new logic does this: - First, split recipients into groups called "targets". - Each target corresponds to one actual mail we're going to build. - Each target has a viewer (whose translation / access levels will be used to generate the mail). - Each target has a to/cc list (the users who we'll ultimately send the mail to). - For each target, build a custom mail body based on the viewer's access levels and settings (language prefs not actually implemented). - Then, deliver the mail. Test Plan: - Read new config help. Then did a bunch of testing, primarily with `bin/mail list-outbound` and `bin/mail show-outbound` (to review generated mail), `bin/phd debug taskmaster` (to run daemons freely) and `bin/worker execute --id <id>` (to repeatedly test a specific piece of code after identifying an issue). With `one-mail-per-recipient` on (default): - Sent mail to multiple users. - Verified mail showed up in `mail list-outbound`. - Examined mail with `mail show-outbound`. - Added a project that a subscriber could not see. - Verified it was not present in `X-Phabricator-Projects`. - Verified it was rendered as "Restricted Project" for the non-permissioned viewer. - Added a subscriber, then changed the object policy so they could not see it and sent mail. - Verified I received mail but the other user did not. - Enabled public replies and verified mail generated with public addresses. - Disabld public replies and verified mail generated with private addresses. With `one-mail-per-recipient` off: - Verified that one mail is sent to all recipients. - Verified users who can not see the object are still filtered. - Verified that partially-visible projects are completely visible in the mail (this violates policies, as documented, as the best available compromise). - Enabled public replies and verified the mail generated with "Reply To". Reviewers: btrahan Reviewed By: btrahan Subscribers: carlsverre, epriestley Maniphest Tasks: T6367 Differential Revision: https://secure.phabricator.com/D13131
2015-06-02 14:29:30 -07:00
$user,
$this->getObjectPrefix());
}
public function getPublicReplyHandlerEmailAddress() {
return $this->getDefaultPublicReplyHandlerEmailAddress(
$this->getObjectPrefix());
}
private function newEditor(PhabricatorMetaMTAReceivedMail $mail) {
$content_source = $mail->newContentSource();
$editor = $this->getMailReceiver()
->getApplicationTransactionEditor()
->setActor($this->getActor())
->setContentSource($content_source)
->setContinueOnMissingFields(true)
->setParentMessageID($mail->getMessageID())
->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs());
if ($this->getApplicationEmail()) {
$editor->setApplicationEmail($this->getApplicationEmail());
}
return $editor;
}
protected function newTransaction() {
return $this->getMailReceiver()->getApplicationTransactionTemplate();
}
protected function didReceiveMail(
PhabricatorMetaMTAReceivedMail $mail,
$body) {
return array();
}
protected function shouldCreateCommentFromMailBody() {
return (bool)$this->getMailReceiver()->getID();
}
final protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) {
$viewer = $this->getActor();
$object = $this->getMailReceiver();
$app_email = $this->getApplicationEmail();
$is_new = !$object->getID();
// If this is a new object which implements the Spaces interface and was
// created by sending mail to an ApplicationEmail address, put the object
// in the same Space the address is in.
if ($is_new) {
if ($object instanceof PhabricatorSpacesInterface) {
if ($app_email) {
$space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID(
$app_email);
$object->setSpacePHID($space_phid);
}
}
}
$body_data = $mail->parseBody();
$body = $body_data['body'];
$body = $this->enhanceBodyWithAttachments($body, $mail->getAttachments());
$xactions = $this->didReceiveMail($mail, $body);
// If this object is subscribable, subscribe all the users who were
// recipients on the message.
if ($object instanceof PhabricatorSubscribableInterface) {
$subscriber_phids = $mail->loadAllRecipientPHIDs();
if ($subscriber_phids) {
$xactions[] = $this->newTransaction()
->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
->setNewValue(
array(
'+' => $subscriber_phids,
));
}
}
$command_xactions = $this->processMailCommands(
$mail,
$body_data['commands']);
foreach ($command_xactions as $xaction) {
$xactions[] = $xaction;
}
if ($this->shouldCreateCommentFromMailBody()) {
$comment = $this
->newTransaction()
->getApplicationTransactionCommentObject()
->setContent($body);
$xactions[] = $this->newTransaction()
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment($comment);
}
$this->newEditor($mail)
->setContinueOnNoEffect(true)
Remove "getApplicationTransactionObject()" from ApplicationTransactionInterface Summary: Depends on D19919. Ref T11351. This method appeared in D8802 (note that "get...Object" was renamed to "get...Transaction" there, so this method was actually "new" even though a method of the same name had existed before). The goal at the time was to let Harbormaster post build results to Diffs and have them end up on Revisions, but this eventually got a better implementation (see below) where the Harbormaster-specific code can just specify a "publishable object" where build results should go. The new `get...Object` semantics ultimately broke some stuff, and the actual implementation in Differential was removed in D10911, so this method hasn't really served a purpose since December 2014. I think that broke the Harbormaster thing by accident and we just lived with it for a bit, then Harbormaster got some more work and D17139 introduced "publishable" objects which was a better approach. This was later refined by D19281. So: the original problem (sending build results to the right place) has a good solution now, this method hasn't done anything for 4 years, and it was probably a bad idea in the first place since it's pretty weird/surprising/fragile. Note that `Comment` objects still have an unrelated method with the same name. In that case, the method ties the `Comment` storage object to the related `Transaction` storage object. Test Plan: Grepped for `getApplicationTransactionObject`, verified that all remaining callsites are related to `Comment` objects. Reviewers: amckinley Reviewed By: amckinley Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam Maniphest Tasks: T11351 Differential Revision: https://secure.phabricator.com/D19920
2018-12-20 10:41:01 -08:00
->applyTransactions($object, $xactions);
}
private function processMailCommands(
PhabricatorMetaMTAReceivedMail $mail,
array $command_list) {
$viewer = $this->getActor();
$object = $this->getMailReceiver();
$list = MetaMTAEmailTransactionCommand::getAllCommandsForObject($object);
$map = MetaMTAEmailTransactionCommand::getCommandMap($list);
$xactions = array();
foreach ($command_list as $command_argv) {
$command = head($command_argv);
$argv = array_slice($command_argv, 1);
$handler = idx($map, phutil_utf8_strtolower($command));
if ($handler) {
$results = $handler->buildTransactions(
$viewer,
$object,
$mail,
$command,
$argv);
foreach ($results as $result) {
$xactions[] = $result;
}
} else {
$valid_commands = array();
foreach ($list as $valid_command) {
$aliases = $valid_command->getCommandAliases();
if ($aliases) {
foreach ($aliases as $key => $alias) {
$aliases[$key] = '!'.$alias;
}
$aliases = implode(', ', $aliases);
$valid_commands[] = pht(
'!%s (or %s)',
$valid_command->getCommand(),
$aliases);
} else {
$valid_commands[] = '!'.$valid_command->getCommand();
}
}
throw new Exception(
pht(
'The command "!%s" is not a supported mail command. Valid '.
'commands for this object are: %s.',
$command,
implode(', ', $valid_commands)));
}
}
return $xactions;
}
}