1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 19:40:55 +01:00

Remove skins from Phame

Summary:
Ref T9897. Purge a bunch of stuff:

  - Remove skins.
  - Remove all custom sites for skin resources.
  - Remove "framed", "notlive", "preview", separate "live" controllers (see below).
  - Merge "publish" and "unpublish" controllers into one.

New behavior:

  - Blogs and posts have three views:
    - "View": Internal view URI, which is a normal detail page.
    - "Internal Live": Internal view URI which is a little prettier.
    - "External Live": External view URI for an external domain.

Right now, the differences are pretty minor (basically, different crumbs/chrome). This mostly gives us room to put some milder flavor of skins back later (photography or more "presentation" elements, for example).

This removes 9 million lines of code so I probably missed a couple of things, but I think it's like 95% of the way there.

Test Plan:
Here are some examples of what the "view", "internal" and "external" views look like for blogs (posts are similar):

"View": Unchanged

{F1021634}

"Internal": No chrome or footer. Still write actions (edit, post commments). Has crumbs to get back into Phame.

{F1021635}

"External": No chrome or footer. No write actions. No Phabricator crumbs. No policy/status information.

{F1021638}

I figure we'll probably tweak these a bit to figure out what makes sense (like: maybe no actions on "internal, live"? and "external, live" probably needs a way to set a root "Company >" crumb?) but that they're reasonable-ish as a first cut?

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9897

Differential Revision: https://secure.phabricator.com/D14740
This commit is contained in:
epriestley 2015-12-11 07:07:45 -08:00
parent c62e0a10f6
commit 8a906b0e18
35 changed files with 450 additions and 1731 deletions

View file

@ -1 +0,0 @@
<h2>404 Not Found</h2>

View file

