Add ability to set a header image per Phame blog
Summary: This is the backend half of uploading an image as a header for Phame Blogs. Allows you to upload image, or delete it. Ref T10901
Test Plan:
Go to Manage Blog, visit Edit Header Image, Upload snarky file. See snarky file on Manage page. Edit Header Image, click delete, save, see file goes away.
{F1690966}
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: Korvin
Maniphest Tasks: T10901
Differential Revision: https://secure.phabricator.com/D16140
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
return array(
|
return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'core.pkg.css' => '6913fe66',
|
'core.pkg.css' => 'c7fc5aec',
|
||||||
'core.pkg.js' => '10275c16',
|
'core.pkg.js' => '10275c16',
|
||||||
'darkconsole.pkg.js' => 'e7393ebb',
|
'darkconsole.pkg.js' => 'e7393ebb',
|
||||||
'differential.pkg.css' => 'b3eea3f5',
|
'differential.pkg.css' => 'b3eea3f5',
|
||||||
@@ -155,7 +155,7 @@ return array(
|
|||||||
'rsrc/css/phui/phui-spacing.css' => '042804d6',
|
'rsrc/css/phui/phui-spacing.css' => '042804d6',
|
||||||
'rsrc/css/phui/phui-status.css' => 'd5263e49',
|
'rsrc/css/phui/phui-status.css' => 'd5263e49',
|
||||||
'rsrc/css/phui/phui-tag-view.css' => '6bbd83e2',
|
'rsrc/css/phui/phui-tag-view.css' => '6bbd83e2',
|
||||||
'rsrc/css/phui/phui-timeline-view.css' => '6e342216',
|
'rsrc/css/phui/phui-timeline-view.css' => '8ea41b25',
|
||||||
'rsrc/css/phui/phui-two-column-view.css' => '9fb86c85',
|
'rsrc/css/phui/phui-two-column-view.css' => '9fb86c85',
|
||||||
'rsrc/css/phui/workboards/phui-workboard-color.css' => 'ac6fe6a7',
|
'rsrc/css/phui/workboards/phui-workboard-color.css' => 'ac6fe6a7',
|
||||||
'rsrc/css/phui/workboards/phui-workboard.css' => 'e6d89647',
|
'rsrc/css/phui/workboards/phui-workboard.css' => 'e6d89647',
|
||||||
@@ -860,7 +860,7 @@ return array(
|
|||||||
'phui-status-list-view-css' => 'd5263e49',
|
'phui-status-list-view-css' => 'd5263e49',
|
||||||
'phui-tag-view-css' => '6bbd83e2',
|
'phui-tag-view-css' => '6bbd83e2',
|
||||||
'phui-theme-css' => '027ba77e',
|
'phui-theme-css' => '027ba77e',
|
||||||
'phui-timeline-view-css' => '6e342216',
|
'phui-timeline-view-css' => '8ea41b25',
|
||||||
'phui-two-column-view-css' => '9fb86c85',
|
'phui-two-column-view-css' => '9fb86c85',
|
||||||
'phui-workboard-color-css' => 'ac6fe6a7',
|
'phui-workboard-color-css' => 'ac6fe6a7',
|
||||||
'phui-workboard-view-css' => 'e6d89647',
|
'phui-workboard-view-css' => 'e6d89647',
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_phame.phame_blog
|
||||||
|
ADD headerImagePHID VARBINARY(64);
|
||||||
@@ -3777,6 +3777,7 @@ phutil_register_library_map(array(
|
|||||||
'PhameBlogEditor' => 'applications/phame/editor/PhameBlogEditor.php',
|
'PhameBlogEditor' => 'applications/phame/editor/PhameBlogEditor.php',
|
||||||
'PhameBlogFeedController' => 'applications/phame/controller/blog/PhameBlogFeedController.php',
|
'PhameBlogFeedController' => 'applications/phame/controller/blog/PhameBlogFeedController.php',
|
||||||
'PhameBlogFulltextEngine' => 'applications/phame/search/PhameBlogFulltextEngine.php',
|
'PhameBlogFulltextEngine' => 'applications/phame/search/PhameBlogFulltextEngine.php',
|
||||||
|
'PhameBlogHeaderPictureController' => 'applications/phame/controller/blog/PhameBlogHeaderPictureController.php',
|
||||||
'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php',
|
'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php',
|
||||||
'PhameBlogListView' => 'applications/phame/view/PhameBlogListView.php',
|
'PhameBlogListView' => 'applications/phame/view/PhameBlogListView.php',
|
||||||
'PhameBlogManageController' => 'applications/phame/controller/blog/PhameBlogManageController.php',
|
'PhameBlogManageController' => 'applications/phame/controller/blog/PhameBlogManageController.php',
|
||||||
@@ -8655,6 +8656,7 @@ phutil_register_library_map(array(
|
|||||||
'PhameBlogEditor' => 'PhabricatorApplicationTransactionEditor',
|
'PhameBlogEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
'PhameBlogFeedController' => 'PhameBlogController',
|
'PhameBlogFeedController' => 'PhameBlogController',
|
||||||
'PhameBlogFulltextEngine' => 'PhabricatorFulltextEngine',
|
'PhameBlogFulltextEngine' => 'PhabricatorFulltextEngine',
|
||||||
|
'PhameBlogHeaderPictureController' => 'PhameBlogController',
|
||||||
'PhameBlogListController' => 'PhameBlogController',
|
'PhameBlogListController' => 'PhameBlogController',
|
||||||
'PhameBlogListView' => 'AphrontTagView',
|
'PhameBlogListView' => 'AphrontTagView',
|
||||||
'PhameBlogManageController' => 'PhameBlogController',
|
'PhameBlogManageController' => 'PhameBlogController',
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ final class PhabricatorPhameApplication extends PhabricatorApplication {
|
|||||||
'manage/(?P<id>[^/]+)/' => 'PhameBlogManageController',
|
'manage/(?P<id>[^/]+)/' => 'PhameBlogManageController',
|
||||||
'feed/(?P<id>[^/]+)/' => 'PhameBlogFeedController',
|
'feed/(?P<id>[^/]+)/' => 'PhameBlogFeedController',
|
||||||
'picture/(?P<id>[1-9]\d*)/' => 'PhameBlogProfilePictureController',
|
'picture/(?P<id>[1-9]\d*)/' => 'PhameBlogProfilePictureController',
|
||||||
|
'header/(?P<id>[1-9]\d*)/' => 'PhameBlogHeaderPictureController',
|
||||||
),
|
),
|
||||||
) + $this->getResourceSubroutes(),
|
) + $this->getResourceSubroutes(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhameBlogHeaderPictureController
|
||||||
|
extends PhameBlogController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $request->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);
|
||||||
|
} else {
|
||||||
|
$blog->setHeaderImagePHID($file->getPHID());
|
||||||
|
$file->attachToObject($blog->getPHID());
|
||||||
|
}
|
||||||
|
$blog->save();
|
||||||
|
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,
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ final class PhameBlogManageController extends PhameBlogController {
|
|||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withIDs(array($id))
|
->withIDs(array($id))
|
||||||
->needProfileImage(true)
|
->needProfileImage(true)
|
||||||
|
->needHeaderImage(true)
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if (!$blog) {
|
if (!$blog) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
@@ -40,6 +41,7 @@ final class PhameBlogManageController extends PhameBlogController {
|
|||||||
|
|
||||||
$curtain = $this->buildCurtain($blog);
|
$curtain = $this->buildCurtain($blog);
|
||||||
$properties = $this->buildPropertyView($blog);
|
$properties = $this->buildPropertyView($blog);
|
||||||
|
$file = $this->buildFileView($blog);
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
$crumbs->addTextCrumb(
|
$crumbs->addTextCrumb(
|
||||||
@@ -62,6 +64,7 @@ final class PhameBlogManageController extends PhameBlogController {
|
|||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->setCurtain($curtain)
|
->setCurtain($curtain)
|
||||||
->addPropertySection(pht('Details'), $properties)
|
->addPropertySection(pht('Details'), $properties)
|
||||||
|
->addPropertySection(pht('Header'), $file)
|
||||||
->setMainColumn(
|
->setMainColumn(
|
||||||
array(
|
array(
|
||||||
$timeline,
|
$timeline,
|
||||||
@@ -157,6 +160,14 @@ final class PhameBlogManageController extends PhameBlogController {
|
|||||||
->setDisabled(!$can_edit)
|
->setDisabled(!$can_edit)
|
||||||
->setWorkflow(!$can_edit));
|
->setWorkflow(!$can_edit));
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setIcon('fa-camera')
|
||||||
|
->setHref($this->getApplicationURI('blog/header/'.$blog->getID().'/'))
|
||||||
|
->setName(pht('Edit Blog Header'))
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(!$can_edit));
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setIcon('fa-picture-o')
|
->setIcon('fa-picture-o')
|
||||||
@@ -188,4 +199,24 @@ final class PhameBlogManageController extends PhameBlogController {
|
|||||||
return $curtain;
|
return $curtain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildFileView(
|
||||||
|
PhameBlog $blog) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$view = id(new PHUIPropertyListView())
|
||||||
|
->setUser($viewer);
|
||||||
|
|
||||||
|
if ($blog->getHeaderImagePHID()) {
|
||||||
|
$view->addImageContent(
|
||||||
|
phutil_tag(
|
||||||
|
'img',
|
||||||
|
array(
|
||||||
|
'src' => $blog->getHeaderImageURI(),
|
||||||
|
'class' => 'phabricator-image-macro-hero',
|
||||||
|
)));
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,6 @@
|
|||||||
final class PhameBlogProfilePictureController
|
final class PhameBlogProfilePictureController
|
||||||
extends PhameBlogController {
|
extends PhameBlogController {
|
||||||
|
|
||||||
public function shouldRequireAdmin() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$viewer = $request->getViewer();
|
$viewer = $request->getViewer();
|
||||||
$id = $request->getURIData('id');
|
$id = $request->getURIData('id');
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ final class PhameBlogQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||||||
|
|
||||||
private $needBloggers;
|
private $needBloggers;
|
||||||
private $needProfileImage;
|
private $needProfileImage;
|
||||||
|
private $needHeaderImage;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
@@ -35,6 +36,11 @@ final class PhameBlogQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function needHeaderImage($need) {
|
||||||
|
$this->needHeaderImage = $need;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function newResultObject() {
|
public function newResultObject() {
|
||||||
return new PhameBlog();
|
return new PhameBlog();
|
||||||
}
|
}
|
||||||
@@ -107,6 +113,28 @@ final class PhameBlogQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||||||
$blog->attachProfileImageFile($file);
|
$blog->attachProfileImageFile($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->needHeaderImage) {
|
||||||
|
$file_phids = mpull($blogs, '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 ($blogs as $blog) {
|
||||||
|
$file = idx($files, $blog->getHeaderImagePHID());
|
||||||
|
if ($file) {
|
||||||
|
$blog->attachHeaderImageFile($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return $blogs;
|
return $blogs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,10 @@ final class PhameBlog extends PhameDAO
|
|||||||
protected $status;
|
protected $status;
|
||||||
protected $mailKey;
|
protected $mailKey;
|
||||||
protected $profileImagePHID;
|
protected $profileImagePHID;
|
||||||
|
protected $headerImagePHID;
|
||||||
|
|
||||||
private $profileImageFile = self::ATTACHABLE;
|
private $profileImageFile = self::ATTACHABLE;
|
||||||
|
private $headerImageFile = self::ATTACHABLE;
|
||||||
|
|
||||||
const STATUS_ACTIVE = 'active';
|
const STATUS_ACTIVE = 'active';
|
||||||
const STATUS_ARCHIVED = 'archived';
|
const STATUS_ARCHIVED = 'archived';
|
||||||
@@ -43,6 +45,7 @@ final class PhameBlog extends PhameDAO
|
|||||||
'status' => 'text32',
|
'status' => 'text32',
|
||||||
'mailKey' => 'bytes20',
|
'mailKey' => 'bytes20',
|
||||||
'profileImagePHID' => 'phid?',
|
'profileImagePHID' => 'phid?',
|
||||||
|
'headerImagePHID' => 'phid?',
|
||||||
|
|
||||||
// T6203/NULLABILITY
|
// T6203/NULLABILITY
|
||||||
// These policies should always be non-null.
|
// These policies should always be non-null.
|
||||||
@@ -212,6 +215,19 @@ final class PhameBlog extends PhameDAO
|
|||||||
return $this->assertAttached($this->profileImageFile);
|
return $this->assertAttached($this->profileImageFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 )-------------------------- */
|
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
height: 9px;
|
height: 9px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
margin-left: 76px;
|
margin-left: 76px;
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.device-desktop .phui-timeline-wedge {
|
.device-desktop .phui-timeline-wedge {
|
||||||
|
|||||||
Reference in New Issue
Block a user