diff --git a/src/applications/phame/controller/blog/PhameBlogHeaderPictureController.php b/src/applications/phame/controller/blog/PhameBlogHeaderPictureController.php index fbda0ab1ef..ab026fecbf 100644 --- a/src/applications/phame/controller/blog/PhameBlogHeaderPictureController.php +++ b/src/applications/phame/controller/blog/PhameBlogHeaderPictureController.php @@ -1,126 +1,139 @@ getViewer(); $id = $request->getURIData('id'); $blog = id(new PhameBlogQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->needHeaderImage(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$blog) { return new Aphront404Response(); } $blog_uri = '/phame/blog/manage/'.$id; $supported_formats = PhabricatorFile::getTransformableImageFormats(); $e_file = true; $errors = array(); $delete_header = ($request->getInt('delete') == 1); if ($request->isFormPost()) { if ($request->getFileExists('header')) { $file = PhabricatorFile::newFromPHPUpload( $_FILES['header'], array( 'authorPHID' => $viewer->getPHID(), 'canCDN' => true, )); } else if (!$delete_header) { $e_file = pht('Required'); $errors[] = pht( 'You must choose a file when uploading a new blog header.'); } if (!$errors && !$delete_header) { if (!$file->isTransformableImage()) { $e_file = pht('Not Supported'); $errors[] = pht( 'This server only supports these image formats: %s.', implode(', ', $supported_formats)); } } if (!$errors) { if ($delete_header) { - $blog->setHeaderImagePHID(null); + $new_value = null; } else { - $blog->setHeaderImagePHID($file->getPHID()); $file->attachToObject($blog->getPHID()); + $new_value = $file->getPHID(); } - $blog->save(); + + $xactions = array(); + $xactions[] = id(new PhameBlogTransaction()) + ->setTransactionType(PhameBlogTransaction::TYPE_HEADERIMAGE) + ->setNewValue($new_value); + + $editor = id(new PhameBlogEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true); + + $editor->applyTransactions($blog, $xactions); + return id(new AphrontRedirectResponse())->setURI($blog_uri); } } $title = pht('Edit Blog Header'); $upload_form = id(new AphrontFormView()) ->setUser($viewer) ->setEncType('multipart/form-data') ->appendChild( id(new AphrontFormFileControl()) ->setName('header') ->setLabel(pht('Upload Header')) ->setError($e_file) ->setCaption( pht('Supported formats: %s', implode(', ', $supported_formats)))) ->appendChild( id(new AphrontFormCheckboxControl()) ->setName('delete') ->setLabel(pht('Delete Header')) ->addCheckbox( 'delete', 1, null, null)) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($blog_uri) ->setValue(pht('Upload Header'))); $upload_box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Upload New Header')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setForm($upload_form); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb( pht('Blogs'), $this->getApplicationURI('blog/')); $crumbs->addTextCrumb( $blog->getName(), $this->getApplicationURI('blog/view/'.$id)); $crumbs->addTextCrumb(pht('Blog Header')); $crumbs->setBorder(true); $header = id(new PHUIHeaderView()) ->setHeader(pht('Edit Blog Header')) ->setHeaderIcon('fa-camera'); $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setFooter(array( $upload_box, )); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->appendChild( array( $view, )); } } diff --git a/src/applications/phame/controller/blog/PhameBlogProfilePictureController.php b/src/applications/phame/controller/blog/PhameBlogProfilePictureController.php index 96d59c8ad4..3368046414 100644 --- a/src/applications/phame/controller/blog/PhameBlogProfilePictureController.php +++ b/src/applications/phame/controller/blog/PhameBlogProfilePictureController.php @@ -1,227 +1,240 @@ getViewer(); $id = $request->getURIData('id'); $blog = id(new PhameBlogQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->needProfileImage(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$blog) { return new Aphront404Response(); } $blog_uri = '/phame/blog/manage/'.$id; $supported_formats = PhabricatorFile::getTransformableImageFormats(); $e_file = true; $errors = array(); if ($request->isFormPost()) { $phid = $request->getStr('phid'); $is_default = false; if ($phid == PhabricatorPHIDConstants::PHID_VOID) { $phid = null; $is_default = true; } else if ($phid) { $file = id(new PhabricatorFileQuery()) ->setViewer($viewer) ->withPHIDs(array($phid)) ->executeOne(); } else { if ($request->getFileExists('picture')) { $file = PhabricatorFile::newFromPHPUpload( $_FILES['picture'], array( 'authorPHID' => $viewer->getPHID(), 'canCDN' => true, )); } else { $e_file = pht('Required'); $errors[] = pht( 'You must choose a file when uploading a new blog picture.'); } } if (!$errors && !$is_default) { if (!$file->isTransformableImage()) { $e_file = pht('Not Supported'); $errors[] = pht( 'This server only supports these image formats: %s.', implode(', ', $supported_formats)); } else { $xform = PhabricatorFileTransform::getTransformByKey( PhabricatorFileThumbnailTransform::TRANSFORM_PROFILE); $xformed = $xform->executeTransform($file); } } if (!$errors) { if ($is_default) { - $blog->setProfileImagePHID(null); + $new_value = null; } else { - $blog->setProfileImagePHID($xformed->getPHID()); $xformed->attachToObject($blog->getPHID()); + $new_value = $xformed->getPHID(); } - $blog->save(); + + $xactions = array(); + $xactions[] = id(new PhameBlogTransaction()) + ->setTransactionType(PhameBlogTransaction::TYPE_PROFILEIMAGE) + ->setNewValue($new_value); + + $editor = id(new PhameBlogEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true); + + $editor->applyTransactions($blog, $xactions); + return id(new AphrontRedirectResponse())->setURI($blog_uri); } } $title = pht('Edit Blog Picture'); $form = id(new PHUIFormLayoutView()) ->setUser($viewer); $default_image = PhabricatorFile::loadBuiltin($viewer, 'blog.png'); $images = array(); $current = $blog->getProfileImagePHID(); $has_current = false; if ($current) { $files = id(new PhabricatorFileQuery()) ->setViewer($viewer) ->withPHIDs(array($current)) ->execute(); if ($files) { $file = head($files); if ($file->isTransformableImage()) { $has_current = true; $images[$current] = array( 'uri' => $file->getBestURI(), 'tip' => pht('Current Picture'), ); } } } $images[PhabricatorPHIDConstants::PHID_VOID] = array( 'uri' => $default_image->getBestURI(), 'tip' => pht('Default Picture'), ); require_celerity_resource('people-profile-css'); Javelin::initBehavior('phabricator-tooltips', array()); $buttons = array(); foreach ($images as $phid => $spec) { $button = javelin_tag( 'button', array( 'class' => 'grey profile-image-button', 'sigil' => 'has-tooltip', 'meta' => array( 'tip' => $spec['tip'], 'size' => 300, ), ), phutil_tag( 'img', array( 'height' => 50, 'width' => 50, 'src' => $spec['uri'], ))); $button = array( phutil_tag( 'input', array( 'type' => 'hidden', 'name' => 'phid', 'value' => $phid, )), $button, ); $button = phabricator_form( $viewer, array( 'class' => 'profile-image-form', 'method' => 'POST', ), $button); $buttons[] = $button; } if ($has_current) { $form->appendChild( id(new AphrontFormMarkupControl()) ->setLabel(pht('Current Picture')) ->setValue(array_shift($buttons))); } $form->appendChild( id(new AphrontFormMarkupControl()) ->setLabel(pht('Use Picture')) ->setValue($buttons)); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText($title) ->setFormErrors($errors) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setForm($form); $upload_form = id(new AphrontFormView()) ->setUser($viewer) ->setEncType('multipart/form-data') ->appendChild( id(new AphrontFormFileControl()) ->setName('picture') ->setLabel(pht('Upload Picture')) ->setError($e_file) ->setCaption( pht('Supported formats: %s', implode(', ', $supported_formats)))) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($blog_uri) ->setValue(pht('Upload Picture'))); $upload_box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Upload New Picture')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setForm($upload_form); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb( pht('Blogs'), $this->getApplicationURI('blog/')); $crumbs->addTextCrumb( $blog->getName(), $this->getApplicationURI('blog/view/'.$id)); $crumbs->addTextCrumb(pht('Blog Picture')); $crumbs->setBorder(true); $header = id(new PHUIHeaderView()) ->setHeader(pht('Edit Blog Picture')) ->setHeaderIcon('fa-camera'); $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setFooter(array( $form_box, $upload_box, )); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->appendChild( array( $view, )); } } diff --git a/src/applications/phame/editor/PhameBlogEditor.php b/src/applications/phame/editor/PhameBlogEditor.php index 197387985b..d075a750ea 100644 --- a/src/applications/phame/editor/PhameBlogEditor.php +++ b/src/applications/phame/editor/PhameBlogEditor.php @@ -1,298 +1,312 @@ getTransactionType()) { case PhameBlogTransaction::TYPE_NAME: return $object->getName(); case PhameBlogTransaction::TYPE_SUBTITLE: return $object->getSubtitle(); case PhameBlogTransaction::TYPE_DESCRIPTION: return $object->getDescription(); case PhameBlogTransaction::TYPE_FULLDOMAIN: return $object->getDomainFullURI(); case PhameBlogTransaction::TYPE_PARENTSITE: return $object->getParentSite(); case PhameBlogTransaction::TYPE_PARENTDOMAIN: return $object->getParentDomain(); + case PhameBlogTransaction::TYPE_PROFILEIMAGE: + return $object->getProfileImagePHID(); + case PhameBlogTransaction::TYPE_HEADERIMAGE: + return $object->getHeaderImagePHID(); case PhameBlogTransaction::TYPE_STATUS: return $object->getStatus(); } } protected function getCustomTransactionNewValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhameBlogTransaction::TYPE_NAME: case PhameBlogTransaction::TYPE_SUBTITLE: case PhameBlogTransaction::TYPE_DESCRIPTION: case PhameBlogTransaction::TYPE_STATUS: case PhameBlogTransaction::TYPE_PARENTSITE: - case PhameBlogTransaction::TYPE_PARENTDOMAIN: + case PhameBlogTransaction::TYPE_PROFILEIMAGE: + case PhameBlogTransaction::TYPE_HEADERIMAGE: return $xaction->getNewValue(); case PhameBlogTransaction::TYPE_FULLDOMAIN: $domain = $xaction->getNewValue(); if (!strlen($xaction->getNewValue())) { return null; } return $domain; } } protected function applyCustomInternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhameBlogTransaction::TYPE_NAME: return $object->setName($xaction->getNewValue()); case PhameBlogTransaction::TYPE_SUBTITLE: return $object->setSubtitle($xaction->getNewValue()); case PhameBlogTransaction::TYPE_DESCRIPTION: return $object->setDescription($xaction->getNewValue()); case PhameBlogTransaction::TYPE_FULLDOMAIN: $new_value = $xaction->getNewValue(); if (strlen($new_value)) { $uri = new PhutilURI($new_value); $domain = $uri->getDomain(); $object->setDomain($domain); } else { $object->setDomain(null); } $object->setDomainFullURI($new_value); return; + case PhameBlogTransaction::TYPE_PROFILEIMAGE: + return $object->setProfileImagePHID($xaction->getNewValue()); + case PhameBlogTransaction::TYPE_HEADERIMAGE: + return $object->setHeaderImagePHID($xaction->getNewValue()); case PhameBlogTransaction::TYPE_STATUS: return $object->setStatus($xaction->getNewValue()); case PhameBlogTransaction::TYPE_PARENTSITE: return $object->setParentSite($xaction->getNewValue()); case PhameBlogTransaction::TYPE_PARENTDOMAIN: return $object->setParentDomain($xaction->getNewValue()); } return parent::applyCustomInternalTransaction($object, $xaction); } protected function applyCustomExternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhameBlogTransaction::TYPE_NAME: case PhameBlogTransaction::TYPE_SUBTITLE: case PhameBlogTransaction::TYPE_DESCRIPTION: case PhameBlogTransaction::TYPE_FULLDOMAIN: case PhameBlogTransaction::TYPE_PARENTSITE: case PhameBlogTransaction::TYPE_PARENTDOMAIN: + case PhameBlogTransaction::TYPE_HEADERIMAGE: + case PhameBlogTransaction::TYPE_PROFILEIMAGE: case PhameBlogTransaction::TYPE_STATUS: 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_PARENTDOMAIN: if (!$xactions) { continue; } $parent_domain = last($xactions)->getNewValue(); if (empty($parent_domain)) { continue; } try { PhabricatorEnv::requireValidRemoteURIForLink($parent_domain); } catch (Exception $ex) { $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Invalid URI'), pht('Parent Domain must be set to a valid Remote URI.'), nonempty(last($xactions), null)); $errors[] = $error; } break; case PhameBlogTransaction::TYPE_FULLDOMAIN: if (!$xactions) { continue; } $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; } $domain = new PhutilURI($custom_domain); $domain = $domain->getDomain(); $duplicate_blog = id(new PhameBlogQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withDomain($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 true; } protected function shouldPublishFeedStory( PhabricatorLiskDAO $object, array $xactions) { return true; } protected function getMailTo(PhabricatorLiskDAO $object) { $phids = array(); $phids[] = $this->requireActor()->getPHID(); $phids[] = $object->getCreatorPHID(); return $phids; } protected function buildMailTemplate(PhabricatorLiskDAO $object) { $phid = $object->getPHID(); $name = $object->getName(); return id(new PhabricatorMetaMTAMail()) ->setSubject($name) ->addHeader('Thread-Topic', $phid); } protected function buildReplyHandler(PhabricatorLiskDAO $object) { return id(new PhameBlogReplyHandler()) ->setMailReceiver($object); } protected function buildMailBody( PhabricatorLiskDAO $object, array $xactions) { $body = parent::buildMailBody($object, $xactions); $body->addLinkSection( pht('BLOG DETAIL'), PhabricatorEnv::getProductionURI($object->getViewURI())); return $body; } public function getMailTagsMap() { return array( PhameBlogTransaction::MAILTAG_DETAILS => pht("A blog's details change."), PhameBlogTransaction::MAILTAG_SUBSCRIBERS => pht("A blog's subscribers change."), PhameBlogTransaction::MAILTAG_OTHER => pht('Other blog activity not listed above occurs.'), ); } protected function getMailSubjectPrefix() { return '[Phame]'; } protected function supportsSearch() { return true; } protected function shouldApplyHeraldRules( PhabricatorLiskDAO $object, array $xactions) { return true; } protected function buildHeraldAdapter( PhabricatorLiskDAO $object, array $xactions) { return id(new HeraldPhameBlogAdapter()) ->setBlog($object); } } diff --git a/src/applications/phame/storage/PhameBlogTransaction.php b/src/applications/phame/storage/PhameBlogTransaction.php index 2d74ca5cc6..f08c7be688 100644 --- a/src/applications/phame/storage/PhameBlogTransaction.php +++ b/src/applications/phame/storage/PhameBlogTransaction.php @@ -1,295 +1,367 @@ getOldValue(); switch ($this->getTransactionType()) { case self::TYPE_DESCRIPTION: if ($old === null) { return true; } } return parent::shouldHide(); } + public function getRequiredHandlePHIDs() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $req_phids = array(); + switch ($this->getTransactionType()) { + case self::TYPE_PROFILEIMAGE: + case self::TYPE_HEADERIMAGE: + $req_phids[] = $old; + $req_phids[] = $new; + break; + } + + return array_merge($req_phids, parent::getRequiredHandlePHIDs()); + } + public function getIcon() { $old = $this->getOldValue(); $new = $this->getNewValue(); 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_FULLDOMAIN: return 'fa-pencil'; + case self::TYPE_HEADERIMAGE: + return 'fa-image'; + case self::TYPE_PROFILEIMAGE: + return 'fa-star'; case self::TYPE_STATUS: if ($new == PhameBlog::STATUS_ARCHIVED) { return 'fa-ban'; } else { return 'fa-check'; } break; } return parent::getIcon(); } public function getColor() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_STATUS: if ($new == PhameBlog::STATUS_ARCHIVED) { return 'violet'; } else { return 'green'; } } return parent::getColor(); } public function getMailTags() { $tags = parent::getMailTags(); switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_SUBSCRIBERS: $tags[] = self::MAILTAG_SUBSCRIBERS; break; case self::TYPE_NAME: case self::TYPE_SUBTITLE: case self::TYPE_DESCRIPTION: case self::TYPE_FULLDOMAIN: case self::TYPE_PARENTSITE: case self::TYPE_PARENTDOMAIN: + case self::TYPE_PROFILEIMAGE: + case self::TYPE_HEADERIMAGE: $tags[] = self::MAILTAG_DETAILS; break; default: $tags[] = self::MAILTAG_OTHER; break; } return $tags; } public function getTitle() { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $type = $this->getTransactionType(); switch ($type) { case PhabricatorTransactions::TYPE_CREATE: return pht( '%s created this blog.', $this->renderHandleLink($author_phid)); 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_SUBTITLE: if ($old === null) { return pht( '%s set this blog\'s subtitle to "%s".', $this->renderHandleLink($author_phid), $new); } else { return pht( '%s updated the blog\'s subtitle 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_FULLDOMAIN: return pht( '%s updated the blog\'s full domain to "%s".', $this->renderHandleLink($author_phid), $new); break; case self::TYPE_PARENTSITE: if ($old === null) { return pht( '%s set this blog\'s parent site to "%s".', $this->renderHandleLink($author_phid), $new); } else { return pht( '%s updated the blog\'s parent site to "%s".', $this->renderHandleLink($author_phid), $new); } break; case self::TYPE_PARENTDOMAIN: if ($old === null) { return pht( '%s set this blog\'s parent domain to "%s".', $this->renderHandleLink($author_phid), $new); } else { return pht( '%s updated the blog\'s parent domain to "%s".', $this->renderHandleLink($author_phid), $new); } break; + case self::TYPE_HEADERIMAGE: + if (!$old) { + return pht( + "%s set this blog's header image to %s.", + $this->renderHandleLink($author_phid), + $this->renderHandleLink($new)); + } else if (!$new) { + return pht( + "%s removed this blog's header image.", + $this->renderHandleLink($author_phid)); + } else { + return pht( + "%s updated this blog's header image from %s to %s.", + $this->renderHandleLink($author_phid), + $this->renderHandleLink($old), + $this->renderHandleLink($new)); + } + break; + case self::TYPE_PROFILEIMAGE: + if (!$old) { + return pht( + "%s set this blog's profile image to %s.", + $this->renderHandleLink($author_phid), + $this->renderHandleLink($new)); + } else if (!$new) { + return pht( + "%s removed this blog's profile image.", + $this->renderHandleLink($author_phid)); + } else { + return pht( + "%s updated this blog's profile image from %s to %s.", + $this->renderHandleLink($author_phid), + $this->renderHandleLink($old), + $this->renderHandleLink($new)); + } + break; case self::TYPE_STATUS: switch ($new) { case PhameBlog::STATUS_ACTIVE: return pht( '%s published this blog.', $this->renderHandleLink($author_phid)); case PhameBlog::STATUS_ARCHIVED: return pht( '%s archived this blog.', $this->renderHandleLink($author_phid)); } } 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_SUBTITLE: if ($old === null) { return pht( '%s set the subtitle for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else { return pht( '%s updated the subtitle 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_FULLDOMAIN: return pht( '%s updated the full domain for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case self::TYPE_PARENTSITE: return pht( '%s updated the parent site for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case self::TYPE_PARENTDOMAIN: return pht( '%s updated the parent domain for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; + case self::TYPE_HEADERIMAGE: + return pht( + '%s updated the header image for %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + break; + case self::TYPE_PROFILEIMAGE: + return pht( + '%s updated the profile image for %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + break; case self::TYPE_STATUS: switch ($new) { case PhameBlog::STATUS_ACTIVE: return pht( '%s published the blog %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); case PhameBlog::STATUS_ARCHIVED: return pht( '%s archived the blog %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } break; } return parent::getTitleForFeed(); } 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); } }