mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Projects - add mail to project updates
Summary: ...which lets all the fancy settings for Email | Notify | Off be possible. Fixes T8164. Wasn't too sure the best way to break things up but members vs watchers felt meaningful to break out to me. Also fixes a small bug where we were generating bad slug updated stories by messing with the signature of the slug data. Perhaps this fix isn't even good enough (the array_keys()) call and instead we'll need to implement transaction has effect and do a sort? Test Plan: used ./bin/mail list-outbound and ./bin/mail show-outbound --id XX to verify reasonable emails were being generated. saw new preferences in settings. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin, epriestley Maniphest Tasks: T8164 Differential Revision: https://secure.phabricator.com/D12868
This commit is contained in:
parent
3ef0721ada
commit
fa82c17079
5 changed files with 145 additions and 6 deletions
|
@ -3101,6 +3101,7 @@ phutil_register_library_map(array(
|
|||
'ProjectQueryConduitAPIMethod' => 'applications/project/conduit/ProjectQueryConduitAPIMethod.php',
|
||||
'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php',
|
||||
'ProjectRemarkupRuleTestCase' => 'applications/project/remarkup/__tests__/ProjectRemarkupRuleTestCase.php',
|
||||
'ProjectReplyHandler' => 'applications/project/mail/ProjectReplyHandler.php',
|
||||
'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php',
|
||||
'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php',
|
||||
'ReleephBranch' => 'applications/releeph/storage/ReleephBranch.php',
|
||||
|
@ -6670,6 +6671,7 @@ phutil_register_library_map(array(
|
|||
'ProjectQueryConduitAPIMethod' => 'ProjectConduitAPIMethod',
|
||||
'ProjectRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||
'ProjectRemarkupRuleTestCase' => 'PhabricatorTestCase',
|
||||
'ProjectReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
||||
'QueryFormattingTestCase' => 'PhabricatorTestCase',
|
||||
'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification',
|
||||
'ReleephBranch' => array(
|
||||
|
|
|
@ -41,7 +41,7 @@ final class PhabricatorProjectTransactionEditor
|
|||
$slugs = $object->getSlugs();
|
||||
$slugs = mpull($slugs, 'getSlug', 'getSlug');
|
||||
unset($slugs[$object->getPrimarySlug()]);
|
||||
return $slugs;
|
||||
return array_keys($slugs);
|
||||
case PhabricatorProjectTransaction::TYPE_STATUS:
|
||||
return $object->getStatus();
|
||||
case PhabricatorProjectTransaction::TYPE_IMAGE:
|
||||
|
@ -403,11 +403,74 @@ final class PhabricatorProjectTransactionEditor
|
|||
return parent::requireCapabilities($object, $xaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: this is implemented for Feed purposes.
|
||||
*/
|
||||
protected function loadEdges(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
$member_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$object->getPHID(),
|
||||
PhabricatorProjectProjectHasMemberEdgeType::EDGECONST);
|
||||
$object->attachMemberPHIDs($member_phids);
|
||||
}
|
||||
|
||||
protected function shouldSendMail(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getMailSubjectPrefix() {
|
||||
return pht('[Project]');
|
||||
}
|
||||
|
||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||
return array();
|
||||
return $object->getMemberPHIDs();
|
||||
}
|
||||
|
||||
protected function getMailCC(PhabricatorLiskDAO $object) {
|
||||
$all = parent::getMailCC($object);
|
||||
return array_diff($all, $object->getMemberPHIDs());
|
||||
}
|
||||
|
||||
public function getMailTagsMap() {
|
||||
return array(
|
||||
PhabricatorProjectTransaction::MAILTAG_METADATA =>
|
||||
pht('Project name, hashtags, icon, image, or color changes.'),
|
||||
PhabricatorProjectTransaction::MAILTAG_MEMBERS =>
|
||||
pht('Project membership changes.'),
|
||||
PhabricatorProjectTransaction::MAILTAG_WATCHERS =>
|
||||
pht('Project watcher list changes.'),
|
||||
PhabricatorProjectTransaction::MAILTAG_OTHER =>
|
||||
pht('Other project activity not listed above occurs.'),
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
|
||||
return id(new ProjectReplyHandler())
|
||||
->setMailReceiver($object);
|
||||
}
|
||||
|
||||
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||
$id = $object->getID();
|
||||
$name = $object->getName();
|
||||
|
||||
return id(new PhabricatorMetaMTAMail())
|
||||
->setSubject("{$name}")
|
||||
->addHeader('Thread-Topic', "Project {$id}");
|
||||
}
|
||||
|
||||
protected function buildMailBody(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
$body = parent::buildMailBody($object, $xactions);
|
||||
|
||||
$uri = '/project/profile/'.$object->getID().'/';
|
||||
$body->addLinkSection(
|
||||
pht('PROJECT DETAIL'),
|
||||
PhabricatorEnv::getProductionURI($uri));
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
protected function shouldPublishFeedStory(
|
||||
|
|
20
src/applications/project/mail/ProjectReplyHandler.php
Normal file
20
src/applications/project/mail/ProjectReplyHandler.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
final class ProjectReplyHandler
|
||||
extends PhabricatorApplicationTransactionReplyHandler {
|
||||
|
||||
public function validateMailReceiver($mail_receiver) {
|
||||
if (!($mail_receiver instanceof PhabricatorProject)) {
|
||||
throw new Exception('Mail receiver is not a PhabricatorProject.');
|
||||
}
|
||||
}
|
||||
|
||||
public function getObjectPrefix() {
|
||||
return PhabricatorProjectProjectPHIDType::TYPECONST;
|
||||
}
|
||||
|
||||
protected function shouldCreateCommentFromMailBody() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -14,6 +14,11 @@ final class PhabricatorProjectTransaction
|
|||
// NOTE: This is deprecated, members are just a normal edge now.
|
||||
const TYPE_MEMBERS = 'project:members';
|
||||
|
||||
const MAILTAG_METADATA = 'project-metadata';
|
||||
const MAILTAG_MEMBERS = 'project-members';
|
||||
const MAILTAG_WATCHERS = 'project-watchers';
|
||||
const MAILTAG_OTHER = 'project-other';
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'project';
|
||||
}
|
||||
|
@ -106,6 +111,8 @@ final class PhabricatorProjectTransaction
|
|||
$old,
|
||||
$new);
|
||||
}
|
||||
break;
|
||||
|
||||
case self::TYPE_STATUS:
|
||||
if ($old == 0) {
|
||||
return pht(
|
||||
|
@ -116,6 +123,8 @@ final class PhabricatorProjectTransaction
|
|||
'%s activated this project.',
|
||||
$author_handle);
|
||||
}
|
||||
break;
|
||||
|
||||
case self::TYPE_IMAGE:
|
||||
// TODO: Some day, it would be nice to show the images.
|
||||
if (!$old) {
|
||||
|
@ -134,18 +143,21 @@ final class PhabricatorProjectTransaction
|
|||
$this->renderHandleLink($old),
|
||||
$this->renderHandleLink($new));
|
||||
}
|
||||
break;
|
||||
|
||||
case self::TYPE_ICON:
|
||||
return pht(
|
||||
'%s set this project\'s icon to %s.',
|
||||
$author_handle,
|
||||
PhabricatorProjectIcon::getLabel($new));
|
||||
break;
|
||||
|
||||
case self::TYPE_COLOR:
|
||||
return pht(
|
||||
'%s set this project\'s color to %s.',
|
||||
$author_handle,
|
||||
PHUITagView::getShadeName($new));
|
||||
break;
|
||||
|
||||
case self::TYPE_LOCKED:
|
||||
if ($new) {
|
||||
|
@ -157,6 +169,7 @@ final class PhabricatorProjectTransaction
|
|||
'%s unlocked this project\'s membership.',
|
||||
$author_handle);
|
||||
}
|
||||
break;
|
||||
|
||||
case self::TYPE_SLUGS:
|
||||
$add = array_diff($new, $old);
|
||||
|
@ -183,6 +196,7 @@ final class PhabricatorProjectTransaction
|
|||
count($rem),
|
||||
$this->renderSlugList($rem));
|
||||
}
|
||||
break;
|
||||
|
||||
case self::TYPE_MEMBERS:
|
||||
$add = array_diff($new, $old);
|
||||
|
@ -221,6 +235,7 @@ final class PhabricatorProjectTransaction
|
|||
$this->renderHandleList($rem));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
|
@ -339,12 +354,43 @@ final class PhabricatorProjectTransaction
|
|||
$object_handle,
|
||||
$this->renderSlugList($rem));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return parent::getTitleForFeed();
|
||||
}
|
||||
|
||||
public function getMailTags() {
|
||||
$tags = array();
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_NAME:
|
||||
case self::TYPE_SLUGS:
|
||||
case self::TYPE_IMAGE:
|
||||
case self::TYPE_ICON:
|
||||
case self::TYPE_COLOR:
|
||||
$tags[] = self::MAILTAG_METADATA;
|
||||
break;
|
||||
case PhabricatorTransactions::TYPE_EDGE:
|
||||
$type = $this->getMetadata('edge:type');
|
||||
$type = head($type);
|
||||
$type_member = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST;
|
||||
$type_watcher = PhabricatorObjectHasWatcherEdgeType::EDGECONST;
|
||||
if ($type == $type_member) {
|
||||
$tags[] = self::MAILTAG_MEMBERS;
|
||||
} else if ($type == $type_watcher) {
|
||||
$tags[] = self::MAILTAG_WATCHERS;
|
||||
} else {
|
||||
$tags[] = self::MAILTAG_OTHER;
|
||||
}
|
||||
break;
|
||||
case self::TYPE_STATUS:
|
||||
case self::TYPE_LOCKED:
|
||||
default:
|
||||
$tags[] = self::MAILTAG_OTHER;
|
||||
break;
|
||||
}
|
||||
return $tags;
|
||||
}
|
||||
|
||||
private function renderSlugList($slugs) {
|
||||
return implode(', ', $slugs);
|
||||
}
|
||||
|
|
|
@ -840,6 +840,8 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
// subscribers to pick up changes caused by Herald (or by other side effects
|
||||
// in various transaction phases).
|
||||
$this->loadSubscribers($object);
|
||||
// Hook for other edges that may need (re-)loading
|
||||
$this->loadEdges($object, $xactions);
|
||||
|
||||
$this->loadHandles($xactions);
|
||||
|
||||
|
@ -965,6 +967,12 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
}
|
||||
}
|
||||
|
||||
protected function loadEdges(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
return;
|
||||
}
|
||||
|
||||
private function validateEditParameters(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
|
Loading…
Reference in a new issue