diff --git a/resources/sql/autopatches/20151111.phame.blog.archive.1.sql b/resources/sql/autopatches/20151111.phame.blog.archive.1.sql new file mode 100644 index 0000000000..c7e5898e66 --- /dev/null +++ b/resources/sql/autopatches/20151111.phame.blog.archive.1.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_phame.phame_blog + ADD status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20151111.phame.blog.archive.2.sql b/resources/sql/autopatches/20151111.phame.blog.archive.2.sql new file mode 100644 index 0000000000..ee9ad1e4c7 --- /dev/null +++ b/resources/sql/autopatches/20151111.phame.blog.archive.2.sql @@ -0,0 +1,2 @@ +UPDATE {$NAMESPACE}_phame.phame_blog + SET status = 'active' WHERE status = ''; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 73a0fd7393..87c661c4a5 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3271,9 +3271,9 @@ phutil_register_library_map(array( 'PhameBasicBlogSkin' => 'applications/phame/skins/PhameBasicBlogSkin.php', 'PhameBasicTemplateBlogSkin' => 'applications/phame/skins/PhameBasicTemplateBlogSkin.php', 'PhameBlog' => 'applications/phame/storage/PhameBlog.php', + 'PhameBlogArchiveController' => 'applications/phame/controller/blog/PhameBlogArchiveController.php', 'PhameBlogController' => 'applications/phame/controller/blog/PhameBlogController.php', 'PhameBlogCreateCapability' => 'applications/phame/capability/PhameBlogCreateCapability.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', @@ -7573,9 +7573,9 @@ phutil_register_library_map(array( 'PhabricatorProjectInterface', 'PhabricatorApplicationTransactionInterface', ), + 'PhameBlogArchiveController' => 'PhameBlogController', 'PhameBlogController' => 'PhameController', 'PhameBlogCreateCapability' => 'PhabricatorPolicyCapability', - 'PhameBlogDeleteController' => 'PhameBlogController', 'PhameBlogEditController' => 'PhameBlogController', 'PhameBlogEditor' => 'PhabricatorApplicationTransactionEditor', 'PhameBlogFeedController' => 'PhameBlogController', diff --git a/src/applications/phame/application/PhabricatorPhameApplication.php b/src/applications/phame/application/PhabricatorPhameApplication.php index 1a3d3f90f4..456a58c9eb 100644 --- a/src/applications/phame/application/PhabricatorPhameApplication.php +++ b/src/applications/phame/application/PhabricatorPhameApplication.php @@ -59,7 +59,7 @@ final class PhabricatorPhameApplication extends PhabricatorApplication { 'blog/' => array( '(?:(?Puser|all)/)?' => 'PhameBlogListController', '(?:query/(?P[^/]+)/)?' => 'PhameBlogListController', - 'delete/(?P[^/]+)/' => 'PhameBlogDeleteController', + 'archive/(?P[^/]+)/' => 'PhameBlogArchiveController', 'edit/(?P[^/]+)/' => 'PhameBlogEditController', 'view/(?P[^/]+)/' => 'PhameBlogViewController', 'feed/(?P[^/]+)/' => 'PhameBlogFeedController', diff --git a/src/applications/phame/controller/blog/PhameBlogArchiveController.php b/src/applications/phame/controller/blog/PhameBlogArchiveController.php new file mode 100644 index 0000000000..dd69f3154a --- /dev/null +++ b/src/applications/phame/controller/blog/PhameBlogArchiveController.php @@ -0,0 +1,68 @@ +getViewer(); + $id = $request->getURIData('id'); + + $blog = id(new PhameBlogQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$blog) { + return new Aphront404Response(); + } + + $view_uri = $this->getApplicationURI('blog/view/'.$blog->getID().'/'); + + if ($request->isFormPost()) { + if ($blog->isArchived()) { + $new_status = PhameBlog::STATUS_ACTIVE; + } else { + $new_status = PhameBlog::STATUS_ARCHIVED; + } + + $xactions = array(); + + $xactions[] = id(new PhameBlogTransaction()) + ->setTransactionType(PhameBlogTransaction::TYPE_STATUS) + ->setNewValue($new_status); + + id(new PhameBlogEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true) + ->applyTransactions($blog, $xactions); + + return id(new AphrontRedirectResponse())->setURI($view_uri); + } + + if ($blog->isArchived()) { + $title = pht('Activate Blog'); + $body = pht('This blog will become active again.'); + $button = pht('Activate Blog'); + } else { + $title = pht('Archive Blog'); + $body = pht('This blog will be marked as archived.'); + $button = pht('Archive Blog'); + } + + $dialog = id(new AphrontDialogView()) + ->setUser($viewer) + ->setTitle($title) + ->appendChild($body) + ->addCancelButton($view_uri) + ->addSubmitButton($button); + + return id(new AphrontDialogResponse())->setDialog($dialog); + } + +} diff --git a/src/applications/phame/controller/blog/PhameBlogDeleteController.php b/src/applications/phame/controller/blog/PhameBlogDeleteController.php deleted file mode 100644 index c60e27b2d7..0000000000 --- a/src/applications/phame/controller/blog/PhameBlogDeleteController.php +++ /dev/null @@ -1,42 +0,0 @@ -getViewer(); - $id = $request->getURIData('id'); - - $blog = id(new PhameBlogQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$blog) { - return new Aphront404Response(); - } - - if ($request->isFormPost()) { - $blog->delete(); - return id(new AphrontRedirectResponse()) - ->setURI($this->getApplicationURI()); - } - - $cancel_uri = $this->getApplicationURI('/blog/view/'.$blog->getID().'/'); - - $dialog = id(new AphrontDialogView()) - ->setUser($viewer) - ->setTitle(pht('Delete Blog?')) - ->appendChild( - pht( - 'Really delete the blog "%s"? It will be gone forever.', - $blog->getName())) - ->addSubmitButton(pht('Delete')) - ->addCancelButton($cancel_uri); - - return id(new AphrontDialogResponse())->setDialog($dialog); - } - -} diff --git a/src/applications/phame/controller/blog/PhameBlogViewController.php b/src/applications/phame/controller/blog/PhameBlogViewController.php index 2f20702f6e..f74b838881 100644 --- a/src/applications/phame/controller/blog/PhameBlogViewController.php +++ b/src/applications/phame/controller/blog/PhameBlogViewController.php @@ -22,10 +22,21 @@ final class PhameBlogViewController extends PhameBlogController { ->withBlogPHIDs(array($blog->getPHID())) ->executeWithCursorPager($pager); + if ($blog->isArchived()) { + $header_icon = 'fa-ban'; + $header_name = pht('Archived'); + $header_color = 'dark'; + } else { + $header_icon = 'fa-check'; + $header_name = pht('Active'); + $header_color = 'bluegrey'; + } + $header = id(new PHUIHeaderView()) ->setHeader($blog->getName()) ->setUser($viewer) - ->setPolicyObject($blog); + ->setPolicyObject($blog) + ->setStatus($header_icon, $header_color, $header_name); $actions = $this->renderActions($blog, $viewer); $properties = $this->renderProperties($blog, $viewer, $actions); @@ -158,13 +169,25 @@ final class PhameBlogViewController extends PhameBlogController { ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); - $actions->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-times') - ->setHref($this->getApplicationURI('blog/delete/'.$blog->getID().'/')) - ->setName(pht('Delete Blog')) - ->setDisabled(!$can_edit) - ->setWorkflow(true)); + if ($blog->isArchived()) { + $actions->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Activate Blog')) + ->setIcon('fa-check') + ->setHref( + $this->getApplicationURI('blog/archive/'.$blog->getID().'/')) + ->setDisabled(!$can_edit) + ->setWorkflow(true)); + } else { + $actions->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Archive Blog')) + ->setIcon('fa-ban') + ->setHref( + $this->getApplicationURI('blog/archive/'.$blog->getID().'/')) + ->setDisabled(!$can_edit) + ->setWorkflow(true)); + } return $actions; } diff --git a/src/applications/phame/editor/PhameBlogEditor.php b/src/applications/phame/editor/PhameBlogEditor.php index 712c4ddd5b..3f23854125 100644 --- a/src/applications/phame/editor/PhameBlogEditor.php +++ b/src/applications/phame/editor/PhameBlogEditor.php @@ -18,6 +18,7 @@ final class PhameBlogEditor $types[] = PhameBlogTransaction::TYPE_DESCRIPTION; $types[] = PhameBlogTransaction::TYPE_DOMAIN; $types[] = PhameBlogTransaction::TYPE_SKIN; + $types[] = PhameBlogTransaction::TYPE_STATUS; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; @@ -37,6 +38,8 @@ final class PhameBlogEditor return $object->getDomain(); case PhameBlogTransaction::TYPE_SKIN: return $object->getSkin(); + case PhameBlogTransaction::TYPE_STATUS: + return $object->getStatus(); } } @@ -49,6 +52,7 @@ final class PhameBlogEditor case PhameBlogTransaction::TYPE_DESCRIPTION: case PhameBlogTransaction::TYPE_DOMAIN: case PhameBlogTransaction::TYPE_SKIN: + case PhameBlogTransaction::TYPE_STATUS: return $xaction->getNewValue(); } } @@ -66,6 +70,8 @@ final class PhameBlogEditor return $object->setDomain($xaction->getNewValue()); case PhameBlogTransaction::TYPE_SKIN: return $object->setSkin($xaction->getNewValue()); + case PhameBlogTransaction::TYPE_STATUS: + return $object->setStatus($xaction->getNewValue()); } return parent::applyCustomInternalTransaction($object, $xaction); @@ -80,6 +86,7 @@ final class PhameBlogEditor case PhameBlogTransaction::TYPE_DESCRIPTION: case PhameBlogTransaction::TYPE_DOMAIN: case PhameBlogTransaction::TYPE_SKIN: + case PhameBlogTransaction::TYPE_STATUS: return; } diff --git a/src/applications/phame/query/PhameBlogQuery.php b/src/applications/phame/query/PhameBlogQuery.php index ef441636b3..279ff91724 100644 --- a/src/applications/phame/query/PhameBlogQuery.php +++ b/src/applications/phame/query/PhameBlogQuery.php @@ -5,6 +5,7 @@ final class PhameBlogQuery extends PhabricatorCursorPagedPolicyAwareQuery { private $ids; private $phids; private $domain; + private $statuses; private $needBloggers; public function withIDs(array $ids) { @@ -22,6 +23,11 @@ final class PhameBlogQuery extends PhabricatorCursorPagedPolicyAwareQuery { return $this; } + public function withStatuses(array $status) { + $this->statuses = $status; + return $this; + } + public function newResultObject() { return new PhameBlog(); } @@ -33,6 +39,13 @@ final class PhameBlogQuery extends PhabricatorCursorPagedPolicyAwareQuery { protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); + if ($this->statuses !== null) { + $where[] = qsprintf( + $conn, + 'status IN (%Ls)', + $this->statuses); + } + if ($this->ids !== null) { $where[] = qsprintf( $conn, diff --git a/src/applications/phame/query/PhameBlogSearchEngine.php b/src/applications/phame/query/PhameBlogSearchEngine.php index 25a0ab515d..58dba3b810 100644 --- a/src/applications/phame/query/PhameBlogSearchEngine.php +++ b/src/applications/phame/query/PhameBlogSearchEngine.php @@ -17,11 +17,23 @@ final class PhameBlogSearchEngine protected function buildQueryFromParameters(array $map) { $query = $this->newQuery(); + if ($map['statuses']) { + $query->withStatuses(array($map['statuses'])); + } return $query; } protected function buildCustomSearchFields() { - return array(); + return array( + id(new PhabricatorSearchSelectField()) + ->setKey('statuses') + ->setLabel(pht('Status')) + ->setOptions(array( + '' => pht('All'), + PhameBlog::STATUS_ACTIVE => pht('Active'), + PhameBlog::STATUS_ARCHIVED => pht('Archived'), + )), + ); } protected function getURI($path) { @@ -30,6 +42,8 @@ final class PhameBlogSearchEngine protected function getBuiltinQueryNames() { $names = array( + 'active' => pht('Active Blogs'), + 'archived' => pht('Archived Blogs'), 'all' => pht('All Blogs'), ); return $names; @@ -42,6 +56,12 @@ final class PhameBlogSearchEngine switch ($query_key) { case 'all': return $query; + case 'active': + return $query->setParameter( + 'statuses', PhameBlog::STATUS_ACTIVE); + case 'archived': + return $query->setParameter( + 'statuses', PhameBlog::STATUS_ARCHIVED); } return parent::buildSavedQueryFromBuiltin($query_key); @@ -58,12 +78,19 @@ final class PhameBlogSearchEngine $list->setUser($viewer); foreach ($blogs as $blog) { + $archived = false; + $icon = 'fa-star'; + if ($blog->isArchived()) { + $archived = true; + $icon = 'fa-ban'; + } $id = $blog->getID(); $item = id(new PHUIObjectItemView()) ->setUser($viewer) ->setObject($blog) ->setHeader($blog->getName()) - ->setStatusIcon('fa-star') + ->setStatusIcon($icon) + ->setDisabled($archived) ->setHref($this->getApplicationURI("/blog/view/{$id}/")) ->addAttribute($blog->getSkin()) ->addAttribute($blog->getDomain()); diff --git a/src/applications/phame/storage/PhameBlog.php b/src/applications/phame/storage/PhameBlog.php index 3082592a93..43d865a058 100644 --- a/src/applications/phame/storage/PhameBlog.php +++ b/src/applications/phame/storage/PhameBlog.php @@ -20,10 +20,14 @@ final class PhameBlog extends PhameDAO protected $creatorPHID; protected $viewPolicy; protected $editPolicy; + protected $status; protected $mailKey; private static $requestBlog; + const STATUS_ACTIVE = 'active'; + const STATUS_ARCHIVED = 'archived'; + protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, @@ -34,6 +38,7 @@ final class PhameBlog extends PhameDAO 'name' => 'text64', 'description' => 'text', 'domain' => 'text128?', + 'status' => 'text32', 'mailKey' => 'bytes20', // T6203/NULLABILITY @@ -98,6 +103,17 @@ final class PhameBlog extends PhameDAO return $skin; } + public function isArchived() { + return ($this->getStatus() == self::STATUS_ARCHIVED); + } + + public static function getStatusNameMap() { + return array( + self::STATUS_ACTIVE => pht('Active'), + self::STATUS_ARCHIVED => pht('Archived'), + ); + } + /** * Makes sure a given custom blog uri is properly configured in DNS * to point at this Phabricator instance. If there is an error in diff --git a/src/applications/phame/storage/PhameBlogTransaction.php b/src/applications/phame/storage/PhameBlogTransaction.php index 0954e72a37..98622a80b1 100644 --- a/src/applications/phame/storage/PhameBlogTransaction.php +++ b/src/applications/phame/storage/PhameBlogTransaction.php @@ -7,6 +7,7 @@ final class PhameBlogTransaction const TYPE_DESCRIPTION = 'phame.blog.description'; const TYPE_DOMAIN = 'phame.blog.domain'; const TYPE_SKIN = 'phame.blog.skin'; + const TYPE_STATUS = 'phame.blog.status'; const MAILTAG_DETAILS = 'phame-blog-details'; const MAILTAG_SUBSCRIBERS = 'phame-blog-subscribers'; @@ -106,6 +107,18 @@ final class PhameBlogTransaction $this->renderHandleLink($author_phid), $new); break; + case self::TYPE_STATUS: + switch ($new) { + case self::STATUS_OPEN: + return pht( + '%s published this blog.', + $this->renderHandleLink($author_phid)); + case self::STATUS_CLOSED: + return pht( + '%s archived this blog.', + $this->renderHandleLink($author_phid)); + } + } return parent::getTitle(); @@ -151,6 +164,21 @@ final class PhameBlogTransaction $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; + case self::TYPE_STATUS: + switch ($new) { + case self::STATUS_OPEN: + return pht( + '%s published the blog %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + case self::STATUS_CLOSED: + return pht( + '%s archived the blog %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + } + break; + } return parent::getTitleForFeed();