Normalize Base URL during installation

- Fix base url when is appended with a script filename
- Add default base url http://flarum.local when CLI wizard used
- Remove some code duplication
- Add minor improvement to the UX when CLI wizard used
- Add tests
- Extract base url normalisation into its own value object
This commit is contained in:
Stefan Totev 2019-09-23 23:26:51 +01:00 committed by Daniël Klabbers
parent 3643e2010b
commit 1b74e43cb9
7 changed files with 168 additions and 19 deletions

83
src/Install/BaseUrl.php Normal file
View File

@ -0,0 +1,83 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Install;
use Psr\Http\Message\UriInterface;
final class BaseUrl
{
/** @var UriInterface|string */
private $baseUrl;
/**
* @param UriInterface|string $baseUrl
*/
private function __construct($baseUrl)
{
$this->baseUrl = $this->normalise($baseUrl);
}
/**
* @param string $baseUrl
* @return \Flarum\Install\BaseUrl
*/
public static function fromString(string $baseUrl): self
{
return new self($baseUrl);
}
/**
* @param \Psr\Http\Message\UriInterface $baseUrl
* @return \Flarum\Install\BaseUrl
*/
public static function fromUri(UriInterface $baseUrl): self
{
return self::fromString((string) $baseUrl);
}
/**
* @return string
*/
public function __toString(): string
{
return $this->baseUrl;
}
/**
* @param UriInterface|string $baseUrl
* @return string
*/
private function normalise($baseUrl): string
{
// Empty base url is still valid
if (empty($baseUrl)) {
return '';
}
$normalisedBaseUrl = trim($baseUrl, '/');
if (! preg_match('#^https?://#i', $normalisedBaseUrl)) {
$normalisedBaseUrl = sprintf('http://%s', $normalisedBaseUrl);
}
$parseUrl = parse_url($normalisedBaseUrl);
$path = $parseUrl['path'] ?? null;
if (isset($parseUrl['path']) && strrpos($parseUrl['path'], '.php') !== false) {
$path = substr($parseUrl['path'], 0, strrpos($parseUrl['path'], '/'));
}
return rtrim(
sprintf('%s://%s%s', $parseUrl['scheme'], $parseUrl['host'], $path),
'/'
);
}
}

View File

