diff --git a/resources/sql/autopatches/20150514.phame.blog.xaction.sql b/resources/sql/autopatches/20150514.phame.blog.xaction.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20150514.phame.blog.xaction.sql @@ -0,0 +1,19 @@ +CREATE TABLE {$NAMESPACE}_phame.phame_blogtransaction ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + phid VARBINARY(64) NOT NULL, + authorPHID VARBINARY(64) NOT NULL, + objectPHID VARBINARY(64) NOT NULL, + viewPolicy VARBINARY(64) NOT NULL, + editPolicy VARBINARY(64) NOT NULL, + commentPHID VARBINARY(64) DEFAULT NULL, + commentVersion INT UNSIGNED NOT NULL, + transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL, + oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, + newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, + contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, + metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + UNIQUE KEY `key_phid` (`phid`), + KEY `key_object` (`objectPHID`) +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2775,11 +2775,13 @@ 'PhameBlog' => 'applications/phame/storage/PhameBlog.php', 'PhameBlogDeleteController' => 'applications/phame/controller/blog/PhameBlogDeleteController.php', 'PhameBlogEditController' => 'applications/phame/controller/blog/PhameBlogEditController.php', + 'PhameBlogEditor' => 'applications/phame/editor/PhameBlogEditor.php', 'PhameBlogFeedController' => 'applications/phame/controller/blog/PhameBlogFeedController.php', 'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php', 'PhameBlogLiveController' => 'applications/phame/controller/blog/PhameBlogLiveController.php', 'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php', 'PhameBlogSkin' => 'applications/phame/skins/PhameBlogSkin.php', + 'PhameBlogTransaction' => 'applications/phame/storage/PhameBlogTransaction.php', 'PhameBlogViewController' => 'applications/phame/controller/blog/PhameBlogViewController.php', 'PhameCelerityResources' => 'applications/phame/celerity/PhameCelerityResources.php', 'PhameConduitAPIMethod' => 'applications/phame/conduit/PhameConduitAPIMethod.php', @@ -6250,11 +6252,13 @@ ), 'PhameBlogDeleteController' => 'PhameController', 'PhameBlogEditController' => 'PhameController', + 'PhameBlogEditor' => 'PhabricatorApplicationTransactionEditor', 'PhameBlogFeedController' => 'PhameController', 'PhameBlogListController' => 'PhameController', 'PhameBlogLiveController' => 'PhameController', 'PhameBlogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhameBlogSkin' => 'PhabricatorController', + 'PhameBlogTransaction' => 'PhabricatorApplicationTransaction', 'PhameBlogViewController' => 'PhameController', 'PhameCelerityResources' => 'CelerityResources', 'PhameConduitAPIMethod' => 'ConduitAPIMethod', diff --git a/src/applications/phame/controller/blog/PhameBlogDeleteController.php b/src/applications/phame/controller/blog/PhameBlogDeleteController.php --- a/src/applications/phame/controller/blog/PhameBlogDeleteController.php +++ b/src/applications/phame/controller/blog/PhameBlogDeleteController.php @@ -2,19 +2,13 @@ final class PhameBlogDeleteController extends PhameController { - private $id; - - public function willProcessRequest(array $data) { - $this->id = $data['id']; - } - - public function processRequest() { - $request = $this->getRequest(); + public function handleRequest(AphrontRequest $request) { $user = $request->getUser(); + $id = $request->getURIData('id'); $blog = id(new PhameBlogQuery()) ->setViewer($user) - ->withIDs(array($this->id)) + ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_EDIT, diff --git a/src/applications/phame/controller/blog/PhameBlogEditController.php b/src/applications/phame/controller/blog/PhameBlogEditController.php --- a/src/applications/phame/controller/blog/PhameBlogEditController.php +++ b/src/applications/phame/controller/blog/PhameBlogEditController.php @@ -3,20 +3,14 @@ final class PhameBlogEditController extends PhameController { - private $id; - - public function willProcessRequest(array $data) { - $this->id = idx($data, 'id'); - } - - public function processRequest() { - $request = $this->getRequest(); + public function handleRequest(AphrontRequest $request) { $user = $request->getUser(); - if ($this->id) { + $id = $request->getURIData('id'); + if ($id) { $blog = id(new PhameBlogQuery()) ->setViewer($user) - ->withIDs(array($this->id)) + ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_EDIT, @@ -30,76 +24,75 @@ $page_title = pht('Edit Blog'); $cancel_uri = $this->getApplicationURI('blog/view/'.$blog->getID().'/'); } else { - $blog = id(new PhameBlog()) - ->setCreatorPHID($user->getPHID()); - - $blog->setViewPolicy(PhabricatorPolicies::POLICY_USER); - $blog->setEditPolicy(PhabricatorPolicies::POLICY_USER); - $blog->setJoinPolicy(PhabricatorPolicies::POLICY_USER); + $blog = PhameBlog::initializeNewBlog($user); $submit_button = pht('Create Blog'); $page_title = pht('Create Blog'); $cancel_uri = $this->getApplicationURI(); } - - $e_name = true; - $e_custom_domain = null; - $errors = array(); - + $name = $blog->getName(); + $description = $blog->getDescription(); + $custom_domain = $blog->getDomain(); + $skin = $blog->getSkin(); + $can_view = $blog->getViewPolicy(); + $can_edit = $blog->getEditPolicy(); + $can_join = $blog->getJoinPolicy(); + + $e_name = true; + $e_custom_domain = null; + $e_view_policy = null; + $validation_exception = null; if ($request->isFormPost()) { $name = $request->getStr('name'); $description = $request->getStr('description'); - $custom_domain = $request->getStr('custom_domain'); + $custom_domain = nonempty($request->getStr('custom_domain'), null); $skin = $request->getStr('skin'); - - if (empty($name)) { - $errors[] = pht('You must give the blog a name.'); - $e_name = pht('Required'); - } else { - $e_name = null; - } - - $blog->setName($name); - $blog->setDescription($description); - $blog->setDomain(nonempty($custom_domain, null)); - $blog->setSkin($skin); - $blog->setViewPolicy($request->getStr('can_view')); - $blog->setEditPolicy($request->getStr('can_edit')); - $blog->setJoinPolicy($request->getStr('can_join')); - - if (!empty($custom_domain)) { - list($error_label, $error_text) = - $blog->validateCustomDomain($custom_domain); - if ($error_label) { - $errors[] = $error_text; - $e_custom_domain = $error_label; - } - if ($blog->getViewPolicy() != PhabricatorPolicies::POLICY_PUBLIC) { - $errors[] = pht( - 'For custom domains to work, the blog must have a view policy of '. - 'public.'); - // Prefer earlier labels for the multiple error scenario. - if (!$e_custom_domain) { - $e_custom_domain = pht('Invalid Policy'); - } - } - } - - // Don't let users remove their ability to edit blogs. - PhabricatorPolicyFilter::mustRetainCapability( - $user, - $blog, - PhabricatorPolicyCapability::CAN_EDIT); - - if (!$errors) { - try { - $blog->save(); - return id(new AphrontRedirectResponse()) - ->setURI($this->getApplicationURI('blog/view/'.$blog->getID().'/')); - } catch (AphrontDuplicateKeyQueryException $ex) { - $errors[] = pht('Domain must be unique.'); - $e_custom_domain = pht('Not Unique'); - } + $can_view = $request->getStr('can_view'); + $can_edit = $request->getStr('can_edit'); + $can_join = $request->getStr('can_join'); + + $xactions = array( + id(new PhameBlogTransaction()) + ->setTransactionType(PhameBlogTransaction::TYPE_NAME) + ->setNewValue($name), + id(new PhameBlogTransaction()) + ->setTransactionType(PhameBlogTransaction::TYPE_DESCRIPTION) + ->setNewValue($description), + id(new PhameBlogTransaction()) + ->setTransactionType(PhameBlogTransaction::TYPE_DOMAIN) + ->setNewValue($custom_domain), + id(new PhameBlogTransaction()) + ->setTransactionType(PhameBlogTransaction::TYPE_SKIN) + ->setNewValue($skin), + id(new PhameBlogTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) + ->setNewValue($can_view), + id(new PhameBlogTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) + ->setNewValue($can_edit), + id(new PhameBlogTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_JOIN_POLICY) + ->setNewValue($can_join), + ); + + $editor = id(new PhameBlogEditor()) + ->setActor($user) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true); + + try { + $editor->applyTransactions($blog, $xactions); + return id(new AphrontRedirectResponse()) + ->setURI($this->getApplicationURI('blog/view/'.$blog->getID().'/')); + } catch (PhabricatorApplicationTransactionValidationException $ex) { + $validation_exception = $ex; + + $e_name = $validation_exception->getShortMessage( + PhameBlogTransaction::TYPE_NAME); + $e_custom_domain = $validation_exception->getShortMessage( + PhameBlogTransaction::TYPE_DOMAIN); + $e_view_policy = $validation_exception->getShortMessage( + PhabricatorTransactions::TYPE_VIEW_POLICY); } } @@ -117,7 +110,7 @@ id(new AphrontFormTextControl()) ->setLabel(pht('Name')) ->setName('name') - ->setValue($blog->getName()) + ->setValue($name) ->setID('blog-name') ->setError($e_name)) ->appendChild( @@ -125,7 +118,7 @@ ->setUser($user) ->setLabel(pht('Description')) ->setName('description') - ->setValue($blog->getDescription()) + ->setValue($description) ->setID('blog-description') ->setUser($user) ->setDisableMacros(true)) @@ -135,6 +128,8 @@ ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicyObject($blog) ->setPolicies($policies) + ->setError($e_view_policy) + ->setValue($can_view) ->setName('can_view')) ->appendChild( id(new AphrontFormPolicyControl()) @@ -142,6 +137,7 @@ ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) ->setPolicyObject($blog) ->setPolicies($policies) + ->setValue($can_edit) ->setName('can_edit')) ->appendChild( id(new AphrontFormPolicyControl()) @@ -149,12 +145,13 @@ ->setCapability(PhabricatorPolicyCapability::CAN_JOIN) ->setPolicyObject($blog) ->setPolicies($policies) + ->setValue($can_join) ->setName('can_join')) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Custom Domain')) ->setName('custom_domain') - ->setValue($blog->getDomain()) + ->setValue($custom_domain) ->setCaption( pht('Must include at least one dot (.), e.g. blog.example.com')) ->setError($e_custom_domain)) @@ -162,7 +159,7 @@ id(new AphrontFormSelectControl()) ->setLabel(pht('Skin')) ->setName('skin') - ->setValue($blog->getSkin()) + ->setValue($skin) ->setOptions($skins)) ->appendChild( id(new AphrontFormSubmitControl()) @@ -171,14 +168,14 @@ $form_box = id(new PHUIObjectBoxView()) ->setHeaderText($page_title) - ->setFormErrors($errors) + ->setValidationException($validation_exception) ->setForm($form); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($page_title, $this->getApplicationURI('blog/new')); $nav = $this->renderSideNavFilterView(); - $nav->selectFilter($this->id ? null : 'blog/new'); + $nav->selectFilter($id ? null : 'blog/new'); $nav->appendChild( array( $crumbs, diff --git a/src/applications/phame/controller/blog/PhameBlogFeedController.php b/src/applications/phame/controller/blog/PhameBlogFeedController.php --- a/src/applications/phame/controller/blog/PhameBlogFeedController.php +++ b/src/applications/phame/controller/blog/PhameBlogFeedController.php @@ -2,23 +2,17 @@ final class PhameBlogFeedController extends PhameController { - private $id; - public function shouldRequireLogin() { return false; } - public function willProcessRequest(array $data) { - $this->id = $data['id']; - } - - public function processRequest() { - $request = $this->getRequest(); + public function handleRequest(AphrontRequest $request) { $user = $request->getUser(); + $id = $request->getURIData('id'); $blog = id(new PhameBlogQuery()) ->setViewer($user) - ->withIDs(array($this->id)) + ->withIDs(array($id)) ->executeOne(); if (!$blog) { return new Aphront404Response(); diff --git a/src/applications/phame/controller/blog/PhameBlogListController.php b/src/applications/phame/controller/blog/PhameBlogListController.php --- a/src/applications/phame/controller/blog/PhameBlogListController.php +++ b/src/applications/phame/controller/blog/PhameBlogListController.php @@ -2,18 +2,12 @@ final class PhameBlogListController extends PhameController { - private $filter; - - public function willProcessRequest(array $data) { - $this->filter = idx($data, 'filter'); - } - - public function processRequest() { - $request = $this->getRequest(); + public function handleRequest(AphrontRequest $request) { $user = $request->getUser(); $nav = $this->renderSideNavFilterView(null); - $filter = $nav->selectFilter('blog/'.$this->filter, 'blog/user'); + $filter = $request->getURIData('filter'); + $filter = $nav->selectFilter('blog/'.$filter, 'blog/user'); $query = id(new PhameBlogQuery()) ->setViewer($user); diff --git a/src/applications/phame/controller/blog/PhameBlogLiveController.php b/src/applications/phame/controller/blog/PhameBlogLiveController.php --- a/src/applications/phame/controller/blog/PhameBlogLiveController.php +++ b/src/applications/phame/controller/blog/PhameBlogLiveController.php @@ -2,25 +2,17 @@ final class PhameBlogLiveController extends PhameController { - private $id; - private $more; - public function shouldAllowPublic() { return true; } - public function willProcessRequest(array $data) { - $this->id = idx($data, 'id'); - $this->more = idx($data, 'more', ''); - } - - public function processRequest() { - $request = $this->getRequest(); + public function handleRequest(AphrontRequest $request) { $user = $request->getUser(); + $id = $request->getURIData('id'); $blog = id(new PhameBlogQuery()) ->setViewer($user) - ->withIDs(array($this->id)) + ->withIDs(array($id)) ->executeOne(); if (!$blog) { return new Aphront404Response(); @@ -55,7 +47,8 @@ } $phame_request = clone $request; - $phame_request->setPath('/'.ltrim($this->more, '/')); + $more = $phame_request->getURIData('more', ''); + $phame_request->setPath('/'.ltrim($more, '/')); $uri = $blog->getLiveURI(); diff --git a/src/applications/phame/controller/blog/PhameBlogViewController.php b/src/applications/phame/controller/blog/PhameBlogViewController.php --- a/src/applications/phame/controller/blog/PhameBlogViewController.php +++ b/src/applications/phame/controller/blog/PhameBlogViewController.php @@ -2,19 +2,13 @@ final class PhameBlogViewController extends PhameController { - private $id; - - public function willProcessRequest(array $data) { - $this->id = $data['id']; - } - - public function processRequest() { - $request = $this->getRequest(); + public function handleRequest(AphrontRequest $request) { $user = $request->getUser(); + $id = $request->getURIData('id'); $blog = id(new PhameBlogQuery()) ->setViewer($user) - ->withIDs(array($this->id)) + ->withIDs(array($id)) ->executeOne(); if (!$blog) { return new Aphront404Response(); diff --git a/src/applications/phame/editor/PhameBlogEditor.php b/src/applications/phame/editor/PhameBlogEditor.php new file mode 100644 --- /dev/null +++ b/src/applications/phame/editor/PhameBlogEditor.php @@ -0,0 +1,189 @@ +getTransactionType()) { + case PhameBlogTransaction::TYPE_NAME: + return $object->getName(); + case PhameBlogTransaction::TYPE_DESCRIPTION: + return $object->getDescription(); + case PhameBlogTransaction::TYPE_DOMAIN: + return $object->getDomain(); + case PhameBlogTransaction::TYPE_SKIN: + return $object->getSkin(); + } + } + + protected function getCustomTransactionNewValue( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case PhameBlogTransaction::TYPE_NAME: + case PhameBlogTransaction::TYPE_DESCRIPTION: + case PhameBlogTransaction::TYPE_DOMAIN: + case PhameBlogTransaction::TYPE_SKIN: + return $xaction->getNewValue(); + } + } + + protected function applyCustomInternalTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case PhameBlogTransaction::TYPE_NAME: + return $object->setName($xaction->getNewValue()); + case PhameBlogTransaction::TYPE_DESCRIPTION: + return $object->setDescription($xaction->getNewValue()); + case PhameBlogTransaction::TYPE_DOMAIN: + return $object->setDomain($xaction->getNewValue()); + case PhameBlogTransaction::TYPE_SKIN: + return $object->setSkin($xaction->getNewValue()); + case PhabricatorTransactions::TYPE_VIEW_POLICY: + $object->setViewPolicy($xaction->getNewValue()); + return; + case PhabricatorTransactions::TYPE_EDIT_POLICY: + $object->setEditPolicy($xaction->getNewValue()); + return; + case PhabricatorTransactions::TYPE_JOIN_POLICY: + $object->setJoinPolicy($xaction->getNewValue()); + return; + case PhabricatorTransactions::TYPE_COMMENT: + return; + } + + return parent::applyCustomInternalTransaction($object, $xaction); + } + + protected function applyCustomExternalTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case PhameBlogTransaction::TYPE_NAME: + case PhameBlogTransaction::TYPE_DESCRIPTION: + case PhameBlogTransaction::TYPE_DOMAIN: + case PhameBlogTransaction::TYPE_SKIN: + case PhabricatorTransactions::TYPE_VIEW_POLICY: + case PhabricatorTransactions::TYPE_EDIT_POLICY: + case PhabricatorTransactions::TYPE_JOIN_POLICY: + case PhabricatorTransactions::TYPE_COMMENT: + return; + } + + return parent::applyCustomExternalTransaction($object, $xaction); + } + + protected function validateTransaction( + PhabricatorLiskDAO $object, + $type, + array $xactions) { + + $errors = parent::validateTransaction($object, $type, $xactions); + + switch ($type) { + case PhameBlogTransaction::TYPE_NAME: + $missing = $this->validateIsEmptyTextField( + $object->getName(), + $xactions); + + if ($missing) { + $error = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Required'), + pht('Name is required.'), + nonempty(last($xactions), null)); + + $error->setIsMissingFieldError(true); + $errors[] = $error; + } + break; + case PhameBlogTransaction::TYPE_DOMAIN: + $custom_domain = last($xactions)->getNewValue(); + if (empty($custom_domain)) { + continue; + } + list($error_label, $error_text) = + $object->validateCustomDomain($custom_domain); + if ($error_label) { + $error = new PhabricatorApplicationTransactionValidationError( + $type, + $error_label, + $error_text, + nonempty(last($xactions), null)); + $errors[] = $error; + } + if ($object->getViewPolicy() != PhabricatorPolicies::POLICY_PUBLIC) { + $error_text = pht( + 'For custom domains to work, the blog must have a view policy of '. + 'public.'); + $error = new PhabricatorApplicationTransactionValidationError( + PhabricatorTransactions::TYPE_VIEW_POLICY, + pht('Invalid Policy'), + $error_text, + nonempty(last($xactions), null)); + $errors[] = $error; + } + $duplicate_blog = id(new PhameBlogQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withDomain($custom_domain) + ->executeOne(); + if ($duplicate_blog && $duplicate_blog->getID() != $object->getID()) { + $error = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Not Unique'), + pht('Domain must be unique; another blog already has this domain.'), + nonempty(last($xactions), null)); + $errors[] = $error; + } + + break; + } + return $errors; + } + + protected function shouldSendMail( + PhabricatorLiskDAO $object, + array $xactions) { + return false; + } + + protected function shouldPublishFeedStory( + PhabricatorLiskDAO $object, + array $xactions) { + return false; + } + + protected function supportsSearch() { + return false; + } + +} diff --git a/src/applications/phame/storage/PhameBlog.php b/src/applications/phame/storage/PhameBlog.php --- a/src/applications/phame/storage/PhameBlog.php +++ b/src/applications/phame/storage/PhameBlog.php @@ -16,9 +16,6 @@ protected $editPolicy; protected $joinPolicy; - private $bloggerPHIDs = self::ATTACHABLE; - private $bloggers = self::ATTACHABLE; - static private $requestBlog; protected function getConfiguration() { @@ -57,6 +54,15 @@ PhabricatorPhameBlogPHIDType::TYPECONST); } + public static function initializeNewBlog(PhabricatorUser $actor) { + $blog = id(new PhameBlog()) + ->setCreatorPHID($actor->getPHID()) + ->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy()) + ->setEditPolicy(PhabricatorPolicies::POLICY_USER) + ->setJoinPolicy(PhabricatorPolicies::POLICY_USER); + return $blog; + } + public function getSkinRenderer(AphrontRequest $request) { $spec = PhameSkinSpecification::loadOneSkinSpecification( $this->getSkin()); @@ -157,22 +163,6 @@ return null; } - public function getBloggerPHIDs() { - return $this->assertAttached($this->bloggerPHIDs); - } - - public function attachBloggers(array $bloggers) { - assert_instances_of($bloggers, 'PhabricatorObjectHandle'); - - $this->bloggers = $bloggers; - - return $this; - } - - public function getBloggers() { - return $this->assertAttached($this->bloggers); - } - public function getSkin() { $config = coalesce($this->getConfigData(), array()); return idx($config, 'skin', self::SKIN_DEFAULT); diff --git a/src/applications/phame/storage/PhameBlogTransaction.php b/src/applications/phame/storage/PhameBlogTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/phame/storage/PhameBlogTransaction.php @@ -0,0 +1,174 @@ +getOldValue(); + switch ($this->getTransactionType()) { + case self::TYPE_DESCRIPTION: + return ($old === null); + } + return parent::shouldHide(); + } + + public function getIcon() { + $old = $this->getOldValue(); + switch ($this->getTransactionType()) { + case self::TYPE_NAME: + if ($old === null) { + return 'fa-plus'; + } else { + return 'fa-pencil'; + } + break; + case self::TYPE_DESCRIPTION: + case self::TYPE_DOMAIN: + case self::TYPE_SKIN: + return 'fa-pencil'; + break; + } + return parent::getIcon(); + } + + public function getTitle() { + $author_phid = $this->getAuthorPHID(); + $object_phid = $this->getObjectPHID(); + + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $type = $this->getTransactionType(); + switch ($type) { + case self:TYPE_NAME: + if ($old === null) { + return pht( + '%s created this blog.', + $this->renderHandleLink($author_phid)); + } else { + return pht( + '%s updated the blog\'s name to "%s".', + $this->renderHandleLink($author_phid), + $new); + } + break; + case self::TYPE_DESCRIPTION: + return pht( + '%s updated the blog\'s description.', + $this->renderHandleLink($author_phid)); + break; + case self::TYPE_DOMAIN: + return pht( + '%s updated the blog\'s domain to "%s".', + $this->renderHandleLink($author_phid), + $new); + break; + case self::TYPE_SKIN: + return pht( + '%s updated the blog\'s skin to "%s".', + $this->renderHandleLink($author_phid), + $new); + break; + } + + return parent::getTitle(); + } + + public function getTitleForFeed() { + $author_phid = $this->getAuthorPHID(); + $object_phid = $this->getObjectPHID(); + + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $type = $this->getTransactionType(); + switch ($type) { + case self::TYPE_NAME: + if ($old === null) { + return pht( + '%s created %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + } else { + return pht( + '%s updated the name for %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + } + break; + case self::TYPE_DESCRIPTION: + return pht( + '%s updated the description for %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + break; + case self::TYPE_DOMAIN: + return pht( + '%s updated the domain for %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + break; + case self::TYPE_SKIN: + return pht( + '%s updated the skin for %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + break; + } + + return parent::getTitleForFeed(); + } + + public function getColor() { + $old = $this->getOldValue(); + + switch ($this->getTransactionType()) { + case self::TYPE_NAME: + if ($old === null) { + return PhabricatorTransactions::COLOR_GREEN; + } + break; + } + + return parent::getColor(); + } + + + public function hasChangeDetails() { + switch ($this->getTransactionType()) { + case self::TYPE_DESCRIPTION: + return ($this->getOldValue() !== null); + } + + return parent::hasChangeDetails(); + } + + public function renderChangeDetails(PhabricatorUser $viewer) { + switch ($this->getTransactionType()) { + case self::TYPE_DESCRIPTION: + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + return $this->renderTextCorpusChangeDetails( + $viewer, + $old, + $new); + } + + return parent::renderChangeDetails($viewer); + } + +}