Page MenuHomePhabricator

D14587.diff
No OneTemporary

D14587.diff

diff --git a/resources/builtin/blog.png b/resources/builtin/blog.png
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/resources/sql/autopatches/20151128.phame.blog.picture.1.sql b/resources/sql/autopatches/20151128.phame.blog.picture.1.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20151128.phame.blog.picture.1.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {$NAMESPACE}_phame.phame_blog
+ ADD profileImagePHID VARBINARY(64);
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
@@ -3285,6 +3285,7 @@
'PhameBlogFeedController' => 'applications/phame/controller/blog/PhameBlogFeedController.php',
'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php',
'PhameBlogLiveController' => 'applications/phame/controller/blog/PhameBlogLiveController.php',
+ 'PhameBlogProfilePictureController' => 'applications/phame/controller/blog/PhameBlogProfilePictureController.php',
'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php',
'PhameBlogReplyHandler' => 'applications/phame/mail/PhameBlogReplyHandler.php',
'PhameBlogSearchEngine' => 'applications/phame/query/PhameBlogSearchEngine.php',
@@ -7592,6 +7593,7 @@
'PhameBlogFeedController' => 'PhameBlogController',
'PhameBlogListController' => 'PhameBlogController',
'PhameBlogLiveController' => 'PhameBlogController',
+ 'PhameBlogProfilePictureController' => 'PhameBlogController',
'PhameBlogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhameBlogReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
'PhameBlogSearchEngine' => 'PhabricatorApplicationSearchEngine',
diff --git a/src/applications/phame/application/PhabricatorPhameApplication.php b/src/applications/phame/application/PhabricatorPhameApplication.php
--- a/src/applications/phame/application/PhabricatorPhameApplication.php
+++ b/src/applications/phame/application/PhabricatorPhameApplication.php
@@ -63,6 +63,7 @@
'view/(?P<id>[^/]+)/' => 'PhameBlogViewController',
'feed/(?P<id>[^/]+)/' => 'PhameBlogFeedController',
'new/' => 'PhameBlogEditController',
+ 'picture/(?P<id>[1-9]\d*)/' => 'PhameBlogProfilePictureController',
),
) + $this->getResourceSubroutes(),
);
diff --git a/src/applications/phame/controller/blog/PhameBlogProfilePictureController.php b/src/applications/phame/controller/blog/PhameBlogProfilePictureController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phame/controller/blog/PhameBlogProfilePictureController.php
@@ -0,0 +1,218 @@
+<?php
+
+final class PhameBlogProfilePictureController
+ extends PhameBlogController {
+
+ public function shouldRequireAdmin() {
+ return false;
+ }
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->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/view/'.$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);
+ } else {
+ $blog->setProfileImagePHID($xformed->getPHID());
+ $xformed->attachToObject($blog->getPHID());
+ }
+ $blog->save();
+ 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)
+ ->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'))
+ ->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'));
+
+ return $this->newPage()
+ ->setTitle($title)
+ ->setCrumbs($crumbs)
+ ->appendChild(
+ array(
+ $form_box,
+ $upload_box,
+ ));
+
+ }
+}
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
@@ -9,6 +9,7 @@
$blog = id(new PhameBlogQuery())
->setViewer($viewer)
->withIDs(array($id))
+ ->needProfileImage(true)
->executeOne();
if (!$blog) {
return new Aphront404Response();
@@ -32,10 +33,13 @@
$header_color = 'bluegrey';
}
+ $picture = $blog->getProfileImageURI();
+
$header = id(new PHUIHeaderView())
->setHeader($blog->getName())
->setUser($viewer)
->setPolicyObject($blog)
+ ->setImage($picture)
->setStatus($header_icon, $header_color, $header_name);
$actions = $this->renderActions($blog, $viewer);
@@ -169,6 +173,14 @@
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
+ $actions->addAction(
+ id(new PhabricatorActionView())
+ ->setIcon('fa-picture-o')
+ ->setHref($this->getApplicationURI('blog/picture/'.$blog->getID().'/'))
+ ->setName(pht('Edit Blog Picture'))
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit));
+
if ($blog->isArchived()) {
$actions->addAction(
id(new PhabricatorActionView())
diff --git a/src/applications/phame/query/PhameBlogQuery.php b/src/applications/phame/query/PhameBlogQuery.php
--- a/src/applications/phame/query/PhameBlogQuery.php
+++ b/src/applications/phame/query/PhameBlogQuery.php
@@ -6,7 +6,9 @@
private $phids;
private $domain;
private $statuses;
+
private $needBloggers;
+ private $needProfileImage;
public function withIDs(array $ids) {
$this->ids = $ids;
@@ -28,6 +30,11 @@
return $this;
}
+ public function needProfileImage($need) {
+ $this->needProfileImage = $need;
+ return $this;
+ }
+
public function newResultObject() {
return new PhameBlog();
}
@@ -70,6 +77,39 @@
return $where;
}
+ protected function didFilterPage(array $blogs) {
+ if ($this->needProfileImage) {
+ $default = null;
+
+ $file_phids = mpull($blogs, 'getProfileImagePHID');
+ $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->getProfileImagePHID());
+ if (!$file) {
+ if (!$default) {
+ $default = PhabricatorFile::loadBuiltin(
+ $this->getViewer(),
+ 'blog.png');
+ }
+ $file = $default;
+ }
+ $blog->attachProfileImageFile($file);
+ }
+ }
+ return $blogs;
+ }
+
public function getQueryApplicationClass() {
// TODO: Can we set this without breaking public blogs?
return null;
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
@@ -11,7 +11,6 @@
PhabricatorApplicationTransactionInterface {
const MARKUP_FIELD_DESCRIPTION = 'markup:description';
-
const SKIN_DEFAULT = 'oblivious';
protected $name;
@@ -23,7 +22,9 @@
protected $editPolicy;
protected $status;
protected $mailKey;
+ protected $profileImagePHID;
+ private $profileImageFile = self::ATTACHABLE;
private static $requestBlog;
const STATUS_ACTIVE = 'active';
@@ -41,6 +42,7 @@
'domain' => 'text128?',
'status' => 'text32',
'mailKey' => 'bytes20',
+ 'profileImagePHID' => 'phid?',
// T6203/NULLABILITY
// These policies should always be non-null.
@@ -243,6 +245,19 @@
return PhabricatorEnv::getProductionURI($uri);
}
+ public function getProfileImageURI() {
+ return $this->getProfileImageFile()->getBestURI();
+ }
+
+ public function attachProfileImageFile(PhabricatorFile $file) {
+ $this->profileImageFile = $file;
+ return $this;
+ }
+
+ public function getProfileImageFile() {
+ return $this->assertAttached($this->profileImageFile);
+ }
+
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */

File Metadata

Mime Type
text/plain
Expires
Mon, Nov 11, 8:43 AM (1 w, 1 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6712131
Default Alt Text
D14587.diff (13 KB)

Event Timeline