diff --git a/src/applications/project/controller/PhabricatorProjectEditDetailsController.php b/src/applications/project/controller/PhabricatorProjectEditDetailsController.php index 5eb1ba1174..af92c60aea 100644 --- a/src/applications/project/controller/PhabricatorProjectEditDetailsController.php +++ b/src/applications/project/controller/PhabricatorProjectEditDetailsController.php @@ -77,10 +77,6 @@ final class PhabricatorProjectEditDetailsController $v_icon = $request->getStr('icon'); $v_locked = $request->getInt('is_membership_locked', 0); - $xactions = $field_list->buildFieldTransactionsFromRequest( - new PhabricatorProjectTransaction(), - $request); - $type_name = PhabricatorProjectTransaction::TYPE_NAME; $type_slugs = PhabricatorProjectTransaction::TYPE_SLUGS; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; @@ -88,6 +84,8 @@ final class PhabricatorProjectEditDetailsController $type_color = PhabricatorProjectTransaction::TYPE_COLOR; $type_locked = PhabricatorProjectTransaction::TYPE_LOCKED; + $xactions = array(); + $xactions[] = id(new PhabricatorProjectTransaction()) ->setTransactionType($type_name) ->setNewValue($v_name); @@ -120,6 +118,12 @@ final class PhabricatorProjectEditDetailsController ->setTransactionType($type_locked) ->setNewValue($v_locked); + $xactions = array_merge( + $xactions, + $field_list->buildFieldTransactionsFromRequest( + new PhabricatorProjectTransaction(), + $request)); + $editor = id(new PhabricatorProjectTransactionEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) diff --git a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php index 89ca641b91..98c4ad1797 100644 --- a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php +++ b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php @@ -403,6 +403,19 @@ final class PhabricatorProjectTransactionEditor return parent::requireCapabilities($object, $xaction); } + /** + * Note: this is implemented for Feed purposes. + */ + protected function getMailTo(PhabricatorLiskDAO $object) { + return array(); + } + + protected function shouldPublishFeedStory( + PhabricatorLiskDAO $object, + array $xactions) { + return true; + } + protected function supportsSearch() { return true; } diff --git a/src/applications/project/storage/PhabricatorProjectTransaction.php b/src/applications/project/storage/PhabricatorProjectTransaction.php index 381f4d6cb0..9b0ff0c340 100644 --- a/src/applications/project/storage/PhabricatorProjectTransaction.php +++ b/src/applications/project/storage/PhabricatorProjectTransaction.php @@ -226,6 +226,125 @@ final class PhabricatorProjectTransaction return parent::getTitle(); } + public function getTitleForFeed() { + $author_phid = $this->getAuthorPHID(); + $object_phid = $this->getObjectPHID(); + $author_handle = $this->renderHandleLink($author_phid); + $object_handle = $this->renderHandleLink($object_phid); + + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + switch ($this->getTransactionType()) { + case self::TYPE_NAME: + if ($old === null) { + return pht( + '%s created %s.', + $author_handle, + $object_handle); + } else { + return pht( + '%s renamed %s from "%s" to "%s".', + $author_handle, + $object_handle, + $old, + $new); + } + case self::TYPE_STATUS: + if ($old == 0) { + return pht( + '%s archived %s.', + $author_handle, + $object_handle); + } else { + return pht( + '%s activated %s.', + $author_handle, + $object_handle); + } + case self::TYPE_IMAGE: + // TODO: Some day, it would be nice to show the images. + if (!$old) { + return pht( + '%s set the image for %s to %s.', + $author_handle, + $object_handle, + $this->renderHandleLink($new)); + } else if (!$new) { + return pht( + '%s removed the image for %s.', + $author_handle, + $object_handle); + } else { + return pht( + '%s updated the image for %s from %s to %s.', + $author_handle, + $object_handle, + $this->renderHandleLink($old), + $this->renderHandleLink($new)); + } + + case self::TYPE_ICON: + return pht( + '%s set the icon for %s to %s.', + $author_handle, + $object_handle, + PhabricatorProjectIcon::getLabel($new)); + + case self::TYPE_COLOR: + return pht( + '%s set the color for %s to %s.', + $author_handle, + $object_handle, + PHUITagView::getShadeName($new)); + + case self::TYPE_LOCKED: + if ($new) { + return pht( + '%s locked %s membership.', + $author_handle, + $object_handle); + } else { + return pht( + '%s unlocked %s membership.', + $author_handle, + $object_handle); + } + + case self::TYPE_SLUGS: + $add = array_diff($new, $old); + $rem = array_diff($old, $new); + + if ($add && $rem) { + return pht( + '%s changed %s hashtag(s), added %d: %s; removed %d: %s.', + $author_handle, + $object_handle, + count($add), + $this->renderSlugList($add), + count($rem), + $this->renderSlugList($rem)); + } else if ($add) { + return pht( + '%s added %d %s hashtag(s): %s.', + $author_handle, + count($add), + $object_handle, + $this->renderSlugList($add)); + } else if ($rem) { + return pht( + '%s removed %d %s hashtag(s): %s.', + $author_handle, + count($rem), + $object_handle, + $this->renderSlugList($rem)); + } + + } + + return parent::getTitleForFeed(); + } + private function renderSlugList($slugs) { return implode(', ', $slugs); } diff --git a/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php b/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php index dbcd22b1ad..a1e0433b2c 100644 --- a/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php +++ b/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php @@ -735,6 +735,23 @@ final class PhabricatorUSEnglishTranslation ), ), + '%s changed %s hashtag(s), added %d: %s; removed %d: %s.' => + '%s changed hashtags for %s, added %4$s; removed %6$s.', + + '%s added %d %s hashtag(s): %s.' => array( + array( + '%s added a hashtag to %3$s: %4$s.', + '%s added hashtags to %3$s: %4$s.', + ), + ), + + '%s removed %d %s hashtag(s): %s.' => array( + array( + '%s removed a hashtag from %3$s: %4$s.', + '%s removed hashtags from %3$s: %4$s.', + ), + ), + '%d User(s) Need Approval' => array( '%d User Needs Approval', '%d Users Need Approval', @@ -948,6 +965,23 @@ final class PhabricatorUSEnglishTranslation '%s edited %s edge(s) for %s, added %s: %s; removed %s: %s.' => '%s edited edges for %3$s, added: %5$s; removed %7$s.', + '%s added %s member(s) for %s: %s.' => array( + array( + '%s added a member for %3$s: %4$s.', + '%s added members for %3$s: %4$s.', + ), + ), + + '%s removed %s member(s) for %s: %s.' => array( + array( + '%s removed a member for %3$s: %4$s.', + '%s removed members for %3$s: %4$s.', + ), + ), + + '%s edited %s member(s) for %s, added %s: %s; removed %s: %s.' => + '%s edited members for %3$s, added: %5$s; removed %7$s.', + '%d related link(s):' => array( 'Related link:', 'Related links:',