mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-18 11:30:55 +01:00
Add Hero Image to Phame Post
Summary: Adds a headerimage and lets you set it on posts for added reverence. Is that a word? Test Plan: Add an image, see an image. {F1923010} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D16873
This commit is contained in:
parent
c7f2e4a924
commit
ce0cb115ca
10 changed files with 249 additions and 1 deletions
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_phame.phame_post
|
||||
ADD headerImagePHID VARBINARY(64);
|
|
@ -4085,6 +4085,7 @@ phutil_register_library_map(array(
|
|||
'PhamePostEditEngine' => 'applications/phame/editor/PhamePostEditEngine.php',
|
||||
'PhamePostEditor' => 'applications/phame/editor/PhamePostEditor.php',
|
||||
'PhamePostFulltextEngine' => 'applications/phame/search/PhamePostFulltextEngine.php',
|
||||
'PhamePostHeaderPictureController' => 'applications/phame/controller/post/PhamePostHeaderPictureController.php',
|
||||
'PhamePostHistoryController' => 'applications/phame/controller/post/PhamePostHistoryController.php',
|
||||
'PhamePostListController' => 'applications/phame/controller/post/PhamePostListController.php',
|
||||
'PhamePostListView' => 'applications/phame/view/PhamePostListView.php',
|
||||
|
@ -9324,6 +9325,7 @@ phutil_register_library_map(array(
|
|||
'PhamePostEditEngine' => 'PhabricatorEditEngine',
|
||||
'PhamePostEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhamePostFulltextEngine' => 'PhabricatorFulltextEngine',
|
||||
'PhamePostHeaderPictureController' => 'PhamePostController',
|
||||
'PhamePostHistoryController' => 'PhamePostController',
|
||||
'PhamePostListController' => 'PhamePostController',
|
||||
'PhamePostListView' => 'AphrontTagView',
|
||||
|
|
|
@ -53,6 +53,7 @@ final class PhabricatorPhameApplication extends PhabricatorApplication {
|
|||
'preview/' => 'PhabricatorMarkupPreviewController',
|
||||
'move/(?P<id>\d+)/' => 'PhamePostMoveController',
|
||||
'archive/(?P<id>\d+)/' => 'PhamePostArchiveController',
|
||||
'header/(?P<id>[1-9]\d*)/' => 'PhamePostHeaderPictureController',
|
||||
),
|
||||
'blog/' => array(
|
||||
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhameBlogListController',
|
||||
|
|
|
@ -90,6 +90,7 @@ abstract class PhameLiveController extends PhameController {
|
|||
if (strlen($post_id)) {
|
||||
$post_query = id(new PhamePostQuery())
|
||||
->setViewer($viewer)
|
||||
->needHeaderImage(true)
|
||||
->withIDs(array($post_id));
|
||||
|
||||
if ($blog) {
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
final class PhamePostHeaderPictureController
|
||||
extends PhamePostController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
$id = $request->getURIData('id');
|
||||
|
||||
$post = id(new PhamePostQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->needHeaderImage(true)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$post) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$post_uri = '/phame/post/view/'.$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 post 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) {
|
||||
$new_value = null;
|
||||
} else {
|
||||
$file->attachToObject($post->getPHID());
|
||||
$new_value = $file->getPHID();
|
||||
}
|
||||
|
||||
$xactions = array();
|
||||
$xactions[] = id(new PhamePostTransaction())
|
||||
->setTransactionType(PhamePostTransaction::TYPE_HEADERIMAGE)
|
||||
->setNewValue($new_value);
|
||||
|
||||
$editor = id(new PhamePostEditor())
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContinueOnNoEffect(true);
|
||||
|
||||
$editor->applyTransactions($post, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($post_uri);
|
||||
}
|
||||
}
|
||||
|
||||
$title = pht('Edit Post 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($post_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(
|
||||
$post->getTitle(),
|
||||
$this->getApplicationURI('post/view/'.$id));
|
||||
$crumbs->addTextCrumb(pht('Post Header'));
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Edit Post Header'))
|
||||
->setHeaderIcon('fa-camera');
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$upload_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild(
|
||||
array(
|
||||
$view,
|
||||
));
|
||||
|
||||
}
|
||||
}
|
|
@ -19,9 +19,11 @@ final class PhamePostViewController
|
|||
$is_external = $this->getIsExternal();
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($post->getTitle())
|
||||
->addClass('phame-header-bar')
|
||||
->setUser($viewer);
|
||||
|
||||
$hero = $this->buildPhamePostHeader($post);
|
||||
|
||||
if (!$is_external) {
|
||||
$actions = $this->renderActions($post);
|
||||
$header->setPolicyObject($post);
|
||||
|
@ -167,6 +169,7 @@ final class PhamePostViewController
|
|||
->setCrumbs($crumbs)
|
||||
->appendChild(
|
||||
array(
|
||||
$hero,
|
||||
$document,
|
||||
$about,
|
||||
$properties,
|
||||
|
@ -204,6 +207,13 @@ final class PhamePostViewController
|
|||
->setName(pht('Edit Post'))
|
||||
->setDisabled(!$can_edit));
|
||||
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-camera-retro')
|
||||
->setHref($this->getApplicationURI('post/header/'.$id.'/'))
|
||||
->setName(pht('Edit Header Image'))
|
||||
->setDisabled(!$can_edit));
|
||||
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-arrows')
|
||||
|
@ -307,4 +317,33 @@ final class PhamePostViewController
|
|||
return array(head($prev), head($next));
|
||||
}
|
||||
|
||||
private function buildPhamePostHeader(
|
||||
PhamePost $post) {
|
||||
|
||||
$image = null;
|
||||
if ($post->getHeaderImagePHID()) {
|
||||
$image = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'phame-header-hero',
|
||||
),
|
||||
phutil_tag(
|
||||
'img',
|
||||
array(
|
||||
'src' => $post->getHeaderImageURI(),
|
||||
'class' => 'phame-header-image',
|
||||
)));
|
||||
}
|
||||
|
||||
$title = phutil_tag_div('phame-header-title', $post->getTitle());
|
||||
$subtitle = null;
|
||||
if ($post->getSubtitle()) {
|
||||
$subtitle = phutil_tag_div('phame-header-subtitle', $post->getSubtitle());
|
||||
}
|
||||
|
||||
return phutil_tag_div(
|
||||
'phame-mega-header', array($image, $title, $subtitle));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ final class PhamePostEditor
|
|||
$types[] = PhamePostTransaction::TYPE_SUBTITLE;
|
||||
$types[] = PhamePostTransaction::TYPE_BODY;
|
||||
$types[] = PhamePostTransaction::TYPE_VISIBILITY;
|
||||
$types[] = PhamePostTransaction::TYPE_HEADERIMAGE;
|
||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||
|
||||
return $types;
|
||||
|
@ -39,6 +40,8 @@ final class PhamePostEditor
|
|||
return $object->getBody();
|
||||
case PhamePostTransaction::TYPE_VISIBILITY:
|
||||
return $object->getVisibility();
|
||||
case PhamePostTransaction::TYPE_HEADERIMAGE:
|
||||
return $object->getHeaderImagePHID();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,6 +54,7 @@ final class PhamePostEditor
|
|||
case PhamePostTransaction::TYPE_SUBTITLE:
|
||||
case PhamePostTransaction::TYPE_BODY:
|
||||
case PhamePostTransaction::TYPE_VISIBILITY:
|
||||
case PhamePostTransaction::TYPE_HEADERIMAGE:
|
||||
case PhamePostTransaction::TYPE_BLOG:
|
||||
return $xaction->getNewValue();
|
||||
}
|
||||
|
@ -69,6 +73,8 @@ final class PhamePostEditor
|
|||
return $object->setBody($xaction->getNewValue());
|
||||
case PhamePostTransaction::TYPE_BLOG:
|
||||
return $object->setBlogPHID($xaction->getNewValue());
|
||||
case PhamePostTransaction::TYPE_HEADERIMAGE:
|
||||
return $object->setHeaderImagePHID($xaction->getNewValue());
|
||||
case PhamePostTransaction::TYPE_VISIBILITY:
|
||||
if ($xaction->getNewValue() == PhameConstants::VISIBILITY_DRAFT) {
|
||||
$object->setDatePublished(0);
|
||||
|
@ -93,6 +99,7 @@ final class PhamePostEditor
|
|||
case PhamePostTransaction::TYPE_SUBTITLE:
|
||||
case PhamePostTransaction::TYPE_BODY:
|
||||
case PhamePostTransaction::TYPE_VISIBILITY:
|
||||
case PhamePostTransaction::TYPE_HEADERIMAGE:
|
||||
case PhamePostTransaction::TYPE_BLOG:
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ final class PhamePostQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
private $publishedAfter;
|
||||
private $phids;
|
||||
|
||||
private $needHeaderImage;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
return $this;
|
||||
|
@ -39,6 +41,11 @@ final class PhamePostQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function needHeaderImage($need) {
|
||||
$this->needHeaderImage = $need;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new PhamePost();
|
||||
}
|
||||
|
@ -71,6 +78,28 @@ final class PhamePostQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
$post->attachBlog($blog);
|
||||
}
|
||||
|
||||
if ($this->needHeaderImage) {
|
||||
$file_phids = mpull($posts, 'getHeaderImagePHID');
|
||||
$file_phids = array_filter($file_phids);
|
||||
if ($file_phids) {
|
||||
$files = id(new PhabricatorFileQuery())
|
||||
->setParentQuery($this)
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($file_phids)
|
||||
->execute();
|
||||
$files = mpull($files, null, 'getPHID');
|
||||
} else {
|
||||
$files = array();
|
||||
}
|
||||
|
||||
foreach ($posts as $post) {
|
||||
$file = idx($files, $post->getHeaderImagePHID());
|
||||
if ($file) {
|
||||
$post->attachHeaderImageFile($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $posts;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,10 @@ final class PhamePost extends PhameDAO
|
|||
protected $datePublished;
|
||||
protected $blogPHID;
|
||||
protected $mailKey;
|
||||
protected $headerImagePHID;
|
||||
|
||||
private $blog = self::ATTACHABLE;
|
||||
private $headerImageFile = self::ATTACHABLE;
|
||||
|
||||
public static function initializePost(
|
||||
PhabricatorUser $blogger,
|
||||
|
@ -127,6 +129,7 @@ final class PhamePost extends PhameDAO
|
|||
'phameTitle' => 'sort64?',
|
||||
'visibility' => 'uint32',
|
||||
'mailKey' => 'bytes20',
|
||||
'headerImagePHID' => 'phid?',
|
||||
|
||||
// T6203/NULLABILITY
|
||||
// These seem like they should always be non-null?
|
||||
|
@ -172,6 +175,19 @@ final class PhamePost extends PhameDAO
|
|||
return PhabricatorSlug::normalizeProjectSlug($this->getTitle(), true);
|
||||
}
|
||||
|
||||
public function getHeaderImageURI() {
|
||||
return $this->getHeaderImageFile()->getBestURI();
|
||||
}
|
||||
|
||||
public function attachHeaderImageFile(PhabricatorFile $file) {
|
||||
$this->headerImageFile = $file;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHeaderImageFile() {
|
||||
return $this->assertAttached($this->headerImageFile);
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ final class PhamePostTransaction
|
|||
const TYPE_SUBTITLE = 'phame.post.subtitle';
|
||||
const TYPE_BODY = 'phame.post.body';
|
||||
const TYPE_VISIBILITY = 'phame.post.visibility';
|
||||
const TYPE_HEADERIMAGE = 'phame.post.headerimage';
|
||||
const TYPE_BLOG = 'phame.post.blog';
|
||||
|
||||
const MAILTAG_CONTENT = 'phame-post-content';
|
||||
|
@ -71,6 +72,9 @@ final class PhamePostTransaction
|
|||
case PhabricatorTransactions::TYPE_CREATE:
|
||||
return 'fa-plus';
|
||||
break;
|
||||
case self::TYPE_HEADERIMAGE:
|
||||
return 'fa-camera-retro';
|
||||
break;
|
||||
case self::TYPE_VISIBILITY:
|
||||
if ($new == PhameConstants::VISIBILITY_PUBLISHED) {
|
||||
return 'fa-globe';
|
||||
|
@ -156,6 +160,11 @@ final class PhamePostTransaction
|
|||
'%s updated the blog post.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
break;
|
||||
case self::TYPE_HEADERIMAGE:
|
||||
return pht(
|
||||
'%s updated the header image.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
break;
|
||||
case self::TYPE_VISIBILITY:
|
||||
if ($new == PhameConstants::VISIBILITY_DRAFT) {
|
||||
return pht(
|
||||
|
@ -222,6 +231,12 @@ final class PhamePostTransaction
|
|||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
break;
|
||||
case self::TYPE_HEADERIMAGE:
|
||||
return pht(
|
||||
'%s updated the header image for post %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
break;
|
||||
case self::TYPE_VISIBILITY:
|
||||
if ($new == PhameConstants::VISIBILITY_DRAFT) {
|
||||
return pht(
|
||||
|
|
Loading…
Reference in a new issue