@ -1,76 +0,0 @@
html, body, p, h1, h2, h3 {
padding: 0;
margin: 0;
font-weight: normal;
}
html {
font-family: "Helvetica Neue", "Arial", sans-serif;
font-size: 16px;
overflow-y: scroll;
color: #555555;
}
.oblivious-info {
position: fixed;
width: 15%;
border-right: 1px solid #dfdfdf;
top: 0;
bottom: 0;
left: 0;
padding: 140px 2% 0;
overflow: hidden;
background: url(/image/badge.png);
background-repeat: no-repeat;
background-position: 20px 20px;
}
.oblivious-content {
padding-top: 3%;
margin-left: 22%;
max-width: 800px;
}
a {
color: #2980b9;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
h1 {
font-size: 24px;
font-weight: normal;
}
h2 {
font-size: 22px;
font-weight: bold;
margin-bottom: 8px;
}
.phame-post {
margin: 0 0 2em;
}
.phame-post-title {
font-size: 28px;
}
.phame-post-date {
font-size: 12px;
margin: .25em 0 2em;
}
.oblivious-content .phabricator-remarkup ul.remarkup-list {
margin-left: 0;
}
.fb-comments,
.fb-comments span,
.fb-comments iframe[style] {
width: 100% !important;
}

View file

@ -1,3 +0,0 @@
</div>
</body>
</html>

View file

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title><?php echo _e($title); ?></title>
<?php echo $skin->getCSSResources(); ?>
</head>
<body>
<div class="oblivious-info">
<h1>
<a href="<?php echo _e($home_uri); ?>"><?php
echo _e($blog->getName());
?></a>
</h1>
<p><?php echo $skin->remarkup($blog->getDescription()); ?></p>
</div>
<div class="oblivious-content">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -1 +0,0 @@
<?php echo $post->render(); ?>

View file

@ -1,13 +0,0 @@
<div class="oblivious-post-list">
<?php
foreach ($posts as $post) {
echo $post->renderWithSummary();
}
?>
</div>
<div class="oblivious-pager">
<?php echo $older; ?>
<?php echo $newer; ?>
</div>

View file

@ -1,3 +0,0 @@
{
"name": "Oblivious"
}

View file

@ -2928,7 +2928,6 @@ phutil_register_library_map(array(
'PhabricatorRepositoryVCSPassword' => 'applications/repository/storage/PhabricatorRepositoryVCSPassword.php', 'PhabricatorRepositoryVCSPassword' => 'applications/repository/storage/PhabricatorRepositoryVCSPassword.php',
'PhabricatorRepositoryVersion' => 'applications/repository/constants/PhabricatorRepositoryVersion.php', 'PhabricatorRepositoryVersion' => 'applications/repository/constants/PhabricatorRepositoryVersion.php',
'PhabricatorRequestExceptionHandler' => 'aphront/handler/PhabricatorRequestExceptionHandler.php', 'PhabricatorRequestExceptionHandler' => 'aphront/handler/PhabricatorRequestExceptionHandler.php',
'PhabricatorResourceSite' => 'aphront/site/PhabricatorResourceSite.php',
'PhabricatorRobotsController' => 'applications/system/controller/PhabricatorRobotsController.php', 'PhabricatorRobotsController' => 'applications/system/controller/PhabricatorRobotsController.php',
'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php', 'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php',
'PhabricatorSMS' => 'infrastructure/sms/storage/PhabricatorSMS.php', 'PhabricatorSMS' => 'infrastructure/sms/storage/PhabricatorSMS.php',
@ -3308,8 +3307,6 @@ phutil_register_library_map(array(
'PhabricatorXHProfSample' => 'applications/xhprof/storage/PhabricatorXHProfSample.php', 'PhabricatorXHProfSample' => 'applications/xhprof/storage/PhabricatorXHProfSample.php',
'PhabricatorXHProfSampleListController' => 'applications/xhprof/controller/PhabricatorXHProfSampleListController.php', 'PhabricatorXHProfSampleListController' => 'applications/xhprof/controller/PhabricatorXHProfSampleListController.php',
'PhabricatorYoutubeRemarkupRule' => 'infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php', 'PhabricatorYoutubeRemarkupRule' => 'infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php',
'PhameBasicBlogSkin' => 'applications/phame/skins/PhameBasicBlogSkin.php',
'PhameBasicTemplateBlogSkin' => 'applications/phame/skins/PhameBasicTemplateBlogSkin.php',
'PhameBlog' => 'applications/phame/storage/PhameBlog.php', 'PhameBlog' => 'applications/phame/storage/PhameBlog.php',
'PhameBlogArchiveController' => 'applications/phame/controller/blog/PhameBlogArchiveController.php', 'PhameBlogArchiveController' => 'applications/phame/controller/blog/PhameBlogArchiveController.php',
'PhameBlogController' => 'applications/phame/controller/blog/PhameBlogController.php', 'PhameBlogController' => 'applications/phame/controller/blog/PhameBlogController.php',
@ -3318,18 +3315,15 @@ 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',
'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php', 'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php',
'PhameBlogLiveController' => 'applications/phame/controller/blog/PhameBlogLiveController.php',
'PhameBlogManageController' => 'applications/phame/controller/blog/PhameBlogManageController.php', 'PhameBlogManageController' => 'applications/phame/controller/blog/PhameBlogManageController.php',
'PhameBlogProfilePictureController' => 'applications/phame/controller/blog/PhameBlogProfilePictureController.php', 'PhameBlogProfilePictureController' => 'applications/phame/controller/blog/PhameBlogProfilePictureController.php',
'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php', 'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php',
'PhameBlogReplyHandler' => 'applications/phame/mail/PhameBlogReplyHandler.php', 'PhameBlogReplyHandler' => 'applications/phame/mail/PhameBlogReplyHandler.php',
'PhameBlogSearchEngine' => 'applications/phame/query/PhameBlogSearchEngine.php', 'PhameBlogSearchEngine' => 'applications/phame/query/PhameBlogSearchEngine.php',
'PhameBlogSite' => 'applications/phame/site/PhameBlogSite.php', 'PhameBlogSite' => 'applications/phame/site/PhameBlogSite.php',
'PhameBlogSkin' => 'applications/phame/skins/PhameBlogSkin.php',
'PhameBlogTransaction' => 'applications/phame/storage/PhameBlogTransaction.php', 'PhameBlogTransaction' => 'applications/phame/storage/PhameBlogTransaction.php',
'PhameBlogTransactionQuery' => 'applications/phame/query/PhameBlogTransactionQuery.php', 'PhameBlogTransactionQuery' => 'applications/phame/query/PhameBlogTransactionQuery.php',
'PhameBlogViewController' => 'applications/phame/controller/blog/PhameBlogViewController.php', 'PhameBlogViewController' => 'applications/phame/controller/blog/PhameBlogViewController.php',
'PhameCelerityResources' => 'applications/phame/celerity/PhameCelerityResources.php',
'PhameConduitAPIMethod' => 'applications/phame/conduit/PhameConduitAPIMethod.php', 'PhameConduitAPIMethod' => 'applications/phame/conduit/PhameConduitAPIMethod.php',
'PhameConstants' => 'applications/phame/constants/PhameConstants.php', 'PhameConstants' => 'applications/phame/constants/PhameConstants.php',
'PhameController' => 'applications/phame/controller/PhameController.php', 'PhameController' => 'applications/phame/controller/PhameController.php',
@ -3337,20 +3331,18 @@ phutil_register_library_map(array(
'PhameDAO' => 'applications/phame/storage/PhameDAO.php', 'PhameDAO' => 'applications/phame/storage/PhameDAO.php',
'PhameDescriptionView' => 'applications/phame/view/PhameDescriptionView.php', 'PhameDescriptionView' => 'applications/phame/view/PhameDescriptionView.php',
'PhameHomeController' => 'applications/phame/controller/PhameHomeController.php', 'PhameHomeController' => 'applications/phame/controller/PhameHomeController.php',
'PhameLiveController' => 'applications/phame/controller/PhameLiveController.php',
'PhamePost' => 'applications/phame/storage/PhamePost.php', 'PhamePost' => 'applications/phame/storage/PhamePost.php',
'PhamePostCommentController' => 'applications/phame/controller/post/PhamePostCommentController.php', 'PhamePostCommentController' => 'applications/phame/controller/post/PhamePostCommentController.php',
'PhamePostController' => 'applications/phame/controller/post/PhamePostController.php', 'PhamePostController' => 'applications/phame/controller/post/PhamePostController.php',
'PhamePostEditController' => 'applications/phame/controller/post/PhamePostEditController.php', 'PhamePostEditController' => 'applications/phame/controller/post/PhamePostEditController.php',
'PhamePostEditor' => 'applications/phame/editor/PhamePostEditor.php', 'PhamePostEditor' => 'applications/phame/editor/PhamePostEditor.php',
'PhamePostFramedController' => 'applications/phame/controller/post/PhamePostFramedController.php',
'PhamePostHistoryController' => 'applications/phame/controller/post/PhamePostHistoryController.php', 'PhamePostHistoryController' => 'applications/phame/controller/post/PhamePostHistoryController.php',
'PhamePostListController' => 'applications/phame/controller/post/PhamePostListController.php', 'PhamePostListController' => 'applications/phame/controller/post/PhamePostListController.php',
'PhamePostListView' => 'applications/phame/view/PhamePostListView.php', 'PhamePostListView' => 'applications/phame/view/PhamePostListView.php',
'PhamePostMailReceiver' => 'applications/phame/mail/PhamePostMailReceiver.php', 'PhamePostMailReceiver' => 'applications/phame/mail/PhamePostMailReceiver.php',
'PhamePostMoveController' => 'applications/phame/controller/post/PhamePostMoveController.php', 'PhamePostMoveController' => 'applications/phame/controller/post/PhamePostMoveController.php',
'PhamePostNewController' => 'applications/phame/controller/post/PhamePostNewController.php', 'PhamePostNewController' => 'applications/phame/controller/post/PhamePostNewController.php',
'PhamePostNotLiveController' => 'applications/phame/controller/post/PhamePostNotLiveController.php',
'PhamePostPreviewController' => 'applications/phame/controller/post/PhamePostPreviewController.php',
'PhamePostPublishController' => 'applications/phame/controller/post/PhamePostPublishController.php', 'PhamePostPublishController' => 'applications/phame/controller/post/PhamePostPublishController.php',
'PhamePostQuery' => 'applications/phame/query/PhamePostQuery.php', 'PhamePostQuery' => 'applications/phame/query/PhamePostQuery.php',
'PhamePostReplyHandler' => 'applications/phame/mail/PhamePostReplyHandler.php', 'PhamePostReplyHandler' => 'applications/phame/mail/PhamePostReplyHandler.php',
@ -3358,15 +3350,11 @@ phutil_register_library_map(array(
'PhamePostTransaction' => 'applications/phame/storage/PhamePostTransaction.php', 'PhamePostTransaction' => 'applications/phame/storage/PhamePostTransaction.php',
'PhamePostTransactionComment' => 'applications/phame/storage/PhamePostTransactionComment.php', 'PhamePostTransactionComment' => 'applications/phame/storage/PhamePostTransactionComment.php',
'PhamePostTransactionQuery' => 'applications/phame/query/PhamePostTransactionQuery.php', 'PhamePostTransactionQuery' => 'applications/phame/query/PhamePostTransactionQuery.php',
'PhamePostUnpublishController' => 'applications/phame/controller/post/PhamePostUnpublishController.php',
'PhamePostView' => 'applications/phame/view/PhamePostView.php',
'PhamePostViewController' => 'applications/phame/controller/post/PhamePostViewController.php', 'PhamePostViewController' => 'applications/phame/controller/post/PhamePostViewController.php',
'PhameQueryConduitAPIMethod' => 'applications/phame/conduit/PhameQueryConduitAPIMethod.php', 'PhameQueryConduitAPIMethod' => 'applications/phame/conduit/PhameQueryConduitAPIMethod.php',
'PhameQueryPostsConduitAPIMethod' => 'applications/phame/conduit/PhameQueryPostsConduitAPIMethod.php', 'PhameQueryPostsConduitAPIMethod' => 'applications/phame/conduit/PhameQueryPostsConduitAPIMethod.php',
'PhameResourceController' => 'applications/phame/controller/PhameResourceController.php',
'PhameSchemaSpec' => 'applications/phame/storage/PhameSchemaSpec.php', 'PhameSchemaSpec' => 'applications/phame/storage/PhameSchemaSpec.php',
'PhameSite' => 'applications/phame/site/PhameSite.php', 'PhameSite' => 'applications/phame/site/PhameSite.php',
'PhameSkinSpecification' => 'applications/phame/skins/PhameSkinSpecification.php',
'PhluxController' => 'applications/phlux/controller/PhluxController.php', 'PhluxController' => 'applications/phlux/controller/PhluxController.php',
'PhluxDAO' => 'applications/phlux/storage/PhluxDAO.php', 'PhluxDAO' => 'applications/phlux/storage/PhluxDAO.php',
'PhluxEditController' => 'applications/phlux/controller/PhluxEditController.php', 'PhluxEditController' => 'applications/phlux/controller/PhluxEditController.php',
@ -7222,7 +7210,6 @@ phutil_register_library_map(array(
'PhabricatorRepositoryVCSPassword' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryVCSPassword' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositoryVersion' => 'Phobject', 'PhabricatorRepositoryVersion' => 'Phobject',
'PhabricatorRequestExceptionHandler' => 'AphrontRequestExceptionHandler', 'PhabricatorRequestExceptionHandler' => 'AphrontRequestExceptionHandler',
'PhabricatorResourceSite' => 'PhabricatorSite',
'PhabricatorRobotsController' => 'PhabricatorController', 'PhabricatorRobotsController' => 'PhabricatorController',
'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorSMS' => 'PhabricatorSMSDAO', 'PhabricatorSMS' => 'PhabricatorSMSDAO',
@ -7650,8 +7637,6 @@ phutil_register_library_map(array(
'PhabricatorXHProfSample' => 'PhabricatorXHProfDAO', 'PhabricatorXHProfSample' => 'PhabricatorXHProfDAO',
'PhabricatorXHProfSampleListController' => 'PhabricatorXHProfController', 'PhabricatorXHProfSampleListController' => 'PhabricatorXHProfController',
'PhabricatorYoutubeRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorYoutubeRemarkupRule' => 'PhutilRemarkupRule',
'PhameBasicBlogSkin' => 'PhameBlogSkin',
'PhameBasicTemplateBlogSkin' => 'PhameBasicBlogSkin',
'PhameBlog' => array( 'PhameBlog' => array(
'PhameDAO', 'PhameDAO',
'PhabricatorPolicyInterface', 'PhabricatorPolicyInterface',
@ -7669,18 +7654,15 @@ phutil_register_library_map(array(
'PhameBlogEditor' => 'PhabricatorApplicationTransactionEditor', 'PhameBlogEditor' => 'PhabricatorApplicationTransactionEditor',
'PhameBlogFeedController' => 'PhameBlogController', 'PhameBlogFeedController' => 'PhameBlogController',
'PhameBlogListController' => 'PhameBlogController', 'PhameBlogListController' => 'PhameBlogController',
'PhameBlogLiveController' => 'PhameBlogController',
'PhameBlogManageController' => 'PhameBlogController', 'PhameBlogManageController' => 'PhameBlogController',
'PhameBlogProfilePictureController' => 'PhameBlogController', 'PhameBlogProfilePictureController' => 'PhameBlogController',
'PhameBlogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhameBlogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhameBlogReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhameBlogReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
'PhameBlogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhameBlogSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhameBlogSite' => 'PhameSite', 'PhameBlogSite' => 'PhameSite',
'PhameBlogSkin' => 'PhabricatorController',
'PhameBlogTransaction' => 'PhabricatorApplicationTransaction', 'PhameBlogTransaction' => 'PhabricatorApplicationTransaction',
'PhameBlogTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhameBlogTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhameBlogViewController' => 'PhameBlogController', 'PhameBlogViewController' => 'PhameLiveController',
'PhameCelerityResources' => 'CelerityResources',
'PhameConduitAPIMethod' => 'ConduitAPIMethod', 'PhameConduitAPIMethod' => 'ConduitAPIMethod',
'PhameConstants' => 'Phobject', 'PhameConstants' => 'Phobject',
'PhameController' => 'PhabricatorController', 'PhameController' => 'PhabricatorController',
@ -7688,6 +7670,7 @@ phutil_register_library_map(array(
'PhameDAO' => 'PhabricatorLiskDAO', 'PhameDAO' => 'PhabricatorLiskDAO',
'PhameDescriptionView' => 'AphrontTagView', 'PhameDescriptionView' => 'AphrontTagView',
'PhameHomeController' => 'PhamePostController', 'PhameHomeController' => 'PhamePostController',
'PhameLiveController' => 'PhameController',
'PhamePost' => array( 'PhamePost' => array(
'PhameDAO', 'PhameDAO',
'PhabricatorPolicyInterface', 'PhabricatorPolicyInterface',
@ -7703,15 +7686,12 @@ phutil_register_library_map(array(
'PhamePostController' => 'PhameController', 'PhamePostController' => 'PhameController',
'PhamePostEditController' => 'PhamePostController', 'PhamePostEditController' => 'PhamePostController',
'PhamePostEditor' => 'PhabricatorApplicationTransactionEditor', 'PhamePostEditor' => 'PhabricatorApplicationTransactionEditor',
'PhamePostFramedController' => 'PhamePostController',
'PhamePostHistoryController' => 'PhamePostController', 'PhamePostHistoryController' => 'PhamePostController',
'PhamePostListController' => 'PhamePostController', 'PhamePostListController' => 'PhamePostController',
'PhamePostListView' => 'AphrontTagView', 'PhamePostListView' => 'AphrontTagView',
'PhamePostMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhamePostMailReceiver' => 'PhabricatorObjectMailReceiver',
'PhamePostMoveController' => 'PhamePostController', 'PhamePostMoveController' => 'PhamePostController',
'PhamePostNewController' => 'PhamePostController', 'PhamePostNewController' => 'PhamePostController',
'PhamePostNotLiveController' => 'PhamePostController',
'PhamePostPreviewController' => 'PhamePostController',
'PhamePostPublishController' => 'PhamePostController', 'PhamePostPublishController' => 'PhamePostController',
'PhamePostQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhamePostQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhamePostReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhamePostReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
@ -7719,15 +7699,11 @@ phutil_register_library_map(array(
'PhamePostTransaction' => 'PhabricatorApplicationTransaction', 'PhamePostTransaction' => 'PhabricatorApplicationTransaction',
'PhamePostTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhamePostTransactionComment' => 'PhabricatorApplicationTransactionComment',
'PhamePostTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhamePostTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhamePostUnpublishController' => 'PhamePostController', 'PhamePostViewController' => 'PhameLiveController',
'PhamePostView' => 'AphrontView',
'PhamePostViewController' => 'PhamePostController',
'PhameQueryConduitAPIMethod' => 'PhameConduitAPIMethod', 'PhameQueryConduitAPIMethod' => 'PhameConduitAPIMethod',
'PhameQueryPostsConduitAPIMethod' => 'PhameConduitAPIMethod', 'PhameQueryPostsConduitAPIMethod' => 'PhameConduitAPIMethod',
'PhameResourceController' => 'CelerityResourceController',
'PhameSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhameSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhameSite' => 'PhabricatorSite', 'PhameSite' => 'PhabricatorSite',
'PhameSkinSpecification' => 'Phobject',
'PhluxController' => 'PhabricatorController', 'PhluxController' => 'PhabricatorController',
'PhluxDAO' => 'PhabricatorLiskDAO', 'PhluxDAO' => 'PhabricatorLiskDAO',
'PhluxEditController' => 'PhluxController', 'PhluxEditController' => 'PhluxController',

View file

@ -1,41 +0,0 @@
<?php
final class PhabricatorResourceSite extends PhabricatorSite {
public function getDescription() {
return pht('Serves static resources like images, CSS and JS.');
}
public function getPriority() {
return 2000;
}
public function newSiteForRequest(AphrontRequest $request) {
$host = $request->getHost();
$uri = PhabricatorEnv::getEnvConfig('security.alternate-file-domain');
if (!strlen($uri)) {
return null;
}
if ($this->isHostMatch($host, array($uri))) {
return new PhabricatorResourceSite();
}
return null;
}
public function getRoutingMaps() {
$applications = PhabricatorApplication::getAllInstalledApplications();
$maps = array();
foreach ($applications as $application) {
$maps[] = $this->newRoutingMap()
->setApplication($application)
->setRoutes($application->getResourceRoutes());
}
return $maps;
}
}

View file

@ -39,19 +39,19 @@ final class PhabricatorPhameApplication extends PhabricatorApplication {
return array( return array(
'/phame/' => array( '/phame/' => array(
'' => 'PhameHomeController', '' => 'PhameHomeController',
'live/(?P<id>[^/]+)/(?P<more>.*)' => 'PhameBlogLiveController',
// NOTE: The live routes include an initial "/", so leave it off
// this route.
'(?P<live>live)/(?P<blogID>[^/]+)' => $this->getLiveRoutes(),
'post/' => array( 'post/' => array(
'(?:(?P<filter>draft|all)/)?' => 'PhamePostListController',
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhamePostListController', '(?:query/(?P<queryKey>[^/]+)/)?' => 'PhamePostListController',
'blogger/(?P<bloggername>[\w\.-_]+)/' => 'PhamePostListController', 'blogger/(?P<bloggername>[\w\.-_]+)/' => 'PhamePostListController',
'edit/(?:(?P<id>[^/]+)/)?' => 'PhamePostEditController', 'edit/(?:(?P<id>[^/]+)/)?' => 'PhamePostEditController',
'history/(?P<id>\d+)/' => 'PhamePostHistoryController', 'history/(?P<id>\d+)/' => 'PhamePostHistoryController',
'view/(?P<id>\d+)/' => 'PhamePostViewController', 'view/(?P<id>\d+)/(?:(?P<slug>[^/]+)/)?' => 'PhamePostViewController',
'view/(?P<id>\d+)/(?P<slug>[^/]+)/' => 'PhamePostViewController', '(?P<action>publish|unpublish)/(?P<id>\d+)/'
'publish/(?P<id>\d+)/' => 'PhamePostPublishController', => 'PhamePostPublishController',
'preview/(?P<id>\d+)/' => 'PhamePostPreviewController', 'preview/(?P<id>\d+)/' => 'PhamePostPreviewController',
'unpublish/(?P<id>\d+)/' => 'PhamePostUnpublishController',
'notlive/(?P<id>\d+)/' => 'PhamePostNotLiveController',
'preview/' => 'PhabricatorMarkupPreviewController', 'preview/' => 'PhabricatorMarkupPreviewController',
'framed/(?P<id>\d+)/' => 'PhamePostFramedController', 'framed/(?P<id>\d+)/' => 'PhamePostFramedController',
'new/' => 'PhamePostNewController', 'new/' => 'PhamePostNewController',
@ -59,11 +59,10 @@ final class PhabricatorPhameApplication extends PhabricatorApplication {
'comment/(?P<id>[1-9]\d*)/' => 'PhamePostCommentController', 'comment/(?P<id>[1-9]\d*)/' => 'PhamePostCommentController',
), ),
'blog/' => array( 'blog/' => array(
'(?:(?P<filter>user|all)/)?' => 'PhameBlogListController',
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhameBlogListController', '(?:query/(?P<queryKey>[^/]+)/)?' => 'PhameBlogListController',
'archive/(?P<id>[^/]+)/' => 'PhameBlogArchiveController', 'archive/(?P<id>[^/]+)/' => 'PhameBlogArchiveController',
'edit/(?P<id>[^/]+)/' => 'PhameBlogEditController', 'edit/(?P<id>[^/]+)/' => 'PhameBlogEditController',
'view/(?P<id>[^/]+)/' => 'PhameBlogViewController', 'view/(?P<blogID>[^/]+)/' => 'PhameBlogViewController',
'manage/(?P<id>[^/]+)/' => 'PhameBlogManageController', 'manage/(?P<id>[^/]+)/' => 'PhameBlogManageController',
'feed/(?P<id>[^/]+)/' => 'PhameBlogFeedController', 'feed/(?P<id>[^/]+)/' => 'PhameBlogFeedController',
'new/' => 'PhameBlogEditController', 'new/' => 'PhameBlogEditController',
@ -87,16 +86,14 @@ final class PhabricatorPhameApplication extends PhabricatorApplication {
} }
public function getBlogRoutes() { public function getBlogRoutes() {
return array( return $this->getLiveRoutes();
'/(?P<more>.*)' => 'PhameBlogLiveController',
);
} }
public function getBlogCDNRoutes() { private function getLiveRoutes() {
return array( return array(
'/phame/' => array( '/' => array(
'r/(?P<id>\d+)/(?P<hash>[^/]+)/(?P<name>.*)' => '' => 'PhameBlogViewController',
'PhameResourceController', 'post/(?P<id>[^/]+)/(?:(?P<slug>[^/]+)/)?' => 'PhamePostViewController',
), ),
); );
} }

View file

@ -1,28 +0,0 @@
<?php
/**
* Defines Phabricator's static resources.
*/
final class PhameCelerityResources extends CelerityResources {
private $skin;
public function setSkin($skin) {
$this->skin = $skin;
return $this;
}
public function getSkin() {
return $this->skin;
}
public function getName() {
return 'phame:'.$this->getSkin()->getName();
}
public function getResourceData($name) {
$resource_path = $this->skin->getRootDirectory().DIRECTORY_SEPARATOR.$name;
return Filesystem::readFile($resource_path);
}
}

View file

@ -0,0 +1,182 @@
<?php
abstract class PhameLiveController extends PhameController {
private $isExternal;
private $isLive;
private $blog;
private $post;
public function shouldAllowPublic() {
return true;
}
protected function getIsExternal() {
return $this->isExternal;
}
protected function getIsLive() {
return $this->isLive;
}
protected function getBlog() {
return $this->blog;
}
protected function getPost() {
return $this->post;
}
protected function setupLiveEnvironment() {
$request = $this->getRequest();
$viewer = $this->getViewer();
$site = $request->getSite();
$blog_id = $request->getURIData('blogID');
$post_id = $request->getURIData('id');
if ($site instanceof PhameBlogSite) {
// This is a live page on a custom domain. We already looked up the blog
// in the Site handler by examining the domain, so we don't need to do
// more lookups.
$blog = $site->getBlog();
$is_external = true;
$is_live = true;
} else if ($blog_id) {
// This is a blog detail view, an internal blog live view, or an
// internal post live view The internal post detail view is handled
// below.
$is_external = false;
if ($request->getURIData('live')) {
$is_live = true;
} else {
$is_live = false;
}
$blog_query = id(new PhameBlogQuery())
->setViewer($viewer)
->needProfileImage(true)
->withIDs(array($blog_id));
// If this is a live view, only show active blogs.
if ($is_live) {
$blog_query->withStatuses(
array(
PhameBlog::STATUS_ACTIVE,
));
}
$blog = $blog_query->executeOne();
if (!$blog) {
return new Aphront404Response();
}
} else {
// This is a post detail page, so we'll figure out the blog by loading
// the post first.
$is_external = false;
$is_live = false;
$blog = null;
}
if ($post_id) {
$post_query = id(new PhamePostQuery())
->setViewer($viewer)
->withIDs(array($post_id));
if ($blog) {
$post_query->withBlogPHIDs(array($blog->getPHID()));
}
// Only show published posts on external domains.
if ($is_external) {
$post_query->withVisibility(PhameConstants::VISIBILITY_PUBLISHED);
}
$post = $post_query->executeOne();
if (!$post) {
return new Aphront404Response();
}
// If this is a post detail page, the URI didn't come with a blog ID,
// so fill that in.
if (!$blog) {
$blog = $post->getBlog();
}
} else {
$post = null;
}
$this->isExternal = $is_external;
$this->isLive = $is_live;
$this->blog = $blog;
$this->post = $post;
// If we have a post, canonicalize the URI to the post's current slug and
// redirect the user if it isn't correct.
if ($post) {
$slug = $request->getURIData('slug');
if ($post->getSlug() != $slug) {
if ($is_live) {
if ($is_external) {
$uri = $post->getExternalLiveURI();
} else {
$uri = $post->getInternalLiveURI();
}
} else {
$uri = $post->getViewURI();
}
return id(new AphrontRedirectResponse())->setURI($uri);
}
}
return null;
}
protected function buildApplicationCrumbs() {
$blog = $this->getBlog();
$post = $this->getPost();
$is_live = $this->getIsLive();
$is_external = $this->getIsExternal();
// If this is an external view, don't put the "Phame" crumb or the
// "Blogs" crumb into the crumbs list.
if ($is_external) {
$crumbs = new PHUICrumbsView();
} else {
$crumbs = parent::buildApplicationCrumbs();
$crumbs->addTextCrumb(
pht('Blogs'),
$this->getApplicationURI('blog/'));
}
$crumbs->setBorder(true);
if ($post) {
if ($is_live) {
if ($is_external) {
$blog_uri = $blog->getExternalLiveURI();
} else {
$blog_uri = $blog->getInternalLiveURI();
}
} else {
$blog_uri = $blog->getViewURI();
}
} else {
$blog_uri = null;
}
$crumbs->addTextCrumb($blog->getName(), $blog_uri);
if ($post) {
$crumbs->addTextCrumb($post->getTitle());
}
return $crumbs;
}
}

View file

@ -1,72 +0,0 @@
<?php
final class PhameResourceController extends CelerityResourceController {
private $id;
private $hash;
private $name;
private $root;
private $celerityResourceMap;
public function getCelerityResourceMap() {
return $this->celerityResourceMap;
}
public function willProcessRequest(array $data) {
$this->id = $data['id'];
$this->hash = $data['hash'];
$this->name = $data['name'];
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
// We require a visible blog associated with a given skin to serve
// resources, so you can't go fishing around where you shouldn't be.
// However, since these resources may be served off a CDN domain, we're
// bypassing the actual policy check. The blog needs to exist, but you
// don't necessarily need to be able to see it in order to see static
// resources on it.
$blog = id(new PhameBlogQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withIDs(array($this->id))
->executeOne();
if (!$blog) {
return new Aphront404Response();
}
$skin = $blog->getSkinRenderer($request);
$spec = $skin->getSpecification();
$resources = new PhameCelerityResources();
$resources->setSkin($spec);
$this->root = $spec->getRootDirectory();
$this->celerityResourceMap = new CelerityResourceMap($resources);
return $this->serveResource($this->name);
}
protected function buildResourceTransformer() {
$xformer = new CelerityResourceTransformer();
$xformer->setMinify(false);
$xformer->setTranslateURICallback(array($this, 'translateResourceURI'));
return $xformer;
}
public function translateResourceURI(array $matches) {
$uri = trim($matches[1], "'\" \r\t\n");
if (Filesystem::pathExists($this->root.$uri)) {
$hash = filemtime($this->root.$uri);
} else {
$hash = '-';
}
$uri = '/phame/r/'.$this->id.'/'.$hash.'/'.$uri;
return 'url('.$uri.')';
}
}

View file

@ -46,7 +46,6 @@ final class PhameBlogEditController
$name = $blog->getName(); $name = $blog->getName();
$description = $blog->getDescription(); $description = $blog->getDescription();
$custom_domain = $blog->getDomain(); $custom_domain = $blog->getDomain();
$skin = $blog->getSkin();
$can_view = $blog->getViewPolicy(); $can_view = $blog->getViewPolicy();
$can_edit = $blog->getEditPolicy(); $can_edit = $blog->getEditPolicy();
@ -58,7 +57,6 @@ final class PhameBlogEditController
$name = $request->getStr('name'); $name = $request->getStr('name');
$description = $request->getStr('description'); $description = $request->getStr('description');
$custom_domain = nonempty($request->getStr('custom_domain'), null); $custom_domain = nonempty($request->getStr('custom_domain'), null);
$skin = $request->getStr('skin');
$can_view = $request->getStr('can_view'); $can_view = $request->getStr('can_view');
$can_edit = $request->getStr('can_edit'); $can_edit = $request->getStr('can_edit');
$v_projects = $request->getArr('projects'); $v_projects = $request->getArr('projects');
@ -74,9 +72,6 @@ final class PhameBlogEditController
id(new PhameBlogTransaction()) id(new PhameBlogTransaction())
->setTransactionType(PhameBlogTransaction::TYPE_DOMAIN) ->setTransactionType(PhameBlogTransaction::TYPE_DOMAIN)
->setNewValue($custom_domain), ->setNewValue($custom_domain),
id(new PhameBlogTransaction())
->setTransactionType(PhameBlogTransaction::TYPE_SKIN)
->setNewValue($skin),
id(new PhameBlogTransaction()) id(new PhameBlogTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
->setNewValue($can_view), ->setNewValue($can_view),
@ -120,9 +115,6 @@ final class PhameBlogEditController
->setObject($blog) ->setObject($blog)
->execute(); ->execute();
$skins = PhameSkinSpecification::loadAllSkinSpecifications();
$skins = mpull($skins, 'getName');
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($viewer) ->setUser($viewer)
->appendChild( ->appendChild(
@ -179,12 +171,6 @@ final class PhameBlogEditController
->setCaption( ->setCaption(
pht('Must include at least one dot (.), e.g. %s', 'blog.example.com')) pht('Must include at least one dot (.), e.g. %s', 'blog.example.com'))
->setError($e_custom_domain)) ->setError($e_custom_domain))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Skin'))
->setName('skin')
->setValue($skin)
->setOptions($skins))
->appendChild( ->appendChild(
id(new AphrontFormSubmitControl()) id(new AphrontFormSubmitControl())
->addCancelButton($cancel_uri) ->addCancelButton($cancel_uri)

View file

@ -1,70 +0,0 @@
<?php
final class PhameBlogLiveController extends PhameBlogController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$site = $request->getSite();
if ($site instanceof PhameBlogSite) {
$blog = $site->getBlog();
} else {
$id = $request->getURIData('id');
$blog = id(new PhameBlogQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$blog) {
return new Aphront404Response();
}
}
if ($blog->getDomain() && ($request->getHost() != $blog->getDomain())) {
$base_uri = $blog->getLiveURI();
// Don't redirect directly, since the domain is user-controlled and there
// are a bevy of security issues associated with automatic redirects to
// external domains.
// Previously we CSRF'd this and someone found a way to pass OAuth
// information through it using anchors. Just make users click a normal
// link so that this is no more dangerous than any other external link
// on the site.
$dialog = id(new AphrontDialogView())
->setTitle(pht('Blog Moved'))
->setUser($viewer)
->appendParagraph(pht('This blog is now hosted here:'))
->appendParagraph(
phutil_tag(
'a',
array(
'href' => $base_uri,
),
$base_uri))
->addCancelButton('/');
return id(new AphrontDialogResponse())->setDialog($dialog);
}
$phame_request = clone $request;
$more = $phame_request->getURIData('more', '');
$phame_request->setPath('/'.ltrim($more, '/'));
$uri = $blog->getLiveURI();
$skin = $blog->getSkinRenderer($phame_request);
$skin
->setBlog($blog)
->setBaseURI($uri);
$skin->willProcessRequest(array());
return $skin->processRequest();
}
}

View file

@ -80,17 +80,11 @@ final class PhameBlogManageController extends PhameBlogController {
->setObject($blog) ->setObject($blog)
->setActionList($actions); ->setActionList($actions);
$skin = $blog->getSkin();
if (!$skin) {
$skin = phutil_tag('em', array(), pht('No external skin'));
}
$domain = $blog->getDomain(); $domain = $blog->getDomain();
if (!$domain) { if (!$domain) {
$domain = phutil_tag('em', array(), pht('No external domain')); $domain = phutil_tag('em', array(), pht('No external domain'));
} }
$properties->addProperty(pht('Skin'), $skin);
$properties->addProperty(pht('Domain'), $domain); $properties->addProperty(pht('Domain'), $domain);
$feed_uri = PhabricatorEnv::getProductionURI( $feed_uri = PhabricatorEnv::getProductionURI(

View file

@ -1,84 +1,78 @@
<?php <?php
final class PhameBlogViewController extends PhameBlogController { final class PhameBlogViewController extends PhameLiveController {
private $blog;
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer(); $response = $this->setupLiveEnvironment();
$id = $request->getURIData('id'); if ($response) {
return $response;
$blog = id(new PhameBlogQuery())
->setViewer($viewer)
->withIDs(array($id))
->needProfileImage(true)
->executeOne();
if (!$blog) {
return new Aphront404Response();
} }
$this->blog = $blog;
$viewer = $this->getViewer();
$blog = $this->getBlog();
$is_live = $this->getIsLive();
$is_external = $this->getIsExternal();
$pager = id(new AphrontCursorPagerView()) $pager = id(new AphrontCursorPagerView())
->readFromRequest($request); ->readFromRequest($request);
$posts = id(new PhamePostQuery()) $post_query = id(new PhamePostQuery())
->setViewer($viewer) ->setViewer($viewer)
->withBlogPHIDs(array($blog->getPHID())) ->withBlogPHIDs(array($blog->getPHID()));
->executeWithCursorPager($pager);
if ($blog->isArchived()) { if ($is_live) {
$header_icon = 'fa-ban'; $post_query->withVisibility(PhameConstants::VISIBILITY_PUBLISHED);
$header_name = pht('Archived');
$header_color = 'dark';
} else {
$header_icon = 'fa-check';
$header_name = pht('Active');
$header_color = 'bluegrey';
} }
$actions = $this->renderActions($blog, $viewer); $posts = $post_query->executeWithCursorPager($pager);
$action_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Actions'))
->setHref('#')
->setIconFont('fa-bars')
->addClass('phui-mobile-menu')
->setDropdownMenu($actions);
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($blog->getName()) ->setHeader($blog->getName())
->setUser($viewer) ->setUser($viewer);
->setPolicyObject($blog)
->setStatus($header_icon, $header_color, $header_name) if (!$is_external) {
->addActionLink($action_button); 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->setStatus($header_icon, $header_color, $header_name);
$actions = $this->renderActions($blog);
$action_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Actions'))
->setHref('#')
->setIconFont('fa-bars')
->addClass('phui-mobile-menu')
->setDropdownMenu($actions);
$header->addActionLink($action_button);
$header->setPolicyObject($blog);
}
$post_list = id(new PhamePostListView()) $post_list = id(new PhamePostListView())
->setPosts($posts) ->setPosts($posts)
->setViewer($viewer) ->setViewer($viewer)
->setIsExternal($is_external)
->setIsLive($is_live)
->setNodata(pht('This blog has no visible posts.')); ->setNodata(pht('This blog has no visible posts.'));
$crumbs = $this->buildApplicationCrumbs();
$crumbs->setBorder(true);
$crumbs->addTextCrumb(
pht('Blogs'),
$this->getApplicationURI('blog/'));
$crumbs->addTextCrumb(
$blog->getName());
$page = id(new PHUIDocumentViewPro()) $page = id(new PHUIDocumentViewPro())
->setHeader($header) ->setHeader($header)
->appendChild($post_list); ->appendChild($post_list);
$description = null; $description = null;
if (strlen($blog->getDescription())) { if (strlen($blog->getDescription())) {
$description = PhabricatorMarkupEngine::renderOneObject( $description = new PHUIRemarkupView(
id(new PhabricatorMarkupOneOff())->setContent($blog->getDescription()), $viewer,
'default', $blog->getDescription());
$viewer);
} else { } else {
$description = phutil_tag('em', array(), pht('No description.')); $description = phutil_tag('em', array(), pht('No description.'));
} }
@ -88,17 +82,30 @@ final class PhameBlogViewController extends PhameBlogController {
->setDescription($description) ->setDescription($description)
->setImage($blog->getProfileImageURI()); ->setImage($blog->getProfileImageURI());
return $this->newPage() $crumbs = $this->buildApplicationCrumbs();
$page = $this->newPage()
->setTitle($blog->getName()) ->setTitle($blog->getName())
->setPageObjectPHIDs(array($blog->getPHID()))
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->appendChild( ->appendChild(
array( array(
$page, $page,
$about, $about,
)); ));
if ($is_live) {
$page
->setShowChrome(false)
->setShowFooter(false);
}
return $page;
} }
private function renderActions(PhameBlog $blog, PhabricatorUser $viewer) { private function renderActions(PhameBlog $blog) {
$viewer = $this->getViewer();
$actions = id(new PhabricatorActionListView()) $actions = id(new PhabricatorActionListView())
->setObject($blog) ->setObject($blog)
->setObjectURI($this->getRequest()->getRequestURI()) ->setObjectURI($this->getRequest()->getRequestURI())

View file

@ -1,39 +0,0 @@
<?php
final class PhamePostFramedController extends PhamePostController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$post = id(new PhamePostQuery())
->setViewer($viewer)
->withIDs(array($id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$post) {
return new Aphront404Response();
}
$blog = $post->getBlog();
$phame_request = $request->setPath('/post/'.$post->getPhameTitle());
$skin = $post->getBlog()->getSkinRenderer($phame_request);
$uri = clone $request->getRequestURI();
$uri->setPath('/phame/live/'.$blog->getID().'/');
$skin
->setPreview(true)
->setBlog($post->getBlog())
->setBaseURI((string)$uri);
$response = $skin->processRequest();
$response->setFrameable(true);
return $response;
}
}

View file

@ -1,45 +0,0 @@
<?php
final class PhamePostNotLiveController extends PhamePostController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$post = id(new PhamePostQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$post) {
return new Aphront404Response();
}
$reasons = array();
if ($post->isDraft()) {
$reasons[] = phutil_tag('p', array(), pht(
'You can not view the live version of this post because it '.
'is still a draft. Use "Preview" or "Publish" to publish the post.'));
}
if ($reasons) {
$cancel_uri = $this->getApplicationURI('/post/view/'.$post->getID().'/');
$dialog = id(new AphrontDialogView())
->setUser($viewer)
->setTitle(pht('Post Not Live'))
->addCancelButton($cancel_uri);
foreach ($reasons as $reason) {
$dialog->appendChild($reason);
}
return id(new AphrontDialogResponse())->setDialog($dialog);
}
// No reason this can't go live, maybe an old link. Kick them live and see
// what happens.
$live_uri = $post->getLiveURI();
return id(new AphrontRedirectResponse())->setURI($live_uri);
}
}

View file

@ -1,89 +0,0 @@
<?php
final class PhamePostPreviewController extends PhamePostController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$post = id(new PhamePostQuery())
->setViewer($viewer)
->withIDs(array($id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$post) {
return new Aphront404Response();
}
$view_uri = $this->getApplicationURI('/post/view/'.$post->getID().'/');
if ($request->isFormPost()) {
$xactions = array();
$xactions[] = id(new PhamePostTransaction())
->setTransactionType(PhamePostTransaction::TYPE_VISIBILITY)
->setNewValue(PhameConstants::VISIBILITY_PUBLISHED);
id(new PhamePostEditor())
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->applyTransactions($post, $xactions);
return id(new AphrontRedirectResponse())->setURI($view_uri);
}
$form = id(new AphrontFormView())
->setUser($viewer)
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Publish Post'))
->addCancelButton($view_uri));
$frame = $this->renderPreviewFrame($post);
$form_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Preview Post'))
->setForm($form);
$blog = $post->getBlog();
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(
$blog->getName(),
$this->getApplicationURI('blog/view/'.$blog->getID().'/'));
$crumbs->addTextCrumb(pht('Preview Post'), $view_uri);
return $this->newPage()
->setTitle(pht('Preview Post'))
->setCrumbs($crumbs)
->appendChild(
array(
$form_box,
$frame,
));
}
private function renderPreviewFrame(PhamePost $post) {
return phutil_tag(
'div',
array(
'style' => 'text-align: center; padding: 16px;',
),
phutil_tag(
'iframe',
array(
'style' => 'width: 100%; height: 800px; '.
'border: 1px solid #BFCFDA; '.
'background-color: #fff; '.
'border-radius: 3px; ',
'src' => $this->getApplicationURI('/post/framed/'.$post->getID().'/'),
),
''));
}
}

View file

@ -4,13 +4,14 @@ final class PhamePostPublishController extends PhamePostController {
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer(); $viewer = $request->getViewer();
$id = $request->getURIData('id');
$id = $request->getURIData('id');
$post = id(new PhamePostQuery()) $post = id(new PhamePostQuery())
->setViewer($viewer) ->setViewer($viewer)
->withIDs(array($id)) ->withIDs(array($id))
->requireCapabilities( ->requireCapabilities(
array( array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT, PhabricatorPolicyCapability::CAN_EDIT,
)) ))
->executeOne(); ->executeOne();
@ -18,11 +19,23 @@ final class PhamePostPublishController extends PhamePostController {
return new Aphront404Response(); return new Aphront404Response();
} }
$cancel_uri = $post->getViewURI();
$action = $request->getURIData('action');
$is_publish = ($action == 'publish');
if ($request->isFormPost()) { if ($request->isFormPost()) {
$xactions = array(); $xactions = array();
if ($is_publish) {
$new_value = PhameConstants::VISIBILITY_PUBLISHED;
} else {
$new_value = PhameConstants::VISIBILITY_DRAFT;
}
$xactions[] = id(new PhamePostTransaction()) $xactions[] = id(new PhamePostTransaction())
->setTransactionType(PhamePostTransaction::TYPE_VISIBILITY) ->setTransactionType(PhamePostTransaction::TYPE_VISIBILITY)
->setNewValue(PhameConstants::VISIBILITY_PUBLISHED); ->setNewValue($new_value);
id(new PhamePostEditor()) id(new PhamePostEditor())
->setActor($viewer) ->setActor($viewer)
@ -32,21 +45,26 @@ final class PhamePostPublishController extends PhamePostController {
->applyTransactions($post, $xactions); ->applyTransactions($post, $xactions);
return id(new AphrontRedirectResponse()) return id(new AphrontRedirectResponse())
->setURI($this->getApplicationURI('/post/view/'.$post->getID().'/')); ->setURI($cancel_uri);
} }
$cancel_uri = $this->getApplicationURI('/post/view/'.$post->getID().'/'); if ($is_publish) {
$title = pht('Publish Post');
$body = pht('This post will go live once you publish it.');
$button = pht('Publish');
} else {
$title = pht('Unpublish Post');
$body = pht(
'This post will revert to draft status and no longer be visible '.
'to other users.');
$button = pht('Unpublish');
}
$dialog = $this->newDialog() return $this->newDialog()
->setTitle(pht('Publish Post?')) ->setTitle($title)
->appendChild( ->appendParagraph($body)
pht( ->addSubmitButton($button)
'The post "%s" will go live once you publish it.',
$post->getTitle()))
->addSubmitButton(pht('Publish'))
->addCancelButton($cancel_uri); ->addCancelButton($cancel_uri);
return id(new AphrontDialogResponse())->setDialog($dialog);
} }
} }

View file

@ -1,53 +0,0 @@
<?php
final class PhamePostUnpublishController extends PhamePostController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$post = id(new PhamePostQuery())
->setViewer($viewer)
->withIDs(array($id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$post) {
return new Aphront404Response();
}
if ($request->isFormPost()) {
$xactions = array();
$xactions[] = id(new PhamePostTransaction())
->setTransactionType(PhamePostTransaction::TYPE_VISIBILITY)
->setNewValue(PhameConstants::VISIBILITY_DRAFT);
id(new PhamePostEditor())
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->applyTransactions($post, $xactions);
return id(new AphrontRedirectResponse())
->setURI($this->getApplicationURI('/post/view/'.$post->getID().'/'));
}
$cancel_uri = $this->getApplicationURI('/post/view/'.$post->getID().'/');
$dialog = $this->newDialog()
->setTitle(pht('Unpublish Post?'))
->appendChild(
pht(
'The post "%s" will no longer be visible to other users until you '.
'republish it.',
$post->getTitle()))
->addSubmitButton(pht('Unpublish'))
->addCancelButton($cancel_uri);
return id(new AphrontDialogResponse())->setDialog($dialog);
}
}

View file

@ -1,53 +1,41 @@
<?php <?php
final class PhamePostViewController extends PhamePostController { final class PhamePostViewController
extends PhameLiveController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$response = $this->setupLiveEnvironment();
if ($response) {
return $response;
}
$viewer = $request->getViewer(); $viewer = $request->getViewer();
$moved = $request->getStr('moved'); $moved = $request->getStr('moved');
$post = id(new PhamePostQuery()) $post = $this->getPost();
->setViewer($viewer) $blog = $this->getBlog();
->withIDs(array($request->getURIData('id')))
->executeOne();
if (!$post) { $is_live = $this->getIsLive();
return new Aphront404Response(); $is_external = $this->getIsExternal();
}
$blog = $post->getBlog();
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(
pht('Blogs'),
$this->getApplicationURI('blog/'));
$crumbs->addTextCrumb(
$blog->getName(),
$this->getApplicationURI('blog/view/'.$blog->getID().'/'));
$crumbs->addTextCrumb(
$post->getTitle(),
$this->getApplicationURI('post/view/'.$post->getID().'/'));
$crumbs->setBorder(true);
$actions = $this->renderActions($post, $viewer);
$action_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Actions'))
->setHref('#')
->setIconFont('fa-bars')
->addClass('phui-mobile-menu')
->setDropdownMenu($actions);
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($post->getTitle()) ->setHeader($post->getTitle())
->setUser($viewer) ->setUser($viewer);
->setPolicyObject($post)
->addActionLink($action_button); if (!$is_external) {
$actions = $this->renderActions($post);
$action_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Actions'))
->setHref('#')
->setIconFont('fa-bars')
->addClass('phui-mobile-menu')
->setDropdownMenu($actions);
$header->setPolicyObject($post);
$header->addActionLink($action_button);
}
$document = id(new PHUIDocumentViewPro()) $document = id(new PHUIDocumentViewPro())
->setHeader($header); ->setHeader($header);
@ -66,7 +54,7 @@ final class PhamePostViewController extends PhamePostController {
->setTitle(pht('Draft Post')) ->setTitle(pht('Draft Post'))
->appendChild( ->appendChild(
pht('Only you can see this draft until you publish it. '. pht('Only you can see this draft until you publish it. '.
'Use "Preview" or "Publish" to publish this post.'))); 'Use "Publish" to publish this post.')));
} }
if (!$post->getBlog()) { if (!$post->getBlog()) {
@ -125,8 +113,12 @@ final class PhamePostViewController extends PhamePostController {
->withTransactionTypes(array(PhabricatorTransactions::TYPE_COMMENT))); ->withTransactionTypes(array(PhabricatorTransactions::TYPE_COMMENT)));
$timeline = phutil_tag_div('phui-document-view-pro-box', $timeline); $timeline = phutil_tag_div('phui-document-view-pro-box', $timeline);
$add_comment = $this->buildCommentForm($post); if ($is_external) {
$add_comment = phutil_tag_div('mlb mlt', $add_comment); $add_comment = null;
} else {
$add_comment = $this->buildCommentForm($post);
$add_comment = phutil_tag_div('mlb mlt', $add_comment);
}
$properties = id(new PHUIPropertyListView()) $properties = id(new PHUIPropertyListView())
->setUser($viewer) ->setUser($viewer)
@ -134,7 +126,9 @@ final class PhamePostViewController extends PhamePostController {
$properties->invokeWillRenderEvent(); $properties->invokeWillRenderEvent();
return $this->newPage() $crumbs = $this->buildApplicationCrumbs();
$page = $this->newPage()
->setTitle($post->getTitle()) ->setTitle($post->getTitle())
->setPageObjectPHIDs(array($post->getPHID())) ->setPageObjectPHIDs(array($post->getPHID()))
->setCrumbs($crumbs) ->setCrumbs($crumbs)
@ -146,16 +140,23 @@ final class PhamePostViewController extends PhamePostController {
$timeline, $timeline,
$add_comment, $add_comment,
)); ));
if ($is_live) {
$page
->setShowChrome(false)
->setShowFooter(false);
}
return $page;
} }
private function renderActions( private function renderActions(PhamePost $post) {
PhamePost $post, $viewer = $this->getViewer();
PhabricatorUser $viewer) {
$actions = id(new PhabricatorActionListView()) $actions = id(new PhabricatorActionListView())
->setObject($post) ->setObject($post)
->setObjectURI($this->getRequest()->getRequestURI()) ->setObjectURI($this->getRequest()->getRequestURI())
->setUser($viewer); ->setUser($viewer);
$can_edit = PhabricatorPolicyFilter::hasCapability( $can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer, $viewer,
@ -190,15 +191,9 @@ final class PhamePostViewController extends PhamePostController {
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setIcon('fa-eye') ->setIcon('fa-eye')
->setHref($this->getApplicationURI('post/publish/'.$id.'/')) ->setHref($this->getApplicationURI('post/publish/'.$id.'/'))
->setDisabled(!$can_edit)
->setName(pht('Publish')) ->setName(pht('Publish'))
->setWorkflow(true));
$actions->addAction(
id(new PhabricatorActionView())
->setIcon('fa-desktop')
->setHref($this->getApplicationURI('post/preview/'.$id.'/'))
->setDisabled(!$can_edit) ->setDisabled(!$can_edit)
->setName(pht('Preview in Skin'))); ->setWorkflow(true));
} else { } else {
$actions->addAction( $actions->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
@ -209,24 +204,18 @@ final class PhamePostViewController extends PhamePostController {
->setWorkflow(true)); ->setWorkflow(true));
} }
$blog = $post->getBlog(); if ($post->isDraft()) {
$can_view_live = $blog && !$post->isDraft(); $live_name = pht('Preview');
if ($can_view_live) {
$live_uri = $blog->getLiveURI($post);
} else { } else {
$live_uri = 'post/notlive/'.$post->getID().'/'; $live_name = pht('View Live');
$live_uri = $this->getApplicationURI($live_uri);
} }
$actions->addAction( $actions->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setUser($viewer) ->setUser($viewer)
->setIcon('fa-globe') ->setIcon('fa-globe')
->setHref($live_uri) ->setHref($post->getLiveURI())
->setName(pht('View Live')) ->setName($live_name));
->setDisabled(!$can_view_live)
->setWorkflow(!$can_view_live));
return $actions; return $actions;
} }

View file

@ -17,7 +17,6 @@ final class PhameBlogEditor
$types[] = PhameBlogTransaction::TYPE_NAME; $types[] = PhameBlogTransaction::TYPE_NAME;
$types[] = PhameBlogTransaction::TYPE_DESCRIPTION; $types[] = PhameBlogTransaction::TYPE_DESCRIPTION;
$types[] = PhameBlogTransaction::TYPE_DOMAIN; $types[] = PhameBlogTransaction::TYPE_DOMAIN;
$types[] = PhameBlogTransaction::TYPE_SKIN;
$types[] = PhameBlogTransaction::TYPE_STATUS; $types[] = PhameBlogTransaction::TYPE_STATUS;
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
@ -36,8 +35,6 @@ final class PhameBlogEditor
return $object->getDescription(); return $object->getDescription();
case PhameBlogTransaction::TYPE_DOMAIN: case PhameBlogTransaction::TYPE_DOMAIN:
return $object->getDomain(); return $object->getDomain();
case PhameBlogTransaction::TYPE_SKIN:
return $object->getSkin();
case PhameBlogTransaction::TYPE_STATUS: case PhameBlogTransaction::TYPE_STATUS:
return $object->getStatus(); return $object->getStatus();
} }
@ -51,7 +48,6 @@ final class PhameBlogEditor
case PhameBlogTransaction::TYPE_NAME: case PhameBlogTransaction::TYPE_NAME:
case PhameBlogTransaction::TYPE_DESCRIPTION: case PhameBlogTransaction::TYPE_DESCRIPTION:
case PhameBlogTransaction::TYPE_DOMAIN: case PhameBlogTransaction::TYPE_DOMAIN:
case PhameBlogTransaction::TYPE_SKIN:
case PhameBlogTransaction::TYPE_STATUS: case PhameBlogTransaction::TYPE_STATUS:
return $xaction->getNewValue(); return $xaction->getNewValue();
} }
@ -68,8 +64,6 @@ final class PhameBlogEditor
return $object->setDescription($xaction->getNewValue()); return $object->setDescription($xaction->getNewValue());
case PhameBlogTransaction::TYPE_DOMAIN: case PhameBlogTransaction::TYPE_DOMAIN:
return $object->setDomain($xaction->getNewValue()); return $object->setDomain($xaction->getNewValue());
case PhameBlogTransaction::TYPE_SKIN:
return $object->setSkin($xaction->getNewValue());
case PhameBlogTransaction::TYPE_STATUS: case PhameBlogTransaction::TYPE_STATUS:
return $object->setStatus($xaction->getNewValue()); return $object->setStatus($xaction->getNewValue());
} }
@ -85,7 +79,6 @@ final class PhameBlogEditor
case PhameBlogTransaction::TYPE_NAME: case PhameBlogTransaction::TYPE_NAME:
case PhameBlogTransaction::TYPE_DESCRIPTION: case PhameBlogTransaction::TYPE_DESCRIPTION:
case PhameBlogTransaction::TYPE_DOMAIN: case PhameBlogTransaction::TYPE_DOMAIN:
case PhameBlogTransaction::TYPE_SKIN:
case PhameBlogTransaction::TYPE_STATUS: case PhameBlogTransaction::TYPE_STATUS:
return; return;
} }

View file

@ -38,6 +38,11 @@ final class PhameBlogSite extends PhameSite {
$blog = id(new PhameBlogQuery()) $blog = id(new PhameBlogQuery())
->setViewer(new PhabricatorUser()) ->setViewer(new PhabricatorUser())
->withDomain($host) ->withDomain($host)
->needProfileImage(true)
->withStatuses(
array(
PhameBlog::STATUS_ACTIVE,
))
->executeOne(); ->executeOne();
} catch (PhabricatorPolicyException $ex) { } catch (PhabricatorPolicyException $ex) {
throw new Exception( throw new Exception(

View file

@ -1,325 +0,0 @@
<?php
/**
* @task paging Paging
* @task internal Internals
*/
abstract class PhameBasicBlogSkin extends PhameBlogSkin {
private $pager;
private $title;
private $description;
private $oGType;
private $uriPath;
public function setURIPath($uri_path) {
$this->uriPath = $uri_path;
return $this;
}
public function getURIPath() {
return $this->uriPath;
}
protected function setOGType($og_type) {
$this->oGType = $og_type;
return $this;
}
protected function getOGType() {
return $this->oGType;
}
protected function setDescription($description) {
$this->description = $description;
return $this;
}
protected function getDescription() {
return $this->description;
}
protected function setTitle($title) {
$this->title = $title;
return $this;
}
protected function getTitle() {
return $this->title;
}
public function handleRequest(AphrontRequest $request) {
$content = $this->renderContent($request);
if (!$content) {
$content = $this->render404Page();
}
$content = array(
$this->renderHeader(),
$content,
$this->renderFooter(),
);
$view = id(new PhabricatorBarePageView())
->setRequest($request)
->setController($this)
->setDeviceReady(true)
->setTitle($this->getBlog()->getName());
if ($this->getPreview()) {
$view->setFrameable(true);
}
$view->appendChild($content);
$response = new AphrontWebpageResponse();
$response->setContent($view->render());
return $response;
}
public function getSkinName() {
return get_class($this);
}
abstract protected function renderHeader();
abstract protected function renderFooter();
protected function renderPostDetail(PhamePostView $post) {
return $post;
}
protected function renderPostList(array $posts) {
$summaries = array();
foreach ($posts as $post) {
$summaries[] = $post->renderWithSummary();
}
$list = phutil_tag(
'div',
array(
'class' => 'phame-post-list',
),
id(new AphrontNullView())->appendChild($summaries)->render());
$pager = null;
if ($this->renderOlderPageLink() || $this->renderNewerPageLink()) {
$pager = phutil_tag(
'div',
array(
'class' => 'phame-pager',
),
array(
$this->renderOlderPageLink(),
$this->renderNewerPageLink(),
));
}
return array(
$list,
$pager,
);
}
protected function render404Page() {
return phutil_tag('h2', array(), pht('404 Not Found'));
}
final public function getResourceURI($resource) {
$root = $this->getSpecification()->getRootDirectory();
$path = $root.DIRECTORY_SEPARATOR.$resource;
$data = Filesystem::readFile($path);
$hash = PhabricatorHash::digest($data);
$hash = substr($hash, 0, 6);
$id = $this->getBlog()->getID();
$uri = '/phame/r/'.$id.'/'.$hash.'/'.$resource;
$uri = PhabricatorEnv::getCDNURI($uri);
return $uri;
}
/* -( Paging )------------------------------------------------------------- */
/**
* @task paging
*/
public function getPageSize() {
return 100;
}
/**
* @task paging
*/
protected function getOlderPageURI() {
if ($this->pager) {
$next = $this->pager->getNextPageID();
if ($next) {
return $this->getURI('older/'.$next.'/');
}
}
return null;
}
/**
* @task paging
*/
protected function renderOlderPageLink() {
$uri = $this->getOlderPageURI();
if (!$uri) {
return null;
}
return phutil_tag(
'a',
array(
'class' => 'phame-page-link phame-page-older',
'href' => $uri,
),
pht("\xE2\x80\xB9 Older"));
}
/**
* @task paging
*/
protected function getNewerPageURI() {
if ($this->pager) {
$next = $this->pager->getPrevPageID();
if ($next) {
return $this->getURI('newer/'.$next.'/');
}
}
return null;
}
/**
* @task paging
*/
protected function renderNewerPageLink() {
$uri = $this->getNewerPageURI();
if (!$uri) {
return null;
}
return phutil_tag(
'a',
array(
'class' => 'phame-page-link phame-page-newer',
'href' => $uri,
),
pht("Newer \xE2\x80\xBA"));
}
/* -( Internals )---------------------------------------------------------- */
/**
* @task internal
*/
protected function renderContent(AphrontRequest $request) {
$viewer = $request->getViewer();
$matches = null;
$path = $request->getPath();
// default to the blog-wide values
$this->setTitle($this->getBlog()->getName());
$this->setDescription($this->getBlog()->getDescription());
$this->setOGType('website');
$this->setURIPath('');
if (preg_match('@^/post/(?P<name>.*)$@', $path, $matches)) {
$post = id(new PhamePostQuery())
->setViewer($viewer)
->withBlogPHIDs(array($this->getBlog()->getPHID()))
->withPhameTitles(array($matches['name']))
->executeOne();
if ($post) {
$description = $post->getMarkupText(PhamePost::MARKUP_FIELD_SUMMARY);
$this->setTitle($post->getTitle());
$this->setDescription($description);
$this->setOGType('article');
$this->setURIPath('post/'.$post->getPhameTitle());
$view = head($this->buildPostViews(array($post)));
return $this->renderPostDetail($view);
}
} else {
$pager = new AphrontCursorPagerView();
if (preg_match('@^/older/(?P<before>\d+)/$@', $path, $matches)) {
$pager->setAfterID($matches['before']);
} else if (preg_match('@^/newer/(?P<after>\d)/$@', $path, $matches)) {
$pager->setBeforeID($matches['after']);
} else if (preg_match('@^/$@', $path, $matches)) {
// Just show the first page.
} else {
return null;
}
$pager->setPageSize($this->getPageSize());
$posts = id(new PhamePostQuery())
->setViewer($viewer)
->withBlogPHIDs(array($this->getBlog()->getPHID()))
->executeWithCursorPager($pager);
$this->pager = $pager;
if ($posts) {
$views = $this->buildPostViews($posts);
return $this->renderPostList($views);
}
}
return null;
}
private function buildPostViews(array $posts) {
assert_instances_of($posts, 'PhamePost');
$viewer = $this->getViewer();
$engine = id(new PhabricatorMarkupEngine())
->setViewer($viewer);
$phids = array();
foreach ($posts as $post) {
$engine->addObject($post, PhamePost::MARKUP_FIELD_BODY);
$engine->addObject($post, PhamePost::MARKUP_FIELD_SUMMARY);
$phids[] = $post->getBloggerPHID();
}
$handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs($phids)
->execute();
$engine->process();
$views = array();
foreach ($posts as $post) {
$view = id(new PhamePostView())
->setUser($viewer)
->setSkin($this)
->setPost($post)
->setBody($engine->getOutput($post, PhamePost::MARKUP_FIELD_BODY))
->setSummary($engine->getOutput($post, PhamePost::MARKUP_FIELD_SUMMARY))
->setAuthor($handles[$post->getBloggerPHID()]);
$post->makeEphemeral();
if (!$post->getDatePublished()) {
$post->setDatePublished(time());
}
$views[] = $view;
}
return $views;
}
}

View file

@ -1,161 +0,0 @@
<?php
final class PhameBasicTemplateBlogSkin extends PhameBasicBlogSkin {
private $cssResources;
public function processRequest() {
$root = dirname(phutil_get_library_root('phabricator'));
require_once $root.'/support/phame/libskin.php';
$this->cssResources = array();
$css = $this->getPath('css/');
if (Filesystem::pathExists($css)) {
foreach (Filesystem::listDirectory($css) as $path) {
if (!preg_match('/.css$/', $path)) {
continue;
}
$this->cssResources[] = phutil_tag(
'link',
array(
'rel' => 'stylesheet',
'type' => 'text/css',
'href' => $this->getResourceURI('css/'.$path),
));
}
}
$map = CelerityResourceMap::getNamedInstance('phabricator');
$highlight_symbol = 'syntax-highlighting-css';
$highlight_uri = $map->getURIForSymbol($highlight_symbol);
$this->cssResources[] = phutil_tag(
'link',
array(
'rel' => 'stylesheet',
'type' => 'text/css',
'href' => PhabricatorEnv::getCDNURI($highlight_uri),
));
$remarkup_symbol = 'phabricator-remarkup-css';
$remarkup_uri = $map->getURIForSymbol($remarkup_symbol);
$this->cssResources[] = phutil_tag(
'link',
array(
'rel' => 'stylesheet',
'type' => 'text/css',
'href' => PhabricatorEnv::getCDNURI($remarkup_uri),
));
$this->cssResources = phutil_implode_html("\n", $this->cssResources);
$request = $this->getRequest();
// Render page parts in order so the templates execute in order, if we're
// using templates.
$header = $this->renderHeader();
$content = $this->renderContent($request);
$footer = $this->renderFooter();
if (!$content) {
$content = $this->render404Page();
}
$content = array(
$header,
$content,
$footer,
);
$response = new AphrontWebpageResponse();
$response->setContent(phutil_implode_html("\n", $content));
return $response;
}
public function getCSSResources() {
return $this->cssResources;
}
public function remarkup($corpus) {
$view = id(new PHUIRemarkupView($this->getViewer(), $corpus));
return hsprintf('%s', $view);
}
public function getName() {
return $this->getSpecification()->getName();
}
public function getPath($to_file = null) {
$path = $this->getSpecification()->getRootDirectory();
if ($to_file) {
$path = $path.DIRECTORY_SEPARATOR.$to_file;
}
return $path;
}
private function renderTemplate($__template__, array $__scope__) {
chdir($this->getPath());
ob_start();
if (Filesystem::pathExists($this->getPath($__template__))) {
// Fool lint.
$__evil__ = 'extract';
$__evil__($__scope__ + $this->getDefaultScope());
require $this->getPath($__template__);
}
return phutil_safe_html(ob_get_clean());
}
private function getDefaultScope() {
return array(
'skin' => $this,
'blog' => $this->getBlog(),
'uri' => $this->getURI($this->getURIPath()),
'home_uri' => $this->getURI(''),
// TODO: This is wrong for detail pages, which should show the post
// title, but getting it right is a pain and this is better than nothing.
'title' => $this->getBlog()->getName(),
'description' => $this->getDescription(),
'og_type' => $this->getOGType(),
);
}
protected function renderHeader() {
return $this->renderTemplate(
'header.php',
array());
}
protected function renderFooter() {
return $this->renderTemplate('footer.php', array());
}
protected function render404Page() {
return $this->renderTemplate('404.php', array());
}
protected function renderPostDetail(PhamePostView $post) {
return $this->renderTemplate(
'post-detail.php',
array(
'post' => $post,
));
}
protected function renderPostList(array $posts) {
return $this->renderTemplate(
'post-list.php',
array(
'posts' => $posts,
'older' => $this->renderOlderPageLink(),
'newer' => $this->renderNewerPageLink(),
));
}
}

View file

@ -1,46 +0,0 @@
<?php
abstract class PhameBlogSkin extends PhabricatorController {
private $blog;
private $baseURI;
private $preview;
private $specification;
public function setSpecification(PhameSkinSpecification $specification) {
$this->specification = $specification;
return $this;
}
public function getSpecification() {
return $this->specification;
}
public function setPreview($preview) {
$this->preview = $preview;
return $this;
}
public function getPreview() {
return $this->preview;
}
final public function setBaseURI($base_uri) {
$this->baseURI = $base_uri;
return $this;
}
final public function getURI($path) {
return $this->baseURI.$path;
}
final public function setBlog(PhameBlog $blog) {
$this->blog = $blog;
return $this;
}
final public function getBlog() {
return $this->blog;
}
}

View file

@ -1,198 +0,0 @@
<?php
final class PhameSkinSpecification extends Phobject {
const TYPE_ADVANCED = 'advanced';
const TYPE_BASIC = 'basic';
const SKIN_PATH = 'externals/skins/';
private $type;
private $rootDirectory;
private $skinClass;
private $phutilLibraries = array();
private $name;
private $config;
public static function loadAllSkinSpecifications() {
static $specs;
if ($specs === null) {
$paths = array(self::SKIN_PATH);
$base = dirname(phutil_get_library_root('phabricator'));
$specs = array();
foreach ($paths as $path) {
$path = Filesystem::resolvePath($path, $base);
foreach (Filesystem::listDirectory($path) as $skin_directory) {
$skin_path = $path.DIRECTORY_SEPARATOR.$skin_directory;
if (!is_dir($skin_path)) {
continue;
}
$spec = self::loadSkinSpecification($skin_path);
if (!$spec) {
continue;
}
$name = trim($skin_directory, DIRECTORY_SEPARATOR);
$spec->setName($name);
if (isset($specs[$name])) {
$that_dir = $specs[$name]->getRootDirectory();
$this_dir = $spec->getRootDirectory();
throw new Exception(
pht(
"Two skins have the same name ('%s'), in '%s' and '%s'. ".
"Rename one or adjust your '%s' configuration.",
$name,
$this_dir,
$that_dir,
self::SKIN_PATH));
}
$specs[$name] = $spec;
}
}
}
return $specs;
}
public static function loadOneSkinSpecification($name) {
// Only allow skins which we know to exist to load. This prevents loading
// skins like "../../secrets/evil/".
$all = self::loadAllSkinSpecifications();
if (empty($all[$name])) {
throw new Exception(
pht(
'Blog skin "%s" is not a valid skin!',
$name));
}
$paths = array(self::SKIN_PATH);
$base = dirname(phutil_get_library_root('phabricator'));
foreach ($paths as $path) {
$path = Filesystem::resolvePath($path, $base);
$skin_path = $path.DIRECTORY_SEPARATOR.$name;
if (is_dir($skin_path)) {
// Double check that the skin really lives in the skin directory.
if (!Filesystem::isDescendant($skin_path, $path)) {
throw new Exception(
pht(
'Blog skin "%s" is not located in path "%s"!',
$name,
$path));
}
$spec = self::loadSkinSpecification($skin_path);
if ($spec) {
$spec->setName($name);
return $spec;
}
}
}
return null;
}
private static function loadSkinSpecification($path) {
$config_path = $path.DIRECTORY_SEPARATOR.'skin.json';
$config = array();
if (Filesystem::pathExists($config_path)) {
$config = Filesystem::readFile($config_path);
try {
$config = phutil_json_decode($config);
} catch (PhutilJSONParserException $ex) {
throw new PhutilProxyException(
pht(
"Skin configuration file '%s' is not a valid JSON file.",
$config_path),
$ex);
}
$type = idx($config, 'type', self::TYPE_BASIC);
} else {
$type = self::TYPE_BASIC;
}
$spec = new PhameSkinSpecification();
$spec->setRootDirectory($path);
$spec->setConfig($config);
switch ($type) {
case self::TYPE_BASIC:
$spec->setSkinClass('PhameBasicTemplateBlogSkin');
break;
case self::TYPE_ADVANCED:
$spec->setSkinClass($config['class']);
$spec->addPhutilLibrary($path.DIRECTORY_SEPARATOR.'src');
break;
default:
throw new Exception(pht('Unknown skin type!'));
}
$spec->setType($type);
return $spec;
}
public function setConfig(array $config) {
$this->config = $config;
return $this;
}
public function getConfig($key, $default = null) {
return idx($this->config, $key, $default);
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function getName() {
return $this->getConfig('name', $this->name);
}
public function setRootDirectory($root_directory) {
$this->rootDirectory = $root_directory;
return $this;
}
public function getRootDirectory() {
return $this->rootDirectory;
}
public function setType($type) {
$this->type = $type;
return $this;
}
public function getType() {
return $this->type;
}
public function setSkinClass($skin_class) {
$this->skinClass = $skin_class;
return $this;
}
public function getSkinClass() {
return $this->skinClass;
}
public function addPhutilLibrary($library) {
$this->phutilLibraries[] = $library;
return $this;
}
public function buildSkin(AphrontRequest $request) {
foreach ($this->phutilLibraries as $library) {
phutil_load_library($library);
}
return newv($this->getSkinClass(), array($request, $this));
}
}

View file

@ -11,7 +11,6 @@ final class PhameBlog extends PhameDAO
PhabricatorApplicationTransactionInterface { PhabricatorApplicationTransactionInterface {
const MARKUP_FIELD_DESCRIPTION = 'markup:description'; const MARKUP_FIELD_DESCRIPTION = 'markup:description';
const SKIN_DEFAULT = 'oblivious';
protected $name; protected $name;
protected $description; protected $description;
@ -25,7 +24,6 @@ final class PhameBlog extends PhameDAO
protected $profileImagePHID; protected $profileImagePHID;
private $profileImageFile = self::ATTACHABLE; private $profileImageFile = self::ATTACHABLE;
private static $requestBlog;
const STATUS_ACTIVE = 'active'; const STATUS_ACTIVE = 'active';
const STATUS_ARCHIVED = 'archived'; const STATUS_ARCHIVED = 'archived';
@ -84,29 +82,6 @@ final class PhameBlog extends PhameDAO
return $blog; return $blog;
} }
public function getSkinRenderer(AphrontRequest $request) {
$spec = PhameSkinSpecification::loadOneSkinSpecification(
$this->getSkin());
if (!$spec) {
$spec = PhameSkinSpecification::loadOneSkinSpecification(
self::SKIN_DEFAULT);
}
if (!$spec) {
throw new Exception(
pht(
'This blog has an invalid skin, and the default skin failed to '.
'load.'));
}
$skin = newv($spec->getSkinClass(), array());
$skin->setRequest($request);
$skin->setSpecification($spec);
return $skin;
}
public function isArchived() { public function isArchived() {
return ($this->getStatus() == self::STATUS_ARCHIVED); return ($this->getStatus() == self::STATUS_ARCHIVED);
} }
@ -196,53 +171,26 @@ final class PhameBlog extends PhameDAO
return null; return null;
} }
public function getSkin() { public function getLiveURI() {
$config = coalesce($this->getConfigData(), array()); if (strlen($this->getDomain())) {
return idx($config, 'skin', self::SKIN_DEFAULT); return $this->getExternalLiveURI();
}
public function setSkin($skin) {
$config = coalesce($this->getConfigData(), array());
$config['skin'] = $skin;
return $this->setConfigData($config);
}
public static function getSkinOptionsForSelect() {
$classes = id(new PhutilSymbolLoader())
->setAncestorClass('PhameBlogSkin')
->setType('class')
->setConcreteOnly(true)
->selectSymbolsWithoutLoading();
return ipull($classes, 'name', 'name');
}
public static function setRequestBlog(PhameBlog $blog) {
self::$requestBlog = $blog;
}
public static function getRequestBlog() {
return self::$requestBlog;
}
public function getLiveURI(PhamePost $post = null) {
if ($this->getDomain()) {
$base = new PhutilURI('http://'.$this->getDomain().'/');
} else { } else {
$base = '/phame/live/'.$this->getID().'/'; return $this->getInternalLiveURI();
$base = PhabricatorEnv::getURI($base);
} }
}
if ($post) { public function getExternalLiveURI() {
$base .= '/post/'.$post->getPhameTitle(); $domain = $this->getDomain();
} $uri = new PhutilURI('http://'.$this->getDomain().'/');
return (string)$uri;
}
return $base; public function getInternalLiveURI() {
return '/phame/live/'.$this->getID().'/';
} }
public function getViewURI() { public function getViewURI() {
$uri = '/phame/blog/view/'.$this->getID().'/'; return '/phame/blog/view/'.$this->getID().'/';
return PhabricatorEnv::getProductionURI($uri);
} }
public function getProfileImageURI() { public function getProfileImageURI() {

View file

@ -6,7 +6,6 @@ final class PhameBlogTransaction
const TYPE_NAME = 'phame.blog.name'; const TYPE_NAME = 'phame.blog.name';
const TYPE_DESCRIPTION = 'phame.blog.description'; const TYPE_DESCRIPTION = 'phame.blog.description';
const TYPE_DOMAIN = 'phame.blog.domain'; const TYPE_DOMAIN = 'phame.blog.domain';
const TYPE_SKIN = 'phame.blog.skin';
const TYPE_STATUS = 'phame.blog.status'; const TYPE_STATUS = 'phame.blog.status';
const MAILTAG_DETAILS = 'phame-blog-details'; const MAILTAG_DETAILS = 'phame-blog-details';
@ -43,7 +42,6 @@ final class PhameBlogTransaction
break; break;
case self::TYPE_DESCRIPTION: case self::TYPE_DESCRIPTION:
case self::TYPE_DOMAIN: case self::TYPE_DOMAIN:
case self::TYPE_SKIN:
return 'fa-pencil'; return 'fa-pencil';
case self::TYPE_STATUS: case self::TYPE_STATUS:
if ($new == PhameBlog::STATUS_ARCHIVED) { if ($new == PhameBlog::STATUS_ARCHIVED) {
@ -82,7 +80,6 @@ final class PhameBlogTransaction
case self::TYPE_NAME: case self::TYPE_NAME:
case self::TYPE_DESCRIPTION: case self::TYPE_DESCRIPTION:
case self::TYPE_DOMAIN: case self::TYPE_DOMAIN:
case self::TYPE_SKIN:
$tags[] = self::MAILTAG_DETAILS; $tags[] = self::MAILTAG_DETAILS;
break; break;
default: default:
@ -124,12 +121,6 @@ final class PhameBlogTransaction
$this->renderHandleLink($author_phid), $this->renderHandleLink($author_phid),
$new); $new);
break; break;
case self::TYPE_SKIN:
return pht(
'%s updated the blog\'s skin to "%s".',
$this->renderHandleLink($author_phid),
$new);
break;
case self::TYPE_STATUS: case self::TYPE_STATUS:
switch ($new) { switch ($new) {
case PhameBlog::STATUS_ACTIVE: case PhameBlog::STATUS_ACTIVE:
@ -181,12 +172,6 @@ final class PhameBlogTransaction
$this->renderHandleLink($author_phid), $this->renderHandleLink($author_phid),
$this->renderHandleLink($object_phid)); $this->renderHandleLink($object_phid));
break; break;
case self::TYPE_SKIN:
return pht(
'%s updated the skin for %s.',
$this->renderHandleLink($author_phid),
$this->renderHandleLink($object_phid));
break;
case self::TYPE_STATUS: case self::TYPE_STATUS:
switch ($new) { switch ($new) {
case PhameBlog::STATUS_ACTIVE: case PhameBlog::STATUS_ACTIVE:

View file

@ -49,19 +49,37 @@ final class PhamePost extends PhameDAO
} }
public function getLiveURI() { public function getLiveURI() {
// go for the pretty uri if we can $blog = $this->getBlog();
$domain = ($this->blog ? $this->blog->getDomain() : ''); $is_draft = $this->isDraft();
if ($domain) { if (strlen($blog->getDomain()) && !$is_draft) {
$phame_title = PhabricatorSlug::normalize($this->getPhameTitle()); return $this->getExternalLiveURI();
return 'http://'.$domain.'/post/'.$phame_title; } else {
return $this->getInternalLiveURI();
} }
$uri = '/phame/post/view/'.$this->getID().'/'; }
return PhabricatorEnv::getProductionURI($uri);
public function getExternalLiveURI() {
$id = $this->getID();
$slug = $this->getSlug();
$path = "/post/{$id}/{$slug}/";
$domain = $this->getBlog()->getDomain();
return (string)id(new PhutilURI('http://'.$domain))
->setPath($path);
}
public function getInternalLiveURI() {
$id = $this->getID();
$slug = $this->getSlug();
$blog_id = $this->getBlog()->getID();
return "/phame/live/{$blog_id}/post/{$id}/{$slug}/";
} }
public function getViewURI() { public function getViewURI() {
$phame_title = PhabricatorSlug::normalize($this->getPhameTitle()); $id = $this->getID();
return '/phame/post/view/'.$this->getID().'/'.$phame_title; $slug = $this->getSlug();
return "/phame/post/view/{$id}/{$slug}/";
} }
public function getEditURI() { public function getEditURI() {
@ -69,17 +87,7 @@ final class PhamePost extends PhameDAO
} }
public function isDraft() { public function isDraft() {
return $this->getVisibility() == PhameConstants::VISIBILITY_DRAFT; return ($this->getVisibility() == PhameConstants::VISIBILITY_DRAFT);
}
public function getHumanName() {
if ($this->isDraft()) {
$name = 'draft';
} else {
$name = 'post';
}
return $name;
} }
protected function getConfiguration() { protected function getConfiguration() {
@ -138,6 +146,10 @@ final class PhamePost extends PhameDAO
PhabricatorPhamePostPHIDType::TYPECONST); PhabricatorPhamePostPHIDType::TYPECONST);
} }
public function getSlug() {
return rtrim($this->getPhameTitle(), '/');
}
public function toDictionary() { public function toDictionary() {
return array( return array(
'id' => $this->getID(), 'id' => $this->getID(),

View file

@ -6,6 +6,8 @@ final class PhamePostListView extends AphrontTagView {
private $nodata; private $nodata;
private $viewer; private $viewer;
private $showBlog = false; private $showBlog = false;
private $isExternal;
private $isLive;
public function setPosts($posts) { public function setPosts($posts) {
assert_instances_of($posts, 'PhamePost'); assert_instances_of($posts, 'PhamePost');
@ -28,6 +30,24 @@ final class PhamePostListView extends AphrontTagView {
return $this; return $this;
} }
public function setIsExternal($is_external) {
$this->isExternal = $is_external;
return $this;
}
public function getIsExternal() {
return $this->isExternal;
}
public function setIsLive($is_live) {
$this->isLive = $is_live;
return $this;
}
public function getIsLive() {
return $this->isLive;
}
protected function getTagAttributes() { protected function getTagAttributes() {
return array(); return array();
} }
@ -63,21 +83,40 @@ final class PhamePostListView extends AphrontTagView {
$blogger = phutil_tag('strong', array(), $blogger); $blogger = phutil_tag('strong', array(), $blogger);
$date = phabricator_datetime($post->getDatePublished(), $viewer); $date = phabricator_datetime($post->getDatePublished(), $viewer);
$blog = null; $blog = $post->getBlog();
if ($post->getBlog()) {
$blog = phutil_tag( if ($this->getIsLive()) {
'a', if ($this->getIsExternal()) {
array( $blog_uri = $blog->getExternalLiveURI();
'href' => '/phame/blog/view/'.$post->getBlog()->getID().'/', $post_uri = $post->getExternalLiveURI();
), } else {
$post->getBlog()->getName()); $blog_uri = $blog->getInternalLiveURI();
$post_uri = $post->getInternalLiveURI();
}
} else {
$blog_uri = $blog->getViewURI();
$post_uri = $post->getViewURI();
} }
if ($this->showBlog && $blog) { $blog_link = phutil_tag(
'a',
array(
'href' => $blog_uri,
),
$blog->getName());
if ($this->showBlog) {
if ($post->isDraft()) { if ($post->isDraft()) {
$subtitle = pht('Unpublished draft by %s in %s.', $blogger, $blog); $subtitle = pht(
'Unpublished draft by %s in %s.',
$blogger,
$blog_link);
} else { } else {
$subtitle = pht('By %s on %s in %s.', $blogger, $date, $blog); $subtitle = pht(
'Written by %s on %s in %s.',
$blogger,
$date,
$blog_link);
} }
} else { } else {
if ($post->isDraft()) { if ($post->isDraft()) {
@ -89,7 +128,7 @@ final class PhamePostListView extends AphrontTagView {
$item = id(new PHUIDocumentSummaryView()) $item = id(new PHUIDocumentSummaryView())
->setTitle($post->getTitle()) ->setTitle($post->getTitle())
->setHref($post->getViewURI()) ->setHref($post_uri)
->setSubtitle($subtitle) ->setSubtitle($subtitle)
->setImage($blogger_image) ->setImage($blogger_image)
->setImageHref($blogger_uri) ->setImageHref($blogger_uri)

View file

@ -1,130 +0,0 @@
<?php
final class PhamePostView extends AphrontView {
private $post;
private $author;
private $body;
private $skin;
private $summary;
public function setSkin(PhameBlogSkin $skin) {
$this->skin = $skin;
return $this;
}
public function getSkin() {
return $this->skin;
}
public function setAuthor(PhabricatorObjectHandle $author) {
$this->author = $author;
return $this;
}
public function getAuthor() {
return $this->author;
}
public function setPost(PhamePost $post) {
$this->post = $post;
return $this;
}
public function getPost() {
return $this->post;
}
public function setBody($body) {
$this->body = $body;
return $this;
}
public function getBody() {
return $this->body;
}
public function setSummary($summary) {
$this->summary = $summary;
return $this;
}
public function getSummary() {
return $this->summary;
}
public function renderTitle() {
$href = $this->getSkin()->getURI('post/'.$this->getPost()->getPhameTitle());
return phutil_tag(
'h2',
array(
'class' => 'phame-post-title',
),
phutil_tag(
'a',
array(
'href' => $href,
),
$this->getPost()->getTitle()));
}
public function renderDatePublished() {
return phutil_tag(
'div',
array(
'class' => 'phame-post-date',
),
pht(
'Published on %s by %s',
phabricator_datetime(
$this->getPost()->getDatePublished(),
$this->getUser()),
$this->getAuthor()->getName()));
}
public function renderBody() {
return phutil_tag(
'div',
array(
'class' => 'phame-post-body phabricator-remarkup',
),
$this->getBody());
}
public function renderSummary() {
return phutil_tag(
'div',
array(
'class' => 'phame-post-body phabricator-remarkup',
),
$this->getSummary());
}
public function render() {
return phutil_tag(
'div',
array(
'class' => 'phame-post',
),
array(
$this->renderTitle(),
$this->renderDatePublished(),
$this->renderBody(),
));
}
public function renderWithSummary() {
return phutil_tag(
'div',
array(
'class' => 'phame-post',
),
array(
$this->renderTitle(),
$this->renderDatePublished(),
$this->renderSummary(),
));
}
}