@ -11,6 +11,7 @@ namespace Flarum\Install\Console;
use Exception; use Exception;
use Flarum\Install\AdminUser; use Flarum\Install\AdminUser;
use Flarum\Install\BaseUrl;
use Flarum\Install\DatabaseConfig; use Flarum\Install\DatabaseConfig;
use Flarum\Install\Installation; use Flarum\Install\Installation;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
@ -43,7 +44,7 @@ class FileDataProvider implements DataProviderInterface
// Define configuration variables // Define configuration variables
$this->debug = $configuration['debug'] ?? false; $this->debug = $configuration['debug'] ?? false;
$this->baseUrl = isset($configuration['baseUrl']) ? rtrim($configuration['baseUrl'], '/') : null; $this->baseUrl = $configuration['baseUrl'] ?? 'http://flarum.local';
$this->databaseConfiguration = $configuration['databaseConfiguration'] ?? []; $this->databaseConfiguration = $configuration['databaseConfiguration'] ?? [];
$this->adminUser = $configuration['adminUser'] ?? []; $this->adminUser = $configuration['adminUser'] ?? [];
$this->settings = $configuration['settings'] ?? []; $this->settings = $configuration['settings'] ?? [];
@ -56,7 +57,7 @@ class FileDataProvider implements DataProviderInterface
{ {
return $installation return $installation
->debugMode($this->debug) ->debugMode($this->debug)
->baseUrl($this->baseUrl ?? 'http://flarum.local') ->baseUrl(BaseUrl::fromString($this->baseUrl))
->databaseConfig($this->getDatabaseConfiguration()) ->databaseConfig($this->getDatabaseConfiguration())
->adminUser($this->getAdminUser()) ->adminUser($this->getAdminUser())
->settings($this->settings); ->settings($this->settings);

View File

@ -10,6 +10,7 @@
namespace Flarum\Install\Console; namespace Flarum\Install\Console;
use Flarum\Install\AdminUser; use Flarum\Install\AdminUser;
use Flarum\Install\BaseUrl;
use Flarum\Install\DatabaseConfig; use Flarum\Install\DatabaseConfig;
use Flarum\Install\Installation; use Flarum\Install\Installation;
use Illuminate\Support\Str; use Illuminate\Support\Str;
@ -39,7 +40,7 @@ class UserDataProvider implements DataProviderInterface
{ {
return $installation return $installation
->debugMode(false) ->debugMode(false)
->baseUrl($this->getBaseUrl()) ->baseUrl(BaseUrl::fromString($this->getBaseUrl()))
->databaseConfig($this->getDatabaseConfiguration()) ->databaseConfig($this->getDatabaseConfiguration())
->adminUser($this->getAdminUser()) ->adminUser($this->getAdminUser())
->settings($this->getSettings()); ->settings($this->getSettings());
@ -47,7 +48,7 @@ class UserDataProvider implements DataProviderInterface
private function getDatabaseConfiguration(): DatabaseConfig private function getDatabaseConfiguration(): DatabaseConfig
{ {
$host = $this->ask('Database host:'); $host = $this->ask('Database host (required):');
$port = 3306; $port = 3306;
if (Str::contains($host, ':')) { if (Str::contains($host, ':')) {
@ -58,31 +59,31 @@ class UserDataProvider implements DataProviderInterface
'mysql', 'mysql',
$host, $host,
intval($port), intval($port),
$this->ask('Database name:'), $this->ask('Database name (required):'),
$this->ask('Database user:'), $this->ask('Database user (required):'),
$this->secret('Database password:'), $this->secret('Database password:'),
$this->ask('Prefix:') $this->ask('Prefix:')
); );
} }
private function getBaseUrl() private function getBaseUrl(): string
{ {
return $this->baseUrl = rtrim($this->ask('Base URL:'), '/'); return $this->baseUrl = $this->ask('Base URL:(Default: http://flarum.local)', 'http://flarum.local');
} }
private function getAdminUser(): AdminUser private function getAdminUser(): AdminUser
{ {
return new AdminUser( return new AdminUser(
$this->ask('Admin username:'), $this->ask('Admin username:(Default: admin)', 'admin'),
$this->askForAdminPassword(), $this->askForAdminPassword(),
$this->ask('Admin email address:') $this->ask('Admin email address (required):')
); );
} }
private function askForAdminPassword() private function askForAdminPassword()
{ {
while (true) { while (true) {
$password = $this->secret('Admin password:'); $password = $this->secret('Admin password (required >= 8 characters):');
if (strlen($password) < 8) { if (strlen($password) < 8) {
$this->validationError('Password must be at least 8 characters.'); $this->validationError('Password must be at least 8 characters.');
@ -103,11 +104,10 @@ class UserDataProvider implements DataProviderInterface
private function getSettings() private function getSettings()
{ {
$title = $this->ask('Forum title:'); $title = $this->ask('Forum title:');
$baseUrl = $this->baseUrl ?: 'http://localhost';
return [ return [
'forum_title' => $title, 'forum_title' => $title,
'mail_from' => 'noreply@'.preg_replace('/^www\./i', '', parse_url($baseUrl, PHP_URL_HOST)), 'mail_from' => 'noreply@'.preg_replace('/^www\./i', '', parse_url($this->baseUrl, PHP_URL_HOST)),
'welcome_title' => 'Welcome to '.$title, 'welcome_title' => 'Welcome to '.$title,
]; ];
} }

View File

@ -11,6 +11,7 @@ namespace Flarum\Install\Controller;
use Flarum\Http\SessionAuthenticator; use Flarum\Http\SessionAuthenticator;
use Flarum\Install\AdminUser; use Flarum\Install\AdminUser;
use Flarum\Install\BaseUrl;
use Flarum\Install\DatabaseConfig; use Flarum\Install\DatabaseConfig;
use Flarum\Install\Installation; use Flarum\Install\Installation;
use Flarum\Install\StepFailed; use Flarum\Install\StepFailed;
@ -52,16 +53,16 @@ class InstallController implements RequestHandlerInterface
public function handle(Request $request): ResponseInterface public function handle(Request $request): ResponseInterface
{ {
$input = $request->getParsedBody(); $input = $request->getParsedBody();
$baseUrl = rtrim((string) $request->getUri(), '/'); $baseUrl = $request->getUri();
try { try {
$pipeline = $this->installation $pipeline = $this->installation
->baseUrl($baseUrl) ->baseUrl(BaseUrl::fromUri($baseUrl))
->databaseConfig($this->makeDatabaseConfig($input)) ->databaseConfig($this->makeDatabaseConfig($input))
->adminUser($this->makeAdminUser($input)) ->adminUser($this->makeAdminUser($input))
->settings([ ->settings([
'forum_title' => Arr::get($input, 'forumTitle'), 'forum_title' => Arr::get($input, 'forumTitle'),
'mail_from' => 'noreply@'.preg_replace('/^www\./i', '', parse_url($baseUrl, PHP_URL_HOST)), 'mail_from' => 'noreply@'.preg_replace('/^www\./i', '', $baseUrl->getHost()),
'welcome_title' => 'Welcome to '.Arr::get($input, 'forumTitle'), 'welcome_title' => 'Welcome to '.Arr::get($input, 'forumTitle'),
]) ])
->build(); ->build();

View File

@ -63,9 +63,13 @@ class Installation
return $this; return $this;
} }
public function baseUrl($baseUrl) /**
* @param \Flarum\Install\BaseUrl $baseUrl
* @return $this
*/
public function baseUrl(BaseUrl $baseUrl)
{ {
$this->baseUrl = $baseUrl; $this->baseUrl = (string) $baseUrl;
return $this; return $this;
} }

View File

@ -8,6 +8,7 @@
*/ */
use Flarum\Install\AdminUser; use Flarum\Install\AdminUser;
use Flarum\Install\BaseUrl;
use Flarum\Install\DatabaseConfig; use Flarum\Install\DatabaseConfig;
use Flarum\Install\Installation; use Flarum\Install\Installation;
@ -46,7 +47,7 @@ $installation = new Installation(
$pipeline = $installation $pipeline = $installation
->configPath('config.php') ->configPath('config.php')
->debugMode(true) ->debugMode(true)
->baseUrl('http://localhost') ->baseUrl(BaseUrl::fromString('http://localhost'))
->databaseConfig(new DatabaseConfig( ->databaseConfig(new DatabaseConfig(
'mysql', 'mysql',
env('DB_HOST', 'localhost'), env('DB_HOST', 'localhost'),

View File

@ -0,0 +1,59 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Tests\unit;
use Flarum\Install\BaseUrl;
use Flarum\Tests\integration\TestCase;
class BaseUrlTest extends TestCase
{
/**
* @dataProvider urlProvider
* @param $uri
* @param $expected
*/
public function test_base_url_simulating_cli_installer($uri, $expected)
{
$this->assertEquals($expected, BaseUrl::fromString($uri));
}
/**
* @dataProvider urlProvider
* @param $uri
* @param $expected
*/
public function test_base_url_simulating_web_installer($uri, $expected)
{
$request = $this->request('get', $uri);
$this->assertEquals($expected, BaseUrl::fromUri($request->getUri()));
}
public function urlProvider()
{
return [
['', ''],
['flarum.org', 'http://flarum.org'],
['flarum.org/', 'http://flarum.org'],
['http://flarum.org', 'http://flarum.org'],
['http://flarum.org/', 'http://flarum.org'],
['https://flarum.org', 'https://flarum.org'],
['http://flarum.org/index.php', 'http://flarum.org'],
['http://flarum.org/index.php/', 'http://flarum.org'],
['http://flarum.org/flarum', 'http://flarum.org/flarum'],
['http://flarum.org/flarum/index.php', 'http://flarum.org/flarum'],
['http://flarum.org/flarum/index.php/', 'http://flarum.org/flarum'],
['sub.flarum.org', 'http://sub.flarum.org'],
['http://sub.flarum.org', 'http://sub.flarum.org'],
];
}
}