mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-30 17:30:59 +01:00
Phame - allow blogs to specify custom URIs
Summary: this then enables people to create blog.theircompany.com. And for us, blog.phacility.com...! Test Plan: - created custom URIs of various goodness and verified the error messages were sensical. - verified if "false" in configuration then custom uri stuff disappears Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T1373 Differential Revision: https://secure.phabricator.com/D3542
This commit is contained in:
parent
f29804a62a
commit
9e1b643896
8 changed files with 147 additions and 26 deletions
|
@ -735,15 +735,6 @@ return array(
|
|||
// The Phabricator "Client Secret" to use for Phabricator API access.
|
||||
'phabricator.application-secret' => null,
|
||||
|
||||
// -- Disqus Comments ------------------------------------------------------- //
|
||||
|
||||
// Should Phame users have Disqus comment widget, and if so what's the
|
||||
// website shortname to use? For example, secure.phabricator.org uses
|
||||
// "phabricator", which we registered with Disqus. If you aren't familiar
|
||||
// with Disqus, see:
|
||||
// Disqus quick start guide - http://docs.disqus.com/help/4/
|
||||
// Information on shortnames - http://docs.disqus.com/help/68/
|
||||
'disqus.shortname' => null,
|
||||
|
||||
// -- Recaptcha ------------------------------------------------------------- //
|
||||
|
||||
|
@ -1070,6 +1061,16 @@ return array(
|
|||
|
||||
'phriction.enabled' => true,
|
||||
|
||||
// -- Phame ----------------------------------------------------------------- //
|
||||
|
||||
// Should Phame users have Disqus comment widget, and if so what's the
|
||||
// website shortname to use? For example, secure.phabricator.org uses
|
||||
// "phabricator", which we registered with Disqus. If you aren't familiar
|
||||
// with Disqus, see:
|
||||
// Disqus quick start guide - http://docs.disqus.com/help/4/
|
||||
// Information on shortnames - http://docs.disqus.com/help/68/
|
||||
'disqus.shortname' => null,
|
||||
|
||||
// -- Remarkup -------------------------------------------------------------- //
|
||||
|
||||
// If you enable this, linked YouTube videos will be embeded inline. This has
|
||||
|
|
4
resources/sql/patches/phamedomain.sql
Normal file
4
resources/sql/patches/phamedomain.sql
Normal file
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE `{$NAMESPACE}_phame`.`phame_blog`
|
||||
ADD COLUMN `domain` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin
|
||||
AFTER `description`,
|
||||
ADD UNIQUE KEY (`domain`);
|
|
@ -91,9 +91,11 @@ abstract class AphrontApplicationConfiguration {
|
|||
/**
|
||||
* Using builtin and application routes, build the appropriate
|
||||
* @{class:AphrontController} class for the request. To route a request, we
|
||||
* test the URI against all builtin routes from @{method:getURIMap}, then
|
||||
* against all application routes from installed
|
||||
* @{class:PhabricatorApplication}s.
|
||||
* first test if the HTTP_HOST is configured as a valid Phabricator URI. If
|
||||
* it isn't, we do a special check to see if it's a custom domain for a blog
|
||||
* in the Phame application and if that fails we error. Otherwise, we test
|
||||
* the URI against all builtin routes from @{method:getURIMap}, then against
|
||||
* all application routes from installed @{class:PhabricatorApplication}s.
|
||||
*
|
||||
* If we match a route, we construct the controller it points at, build it,
|
||||
* and return it.
|
||||
|
@ -117,7 +119,6 @@ abstract class AphrontApplicationConfiguration {
|
|||
*/
|
||||
final public function buildController() {
|
||||
$request = $this->getRequest();
|
||||
$path = $request->getPath();
|
||||
|
||||
if (PhabricatorEnv::getEnvConfig('security.require-https')) {
|
||||
if (!$request->isHTTPS()) {
|
||||
|
@ -128,6 +129,41 @@ abstract class AphrontApplicationConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
$path = $request->getPath();
|
||||
$host = $request->getHost();
|
||||
$base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri');
|
||||
$prod_uri = PhabricatorEnv::getEnvConfig('phabricator.production-uri');
|
||||
$file_uri = PhabricatorEnv::getEnvConfig('security.alternate-file-domain');
|
||||
if ($host != id(new PhutilURI($base_uri))->getDomain() &&
|
||||
$host != id(new PhutilURI($prod_uri))->getDomain() &&
|
||||
$host != id(new PhutilURI($file_uri))->getDomain()) {
|
||||
$blogs = id(new PhameBlogQuery())->withDomain($host)->execute();
|
||||
$blog = reset($blogs);
|
||||
if (!$blog) {
|
||||
if ($prod_uri) {
|
||||
$prod_str = ' or '.$prod_uri;
|
||||
} else {
|
||||
$prod_str = '';
|
||||
}
|
||||
throw new Exception(
|
||||
'Specified domain '.$host.' is not configured for Phabricator '.
|
||||
'requests. Please use '.$base_uri.$prod_str.' to visit this instance.'
|
||||
);
|
||||
}
|
||||
|
||||
// 2 basic cases
|
||||
// -- looking at a list of blog posts, path is nothing or '/'
|
||||
// -- looking at an actual blog post, path is like /btrahan/post_title
|
||||
if (!$path || $path == '/') {
|
||||
$path = $blog->getViewURI();
|
||||
} else {
|
||||
$path = '/phame/posts/'.trim($path, '/').'/';
|
||||
}
|
||||
|
||||
// TODO - now we need to tell Celerity to render static resources with
|
||||
// full URIs like secure.phabricator.org/rsrc/blahblah
|
||||
}
|
||||
|
||||
list($controller, $uri_data) = $this->buildControllerForPath($path);
|
||||
if (!$controller) {
|
||||
if (!preg_match('@/$@', $path)) {
|
||||
|
|
|
@ -74,11 +74,12 @@ final class PhameBlogEditController
|
|||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$e_name = null;
|
||||
$e_bloggers = null;
|
||||
$errors = array();
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$e_name = null;
|
||||
$e_bloggers = null;
|
||||
$e_custom_domain = null;
|
||||
$errors = array();
|
||||
|
||||
if ($this->isBlogEdit()) {
|
||||
$blogs = id(new PhameBlogQuery())
|
||||
|
@ -117,10 +118,11 @@ final class PhameBlogEditController
|
|||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$saved = true;
|
||||
$name = $request->getStr('name');
|
||||
$description = $request->getStr('description');
|
||||
$blogger_arr = $request->getArr('bloggers');
|
||||
$saved = true;
|
||||
$name = $request->getStr('name');
|
||||
$description = $request->getStr('description');
|
||||
$blogger_arr = $request->getArr('bloggers');
|
||||
$custom_domain = $request->getStr('custom_domain');
|
||||
|
||||
if (empty($blogger_arr)) {
|
||||
$error = 'Bloggers must be nonempty.';
|
||||
|
@ -145,6 +147,14 @@ final class PhameBlogEditController
|
|||
}
|
||||
$blog->setName($name);
|
||||
$blog->setDescription($description);
|
||||
if (!empty($custom_domain)) {
|
||||
$error = $blog->validateCustomDomain($custom_domain);
|
||||
if ($error) {
|
||||
$errors[] = $error;
|
||||
$e_custom_domain = 'Invalid';
|
||||
}
|
||||
$blog->setDomain($custom_domain);
|
||||
}
|
||||
|
||||
if (empty($errors)) {
|
||||
$blog->save();
|
||||
|
@ -168,7 +178,11 @@ final class PhameBlogEditController
|
|||
|
||||
if ($saved) {
|
||||
$uri = new PhutilURI($blog->getViewURI());
|
||||
$uri->setQueryParam('new', true);
|
||||
if ($this->isBlogEdit()) {
|
||||
$uri->setQueryParam('edit', true);
|
||||
} else {
|
||||
$uri->setQueryParam('new', true);
|
||||
}
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($uri);
|
||||
}
|
||||
|
@ -208,8 +222,17 @@ final class PhameBlogEditController
|
|||
->setDatasource('/typeahead/common/users/')
|
||||
->setError($e_bloggers)
|
||||
)
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel('Custom Domain')
|
||||
->setName('custom_domain')
|
||||
->setValue($blog->getDomain())
|
||||
->setCaption('Must include at least one dot (.), e.g. '.
|
||||
'blog.example.com')
|
||||
->setError($e_custom_domain)
|
||||
)
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->addCancelButton('/phame/blog/')
|
||||
->setValue($submit_button)
|
||||
);
|
||||
|
|
|
@ -111,6 +111,10 @@ final class PhameBlogViewController
|
|||
$notice = $this->buildNoticeView()
|
||||
->setTitle('Successfully created your blog.')
|
||||
->appendChild('Time to write some posts.');
|
||||
} else if ($request->getExists('edit')) {
|
||||
$notice = $this->buildNoticeView()
|
||||
->setTitle('Successfully edited your blog.')
|
||||
->appendChild('Time to write some posts.');
|
||||
} else {
|
||||
$notice = null;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
final class PhameBlogQuery extends PhabricatorOffsetPagedQuery {
|
||||
|
||||
private $phids;
|
||||
private $domain;
|
||||
private $needBloggers;
|
||||
|
||||
public function withPHIDs($phids) {
|
||||
|
@ -29,6 +30,11 @@ final class PhameBlogQuery extends PhabricatorOffsetPagedQuery {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withDomain($domain) {
|
||||
$this->domain = $domain;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function needBloggers($need_bloggers) {
|
||||
$this->needBloggers = $need_bloggers;
|
||||
return $this;
|
||||
|
@ -96,7 +102,16 @@ final class PhameBlogQuery extends PhabricatorOffsetPagedQuery {
|
|||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'phid IN (%Ls)',
|
||||
$this->phids);
|
||||
$this->phids
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->domain) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'domain = %s',
|
||||
$this->domain
|
||||
);
|
||||
}
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
|
|
|
@ -25,6 +25,7 @@ final class PhameBlog extends PhameDAO {
|
|||
protected $phid;
|
||||
protected $name;
|
||||
protected $description;
|
||||
protected $domain;
|
||||
protected $configData;
|
||||
protected $creatorPHID;
|
||||
|
||||
|
@ -45,6 +46,38 @@ final class PhameBlog extends PhameDAO {
|
|||
PhabricatorPHIDConstants::PHID_TYPE_BLOG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure a given custom blog uri is properly configured in DNS
|
||||
* to point at this Phabricator instance. If there is an error in
|
||||
* the configuration, return a string describing the error and how
|
||||
* to fix it. If there is no error, return an empty string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function validateCustomDomain($custom_domain) {
|
||||
$example_domain = '(e.g. blog.example.com)';
|
||||
$valid = '';
|
||||
|
||||
// note this "uri" should be pretty busted given the desired input
|
||||
// so just use it to test if there's a protocol specified
|
||||
$uri = new PhutilURI($custom_domain);
|
||||
if ($uri->getProtocol()) {
|
||||
return 'Do not specify a protocol, just the domain. '.$example_domain;
|
||||
}
|
||||
|
||||
if (strpos($custom_domain, '/') !== false) {
|
||||
return 'Do not specify a path, just the domain. '.$example_domain;
|
||||
}
|
||||
|
||||
if (strpos($custom_domain, '.') === false) {
|
||||
return 'Custom domain must contain at least one dot (.) because '.
|
||||
'some browsers fail to set cookies on domains such as '.
|
||||
'http://example. '.$example_domain;
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
public function loadBloggerPHIDs() {
|
||||
if (!$this->getPHID()) {
|
||||
return $this;
|
||||
|
|
|
@ -988,6 +988,11 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
|||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('draft-metadata.sql'),
|
||||
),
|
||||
'phamedomain.sql' => array(
|
||||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('phamedomain.sql'),
|
||||
),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue