Refactor setup
This commit is contained in:
parent
5d1dce347f
commit
13a2cd9b18
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -20,4 +20,5 @@ storage/*.sqlite
|
||||||
.vscode
|
.vscode
|
||||||
storage/oauth-public.key
|
storage/oauth-public.key
|
||||||
storage/oauth-private.key
|
storage/oauth-private.key
|
||||||
|
storage/install.lock
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Filesystem\Filesystem;
|
||||||
|
|
||||||
class BsInstallCommand extends Command
|
class BsInstallCommand extends Command
|
||||||
{
|
{
|
||||||
|
|
@ -11,9 +12,9 @@ class BsInstallCommand extends Command
|
||||||
|
|
||||||
protected $description = 'Execute installation and create a super administrator.';
|
protected $description = 'Execute installation and create a super administrator.';
|
||||||
|
|
||||||
public function handle()
|
public function handle(Filesystem $filesystem)
|
||||||
{
|
{
|
||||||
if (\App\Http\Controllers\SetupController::checkTablesExist()) {
|
if ($filesystem->exists(storage_path('install.lock'))) {
|
||||||
$this->info('You have installed Blessing Skin Server. Nothing to do.');
|
$this->info('You have installed Blessing Skin Server. Nothing to do.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -44,6 +45,8 @@ class BsInstallCommand extends Command
|
||||||
$admin->verified = true;
|
$admin->verified = true;
|
||||||
$admin->save();
|
$admin->save();
|
||||||
|
|
||||||
|
$filesystem->put(storage_path('install.lock'), '');
|
||||||
|
|
||||||
$this->info('Installation completed!');
|
$this->info('Installation completed!');
|
||||||
$this->info('We recommend to modify your "Site URL" option if incorrect.');
|
$this->info('We recommend to modify your "Site URL" option if incorrect.');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,23 +6,22 @@ use DB;
|
||||||
use Log;
|
use Log;
|
||||||
use File;
|
use File;
|
||||||
use Option;
|
use Option;
|
||||||
use Schema;
|
|
||||||
use Artisan;
|
use Artisan;
|
||||||
use Storage;
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Composer\Semver\Comparator;
|
use Composer\Semver\Comparator;
|
||||||
|
use Illuminate\Filesystem\Filesystem;
|
||||||
use App\Exceptions\PrettyPageException;
|
use App\Exceptions\PrettyPageException;
|
||||||
|
use Symfony\Component\Finder\SplFileInfo;
|
||||||
|
|
||||||
class SetupController extends Controller
|
class SetupController extends Controller
|
||||||
{
|
{
|
||||||
public function welcome()
|
public function welcome(Filesystem $filesystem)
|
||||||
{
|
{
|
||||||
// @codeCoverageIgnoreStart
|
if (! $filesystem->exists(base_path('.env'))) {
|
||||||
if (! File::exists(base_path('.env'))) {
|
$filesystem->copy(base_path('.env.example'), base_path('.env'));
|
||||||
File::copy(base_path('.env.example'), base_path('.env'));
|
|
||||||
}
|
}
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
|
|
||||||
return view('setup.wizard.welcome');
|
return view('setup.wizard.welcome');
|
||||||
}
|
}
|
||||||
|
|
@ -104,31 +103,7 @@ class SetupController extends Controller
|
||||||
return redirect('setup/info');
|
return redirect('setup/info');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function info()
|
public function finish(Request $request, Filesystem $filesystem)
|
||||||
{
|
|
||||||
$existingTables = static::checkTablesExist([], true);
|
|
||||||
|
|
||||||
// Not installed completely
|
|
||||||
if (count($existingTables) > 0) {
|
|
||||||
Log::info('Remaining tables detected, exit setup wizard now', [$existingTables]);
|
|
||||||
|
|
||||||
$existingTables = array_map(function ($item) {
|
|
||||||
return get_db_config()['prefix'].$item;
|
|
||||||
}, $existingTables);
|
|
||||||
|
|
||||||
throw new PrettyPageException(trans('setup.database.table-already-exists', ['tables' => json_encode($existingTables)]), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
if (! function_exists('escapeshellarg')) {
|
|
||||||
throw new PrettyPageException(trans('setup.disabled-functions.escapeshellarg'), 1);
|
|
||||||
}
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
|
|
||||||
return view('setup.wizard.info');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function finish(Request $request)
|
|
||||||
{
|
{
|
||||||
$data = $this->validate($request, [
|
$data = $this->validate($request, [
|
||||||
'email' => 'required|email',
|
'email' => 'required|email',
|
||||||
|
|
@ -158,7 +133,7 @@ class SetupController extends Controller
|
||||||
|
|
||||||
$siteUrl = url('/');
|
$siteUrl = url('/');
|
||||||
|
|
||||||
if (ends_with($siteUrl, '/index.php')) {
|
if (Str::endsWith($siteUrl, '/index.php')) {
|
||||||
$siteUrl = substr($siteUrl, 0, -10); // @codeCoverageIgnore
|
$siteUrl = substr($siteUrl, 0, -10); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,7 +154,7 @@ class SetupController extends Controller
|
||||||
|
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
$this->createDirectories();
|
$filesystem->put(storage_path('install.lock'), '');
|
||||||
|
|
||||||
return view('setup.wizard.finish')->with([
|
return view('setup.wizard.finish')->with([
|
||||||
'email' => $request->input('email'),
|
'email' => $request->input('email'),
|
||||||
|
|
@ -187,102 +162,22 @@ class SetupController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update()
|
public function update(Filesystem $filesystem)
|
||||||
{
|
{
|
||||||
if (Comparator::lessThanOrEqualTo(config('app.version'), option('version'))) {
|
collect($filesystem->files(database_path('update_scripts')))
|
||||||
// No updates available
|
->filter(function (SplFileInfo $file) {
|
||||||
return view('setup.locked');
|
$name = $file->getFilenameWithoutExtension();
|
||||||
}
|
return preg_match('/^\d+\.\d+\.\d+$/', $name) > 0
|
||||||
|
&& Comparator::greaterThanOrEqualTo($name, option('version'));
|
||||||
return view('setup.updates.welcome');
|
})
|
||||||
}
|
->each(function (SplFileInfo $file) use ($filesystem) {
|
||||||
|
$filesystem->getRequire($file->getPathname());
|
||||||
public function doUpdate()
|
});
|
||||||
{
|
|
||||||
$resource = opendir(database_path('update_scripts'));
|
|
||||||
$updateScriptExist = false;
|
|
||||||
|
|
||||||
while ($filename = @readdir($resource)) {
|
|
||||||
if ($filename != '.' && $filename != '..') {
|
|
||||||
preg_match('/update-(.*)-to-(.*).php/', $filename, $matches);
|
|
||||||
|
|
||||||
// Skip if the file is not valid or expired
|
|
||||||
if (! isset($matches[2]) ||
|
|
||||||
Comparator::lessThan($matches[2], config('app.version'))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$tips = require database_path('update_scripts')."/$filename";
|
|
||||||
$updateScriptExist = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir($resource);
|
|
||||||
|
|
||||||
foreach (config('options') as $key => $value) {
|
|
||||||
if (! Option::has($key)) {
|
|
||||||
Option::set($key, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Option::set('version', config('app.version'));
|
|
||||||
|
|
||||||
|
option(['version' => config('app.version')]);
|
||||||
Artisan::call('view:clear');
|
Artisan::call('view:clear');
|
||||||
|
$filesystem->put(storage_path('install.lock'), '');
|
||||||
|
|
||||||
return view('setup.updates.success', ['tips' => $tips ?? []]);
|
return view('setup.updates.success');
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the given tables exist in current database.
|
|
||||||
*
|
|
||||||
* @param array $tables
|
|
||||||
* @param bool $returnExisting
|
|
||||||
* @return bool|array
|
|
||||||
*/
|
|
||||||
public static function checkTablesExist($tables = [], $returnExistingTables = false)
|
|
||||||
{
|
|
||||||
$existingTables = [];
|
|
||||||
$tables = $tables ?: [
|
|
||||||
'users',
|
|
||||||
'user_closet',
|
|
||||||
'players',
|
|
||||||
'textures',
|
|
||||||
'options',
|
|
||||||
'reports',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($tables as $tableName) {
|
|
||||||
if (Schema::hasTable($tableName)) {
|
|
||||||
$existingTables[] = $tableName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($existingTables) == count($tables)) {
|
|
||||||
return $returnExistingTables ? $existingTables : true;
|
|
||||||
} else {
|
|
||||||
return $returnExistingTables ? $existingTables : false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function checkDirectories()
|
|
||||||
{
|
|
||||||
$directories = ['storage/textures', 'plugins'];
|
|
||||||
|
|
||||||
try {
|
|
||||||
foreach ($directories as $dir) {
|
|
||||||
if (! Storage::disk('root')->has($dir)) {
|
|
||||||
if (! Storage::disk('root')->makeDirectory($dir)) {
|
|
||||||
return false; // @codeCoverageIgnore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function createDirectories()
|
|
||||||
{
|
|
||||||
return self::checkDirectories();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,9 @@ class Kernel extends HttpKernel
|
||||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||||
\Illuminate\Session\Middleware\StartSession::class,
|
\Illuminate\Session\Middleware\StartSession::class,
|
||||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
\App\Http\Middleware\ForbiddenIE::class,
|
|
||||||
\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class,
|
\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class,
|
||||||
|
\App\Http\Middleware\ForbiddenIE::class,
|
||||||
|
\App\Http\Middleware\RedirectToSetup::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,15 @@
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Filesystem\Filesystem;
|
||||||
use App\Http\Controllers\SetupController;
|
use App\Http\Controllers\SetupController;
|
||||||
|
|
||||||
class CheckInstallation
|
class CheckInstallation
|
||||||
{
|
{
|
||||||
public function handle($request, \Closure $next)
|
public function handle($request, \Closure $next)
|
||||||
{
|
{
|
||||||
if (config('database.default') == 'dummy') {
|
$hasLock = resolve(Filesystem::class)->exists(storage_path('install.lock'));
|
||||||
return $next($request); // @codeCoverageIgnore
|
if ($hasLock && ! $request->is('setup/*update')) {
|
||||||
}
|
|
||||||
|
|
||||||
if (SetupController::checkTablesExist()) {
|
|
||||||
return response()->view('setup.locked');
|
return response()->view('setup.locked');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Closure;
|
|
||||||
use App\Models\User;
|
|
||||||
|
|
||||||
class LockUpdatePage
|
|
||||||
{
|
|
||||||
public function handle($request, Closure $next)
|
|
||||||
{
|
|
||||||
abort_if($request->user()->permission < User::SUPER_ADMIN, 503);
|
|
||||||
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
30
app/Http/Middleware/RedirectToSetup.php
Normal file
30
app/Http/Middleware/RedirectToSetup.php
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Composer\Semver\Comparator;
|
||||||
|
use Illuminate\Filesystem\Filesystem;
|
||||||
|
|
||||||
|
class RedirectToSetup
|
||||||
|
{
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
$version = config('app.version');
|
||||||
|
if (! $request->is('setup*') && Comparator::greaterThan($version, option('version', $version))) {
|
||||||
|
$user = $request->user();
|
||||||
|
if ($user && $user->isAdmin()) {
|
||||||
|
return redirect('/setup/update');
|
||||||
|
} else {
|
||||||
|
abort(503);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$hasLock = resolve(Filesystem::class)->exists(storage_path('install.lock'));
|
||||||
|
if ($hasLock || $request->is('setup*')) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect('/setup');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,16 +20,6 @@ class RouteServiceProvider extends ServiceProvider
|
||||||
*/
|
*/
|
||||||
protected $namespace = 'App\Http\Controllers';
|
protected $namespace = 'App\Http\Controllers';
|
||||||
|
|
||||||
/**
|
|
||||||
* Define your route model bindings, pattern filters, etc.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function boot()
|
|
||||||
{
|
|
||||||
parent::boot();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the routes for the application.
|
* Define the routes for the application.
|
||||||
*
|
*
|
||||||
|
|
@ -38,8 +28,6 @@ class RouteServiceProvider extends ServiceProvider
|
||||||
*/
|
*/
|
||||||
public function map(Router $router)
|
public function map(Router $router)
|
||||||
{
|
{
|
||||||
$this->mapSetupRoutes($router);
|
|
||||||
|
|
||||||
$this->mapStaticRoutes($router);
|
$this->mapStaticRoutes($router);
|
||||||
|
|
||||||
$this->mapWebRoutes($router);
|
$this->mapWebRoutes($router);
|
||||||
|
|
@ -74,22 +62,6 @@ class RouteServiceProvider extends ServiceProvider
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Define the "setup" routes for the application.
|
|
||||||
*
|
|
||||||
* The routes for setup wizard.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Routing\Router $router
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function mapSetupRoutes(Router $router)
|
|
||||||
{
|
|
||||||
Route::prefix('setup')
|
|
||||||
->namespace($this->namespace)
|
|
||||||
->middleware('web')
|
|
||||||
->group(base_path('routes/setup.php'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the "static" routes for the application.
|
* Define the "static" routes for the application.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Providers;
|
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Composer\Semver\Comparator;
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
|
||||||
use App\Http\Controllers\SetupController;
|
|
||||||
|
|
||||||
class RuntimeCheckServiceProvider extends ServiceProvider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Bootstrap any application services.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function boot(Request $request)
|
|
||||||
{
|
|
||||||
// Skip the installation check when in setup or under CLI
|
|
||||||
if ($request->is('setup*') || $this->app->runningInConsole()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->checkInstallation(); // @codeCoverageIgnore
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @codeCoverageIgnore
|
|
||||||
*/
|
|
||||||
protected function checkInstallation()
|
|
||||||
{
|
|
||||||
// Redirect to setup wizard
|
|
||||||
if (config('database.default') == 'dummy' || ! SetupController::checkTablesExist()) {
|
|
||||||
return redirect('/setup')->send();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Comparator::greaterThan(config('app.version'), option('version'))) {
|
|
||||||
return redirect('/setup/update')->send();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -170,7 +170,6 @@ return [
|
||||||
/*
|
/*
|
||||||
* Application Service Providers...
|
* Application Service Providers...
|
||||||
*/
|
*/
|
||||||
App\Providers\RuntimeCheckServiceProvider::class,
|
|
||||||
App\Providers\AppServiceProvider::class,
|
App\Providers\AppServiceProvider::class,
|
||||||
App\Providers\EventServiceProvider::class,
|
App\Providers\EventServiceProvider::class,
|
||||||
App\Providers\PluginServiceProvider::class,
|
App\Providers\PluginServiceProvider::class,
|
||||||
|
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
|
|
||||||
'characters' => '2346789abcdefghjmnpqrtuxyzABCDEFGHJMNPQRTUXYZ',
|
|
||||||
|
|
||||||
'default' => [
|
|
||||||
'length' => 5,
|
|
||||||
'width' => 100,
|
|
||||||
'height' => 34,
|
|
||||||
'quality' => 90,
|
|
||||||
],
|
|
||||||
|
|
||||||
'flat' => [
|
|
||||||
'length' => 6,
|
|
||||||
'width' => 160,
|
|
||||||
'height' => 46,
|
|
||||||
'quality' => 90,
|
|
||||||
'lines' => 6,
|
|
||||||
'bgImage' => false,
|
|
||||||
'bgColor' => '#ecf2f4',
|
|
||||||
'fontColors'=> ['#2c3e50', '#c0392b', '#16a085', '#c0392b', '#8e44ad', '#303f9f', '#f57c00', '#795548'],
|
|
||||||
'contrast' => -5,
|
|
||||||
],
|
|
||||||
|
|
||||||
'mini' => [
|
|
||||||
'length' => 3,
|
|
||||||
'width' => 60,
|
|
||||||
'height' => 32,
|
|
||||||
],
|
|
||||||
|
|
||||||
'inverse' => [
|
|
||||||
'length' => 5,
|
|
||||||
'width' => 120,
|
|
||||||
'height' => 36,
|
|
||||||
'quality' => 90,
|
|
||||||
'sensitive' => true,
|
|
||||||
'angle' => 12,
|
|
||||||
'sharpen' => 10,
|
|
||||||
'blur' => 2,
|
|
||||||
'invert' => true,
|
|
||||||
'contrast' => -5,
|
|
||||||
],
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
@ -15,7 +15,7 @@ disabled-functions:
|
||||||
|
|
||||||
locked:
|
locked:
|
||||||
title: Already installed
|
title: Already installed
|
||||||
text: It appears that you have already installed Blessing Skin Server. To reinstall, please delete the tables in your database first, or use a new table prefix.
|
text: It appears that you have already installed Blessing Skin Server. To reinstall, please delete the "install.lock" file under "storage" directory.
|
||||||
button: Back to homepage
|
button: Back to homepage
|
||||||
|
|
||||||
updates:
|
updates:
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ disabled-functions:
|
||||||
|
|
||||||
locked:
|
locked:
|
||||||
title: 已安装过
|
title: 已安装过
|
||||||
text: Blessing Skin Server 看起来已经安装妥当。如果想重新安装,请删除数据库中的旧数据表,或者换一个数据表前缀。
|
text: Blessing Skin Server 看起来已经安装妥当。如果想重新安装,请删除 storage 目录下的 install.lock 文件。
|
||||||
button: 返回首页
|
button: 返回首页
|
||||||
|
|
||||||
updates:
|
updates:
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
- Tweaked policy of retrieve CA cert for GuzzleHttp.
|
- Tweaked policy of retrieve CA cert for GuzzleHttp.
|
||||||
- Refactor account system.
|
- Refactor account system.
|
||||||
- PHP version requirement is increased to 7.2.0.
|
- PHP version requirement is increased to 7.2.0.
|
||||||
|
- Use `install.lock` file to detect status of installation.
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
- 修改 GuzzleHttp 库获取 CA 证书的策略
|
- 修改 GuzzleHttp 库获取 CA 证书的策略
|
||||||
- 重构用户系统
|
- 重构用户系统
|
||||||
- PHP 版本最低要求为 7.2.0
|
- PHP 版本最低要求为 7.2.0
|
||||||
|
- 使用 `install.lock` 文件来检测安装状态
|
||||||
|
|
||||||
## 修复
|
## 修复
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,6 @@
|
||||||
|
|
||||||
<p>@lang('setup.updates.success.text', ['version' => config('app.version')])</p>
|
<p>@lang('setup.updates.success.text', ['version' => config('app.version')])</p>
|
||||||
|
|
||||||
{{-- if any tip is given --}}
|
|
||||||
@if (is_array($tips) && count($tips) > 0)
|
|
||||||
<p><b>@lang('setup.updates.success.tips')</b></p>
|
|
||||||
<ul>
|
|
||||||
@foreach ($tips as $tip)
|
|
||||||
<li><p>{!! $tip !!}</p></li>
|
|
||||||
@endforeach
|
|
||||||
</ul>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<p class="step">
|
<p class="step">
|
||||||
<a href="{{ url('/setup/changelog') }}" class="button button-large">@lang('setup.updates.welcome.button')</a>
|
<a href="{{ url('/setup/changelog') }}" class="button button-large">@lang('setup.updates.welcome.button')</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Application Routes
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Here is where you can register all of the routes for an application.
|
|
||||||
| It's a breeze. Simply tell Laravel the URIs it should respond to
|
|
||||||
| and give it the controller to call when that URI is requested.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup Wizard.
|
|
||||||
*/
|
|
||||||
Route::group(['middleware' => 'setup'], function () {
|
|
||||||
Route::any('/', 'SetupController@welcome');
|
|
||||||
Route::any('/database', 'SetupController@database');
|
|
||||||
Route::get('/info', 'SetupController@info');
|
|
||||||
Route::post('/finish', 'SetupController@finish');
|
|
||||||
});
|
|
||||||
|
|
||||||
Route::group(['middleware' => ['authorize', App\Http\Middleware\LockUpdatePage::class]], function () {
|
|
||||||
Route::any('/update', 'SetupController@update');
|
|
||||||
Route::any('/exec-update', 'SetupController@doUpdate');
|
|
||||||
Route::view('/changelog', 'setup.updates.changelog');
|
|
||||||
});
|
|
||||||
|
|
@ -156,3 +156,21 @@ Route::group(['middleware' => ['authorize', 'admin'], 'prefix' => 'admin'], func
|
||||||
Route::any('/download', 'UpdateController@download');
|
Route::any('/download', 'UpdateController@download');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup and Update
|
||||||
|
*/
|
||||||
|
Route::group(['prefix' => 'setup'], function () {
|
||||||
|
Route::group(['middleware' => 'setup'], function () {
|
||||||
|
Route::any('/', 'SetupController@welcome');
|
||||||
|
Route::any('/database', 'SetupController@database');
|
||||||
|
Route::view('/info', 'setup.wizard.info');
|
||||||
|
Route::post('/finish', 'SetupController@finish');
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::group(['middleware' => 'authorize'], function () {
|
||||||
|
Route::view('/update', 'setup.updates.welcome')->middleware('setup');
|
||||||
|
Route::any('/exec-update', 'SetupController@update')->middleware('setup');
|
||||||
|
Route::view('/changelog', 'setup.updates.changelog');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,11 @@ class BrowserKitTestCase extends TestCase
|
||||||
|
|
||||||
Artisan::call('migrate:refresh');
|
Artisan::call('migrate:refresh');
|
||||||
|
|
||||||
|
$files = $app->make('files');
|
||||||
|
if (! $files->exists(storage_path('install.lock'))) {
|
||||||
|
$files->put(storage_path('install.lock'), '');
|
||||||
|
}
|
||||||
|
|
||||||
return $app;
|
return $app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ namespace Tests;
|
||||||
|
|
||||||
use Schema;
|
use Schema;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Illuminate\Filesystem\Filesystem;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
class BsInstallCommandTest extends TestCase
|
class BsInstallCommandTest extends TestCase
|
||||||
|
|
@ -15,25 +16,15 @@ class BsInstallCommandTest extends TestCase
|
||||||
$this->artisan('bs:install ibara.mayaka@hyouka.test 12345678 mayaka')
|
$this->artisan('bs:install ibara.mayaka@hyouka.test 12345678 mayaka')
|
||||||
->expectsOutput('You have installed Blessing Skin Server. Nothing to do.');
|
->expectsOutput('You have installed Blessing Skin Server. Nothing to do.');
|
||||||
|
|
||||||
$tables = [
|
$this->mock(Filesystem::class, function ($mock) {
|
||||||
'user_closet',
|
$mock->shouldReceive('exists')
|
||||||
'migrations',
|
->with(storage_path('install.lock'))
|
||||||
'options',
|
->once()
|
||||||
'players',
|
->andReturn(false);
|
||||||
'textures',
|
$mock->shouldReceive('put')
|
||||||
'users',
|
->with(storage_path('install.lock'), '')
|
||||||
'reports',
|
->once()
|
||||||
'oauth_auth_codes',
|
->andReturn(true);
|
||||||
'oauth_access_tokens',
|
|
||||||
'oauth_clients',
|
|
||||||
'oauth_personal_access_clients',
|
|
||||||
'oauth_refresh_tokens',
|
|
||||||
'notifications',
|
|
||||||
'jobs',
|
|
||||||
'language_lines',
|
|
||||||
];
|
|
||||||
array_walk($tables, function ($table) {
|
|
||||||
Schema::dropIfExists($table);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->artisan('bs:install ibara.mayaka@hyouka.test 12345678 mayaka')
|
$this->artisan('bs:install ibara.mayaka@hyouka.test 12345678 mayaka')
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use Event;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Player;
|
use App\Models\Player;
|
||||||
use App\Services\Facades\Option;
|
use App\Services\Facades\Option;
|
||||||
|
use Illuminate\Filesystem\Filesystem;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
|
|
@ -84,16 +85,28 @@ class MiddlewareTest extends TestCase
|
||||||
{
|
{
|
||||||
$this->get('/setup')->assertSee('Already installed');
|
$this->get('/setup')->assertSee('Already installed');
|
||||||
|
|
||||||
$tables = [
|
$this->mock(Filesystem::class, function ($mock) {
|
||||||
'user_closet', 'migrations', 'options', 'players', 'textures', 'users',
|
$mock->shouldReceive('exists')
|
||||||
];
|
->with(storage_path('install.lock'))
|
||||||
array_walk($tables, function ($table) {
|
->twice()
|
||||||
Schema::dropIfExists($table);
|
->andReturn(false);
|
||||||
|
$mock->shouldReceive('exists')
|
||||||
|
->with(base_path('.env'))
|
||||||
|
->andReturn(true);
|
||||||
});
|
});
|
||||||
$this->get('/setup')->assertSee(trans(
|
$this->get('/setup')->assertSee(trans(
|
||||||
'setup.wizard.welcome.text',
|
'setup.wizard.welcome.text',
|
||||||
['version' => config('app.version')]
|
['version' => config('app.version')]
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$this->actAs('superAdmin');
|
||||||
|
$this->mock(Filesystem::class, function ($mock) {
|
||||||
|
$mock->shouldReceive('exists')
|
||||||
|
->with(storage_path('install.lock'))
|
||||||
|
->andReturn(true);
|
||||||
|
});
|
||||||
|
config(['app.version' => '100.0.0']);
|
||||||
|
$this->get('/setup/update')->assertSee(trans('setup.updates.welcome.title'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCheckPlayerExist()
|
public function testCheckPlayerExist()
|
||||||
|
|
@ -178,6 +191,28 @@ class MiddlewareTest extends TestCase
|
||||||
->assertRedirect('/user');
|
->assertRedirect('/user');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRedirectToSetup()
|
||||||
|
{
|
||||||
|
$current = config('app.version');
|
||||||
|
config(['app.version' => '100.0.0']);
|
||||||
|
$this->get('/')->assertStatus(503);
|
||||||
|
$this->actAs('superAdmin')->get('/')->assertRedirect('/setup/update');
|
||||||
|
config(['app.version' => $current]);
|
||||||
|
|
||||||
|
$this->mock(Filesystem::class, function ($mock) {
|
||||||
|
$mock->shouldReceive('exists')
|
||||||
|
->with(storage_path('install.lock'))
|
||||||
|
->andReturn(true, false, false);
|
||||||
|
|
||||||
|
$mock->shouldReceive('exists')
|
||||||
|
->with(base_path('.env'))
|
||||||
|
->andReturn(true);
|
||||||
|
});
|
||||||
|
$this->get('/')->assertViewIs('index');
|
||||||
|
$this->get('/setup')->assertViewIs('setup.wizard.welcome');
|
||||||
|
$this->get('/')->assertRedirect('/setup');
|
||||||
|
}
|
||||||
|
|
||||||
public function testRejectBannedUser()
|
public function testRejectBannedUser()
|
||||||
{
|
{
|
||||||
$user = factory(User::class, 'banned')->create();
|
$user = factory(User::class, 'banned')->create();
|
||||||
|
|
@ -210,10 +245,4 @@ class MiddlewareTest extends TestCase
|
||||||
$this->get('/', ['user-agent' => 'MSIE'])->assertSee(trans('errors.http.ie'));
|
$this->get('/', ['user-agent' => 'MSIE'])->assertSee(trans('errors.http.ie'));
|
||||||
$this->get('/', ['user-agent' => 'Trident'])->assertSee(trans('errors.http.ie'));
|
$this->get('/', ['user-agent' => 'Trident'])->assertSee(trans('errors.http.ie'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLockUpdatePage()
|
|
||||||
{
|
|
||||||
$this->actAs('admin')->get('/setup/changelog')->assertStatus(503);
|
|
||||||
$this->actAs('superAdmin')->get('/setup/changelog')->assertStatus(200);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,62 +2,48 @@
|
||||||
|
|
||||||
namespace Tests;
|
namespace Tests;
|
||||||
|
|
||||||
use Mockery;
|
|
||||||
use Exception;
|
|
||||||
use CreateAllTables;
|
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use AddVerificationToUsersTable;
|
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Filesystem\Filesystem;
|
||||||
use Illuminate\Support\Facades\Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Symfony\Component\Finder\SplFileInfo;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
class SetupControllerTest extends TestCase
|
class SetupControllerTest extends TestCase
|
||||||
{
|
{
|
||||||
use DatabaseTransactions;
|
use DatabaseTransactions;
|
||||||
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
$this->dropAllTables();
|
|
||||||
Mockery::close();
|
|
||||||
parent::tearDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function dropAllTables()
|
|
||||||
{
|
|
||||||
$tables = [
|
|
||||||
'user_closet',
|
|
||||||
'migrations',
|
|
||||||
'options',
|
|
||||||
'players',
|
|
||||||
'textures',
|
|
||||||
'users',
|
|
||||||
'reports',
|
|
||||||
'oauth_auth_codes',
|
|
||||||
'oauth_access_tokens',
|
|
||||||
'oauth_clients',
|
|
||||||
'oauth_personal_access_clients',
|
|
||||||
'oauth_refresh_tokens',
|
|
||||||
'notifications',
|
|
||||||
'jobs',
|
|
||||||
];
|
|
||||||
array_walk($tables, function ($table) {
|
|
||||||
Schema::dropIfExists($table);
|
|
||||||
});
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testWelcome()
|
public function testWelcome()
|
||||||
{
|
{
|
||||||
$this->dropAllTables();
|
$this->mock(Filesystem::class, function ($mock) {
|
||||||
|
$mock->shouldReceive('exists')
|
||||||
|
->with(storage_path('install.lock'))
|
||||||
|
->andReturn(false);
|
||||||
|
$mock->shouldReceive('exists')
|
||||||
|
->with(base_path('.env'))
|
||||||
|
->once()
|
||||||
|
->andReturn(false);
|
||||||
|
$mock->shouldReceive('copy')
|
||||||
|
->with(base_path('.env.example'), base_path('.env'))
|
||||||
|
->once()
|
||||||
|
->andReturn(true);
|
||||||
|
});
|
||||||
$this->get('/setup')->assertViewIs('setup.wizard.welcome');
|
$this->get('/setup')->assertViewIs('setup.wizard.welcome');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDatabase()
|
public function testDatabase()
|
||||||
{
|
{
|
||||||
$this->dropAllTables();
|
$this->mock(Filesystem::class, function ($mock) {
|
||||||
|
$mock->shouldReceive('exists')
|
||||||
|
->with(storage_path('install.lock'))
|
||||||
|
->atLeast(1)
|
||||||
|
->andReturn(false);
|
||||||
|
$mock->shouldReceive('put')
|
||||||
|
->with(storage_path('install.lock'), '')
|
||||||
|
->atLeast(1)
|
||||||
|
->andReturn(true);
|
||||||
|
});
|
||||||
|
|
||||||
$fake = [
|
$fake = [
|
||||||
'type' => env('DB_CONNECTION'),
|
'type' => env('DB_CONNECTION'),
|
||||||
'host' => env('DB_HOST'),
|
'host' => env('DB_HOST'),
|
||||||
|
|
@ -76,7 +62,17 @@ class SetupControllerTest extends TestCase
|
||||||
|
|
||||||
public function testReportDatabaseConnectionError()
|
public function testReportDatabaseConnectionError()
|
||||||
{
|
{
|
||||||
$this->dropAllTables();
|
$this->mock(Filesystem::class, function ($mock) {
|
||||||
|
$mock->shouldReceive('exists')
|
||||||
|
->with(storage_path('install.lock'))
|
||||||
|
->atLeast(1)
|
||||||
|
->andReturn(false);
|
||||||
|
$mock->shouldReceive('put')
|
||||||
|
->with(storage_path('install.lock'), '')
|
||||||
|
->atLeast(1)
|
||||||
|
->andReturn(true);
|
||||||
|
});
|
||||||
|
|
||||||
$this->post('/setup/database', ['type' => 'sqlite', 'host' => 'placeholder', 'db' => 'test'])
|
$this->post('/setup/database', ['type' => 'sqlite', 'host' => 'placeholder', 'db' => 'test'])
|
||||||
->assertSee(trans('setup.database.connection-error', [
|
->assertSee(trans('setup.database.connection-error', [
|
||||||
'type' => 'SQLite',
|
'type' => 'SQLite',
|
||||||
|
|
@ -84,18 +80,19 @@ class SetupControllerTest extends TestCase
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testInfo()
|
|
||||||
{
|
|
||||||
$this->dropAllTables();
|
|
||||||
$this->get('/setup/info')->assertViewIs('setup.wizard.info');
|
|
||||||
Artisan::call('migrate:refresh');
|
|
||||||
Schema::drop('users');
|
|
||||||
$this->get('/setup/info')->assertSee('already exist');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFinish()
|
public function testFinish()
|
||||||
{
|
{
|
||||||
$this->dropAllTables();
|
$this->mock(Filesystem::class, function ($mock) {
|
||||||
|
$mock->shouldReceive('exists')
|
||||||
|
->with(storage_path('install.lock'))
|
||||||
|
->atLeast(1)
|
||||||
|
->andReturn(false);
|
||||||
|
$mock->shouldReceive('put')
|
||||||
|
->with(storage_path('install.lock'), '')
|
||||||
|
->atLeast(1)
|
||||||
|
->andReturn(true);
|
||||||
|
});
|
||||||
|
|
||||||
// Without `email` field
|
// Without `email` field
|
||||||
$this->post('/setup/finish')
|
$this->post('/setup/finish')
|
||||||
->assertDontSee(trans('setup.wizard.finish.title'));
|
->assertDontSee(trans('setup.wizard.finish.title'));
|
||||||
|
|
@ -183,13 +180,7 @@ class SetupControllerTest extends TestCase
|
||||||
],
|
],
|
||||||
])
|
])
|
||||||
->once()
|
->once()
|
||||||
->andReturnUsing(function () {
|
->andReturn(true);
|
||||||
$migration = new CreateAllTables();
|
|
||||||
$migration->up();
|
|
||||||
|
|
||||||
$migration = new AddVerificationToUsersTable();
|
|
||||||
$migration->up();
|
|
||||||
});
|
|
||||||
$this->post('/setup/finish', [
|
$this->post('/setup/finish', [
|
||||||
'email' => 'a@b.c',
|
'email' => 'a@b.c',
|
||||||
'nickname' => 'nickname',
|
'nickname' => 'nickname',
|
||||||
|
|
@ -209,47 +200,41 @@ class SetupControllerTest extends TestCase
|
||||||
|
|
||||||
public function testUpdate()
|
public function testUpdate()
|
||||||
{
|
{
|
||||||
$this->actAs('superAdmin')
|
$this->mock(Filesystem::class, function ($mock) {
|
||||||
->get('/setup/update')
|
$mock->shouldReceive('exists')
|
||||||
->assertSee(trans('setup.locked.text'));
|
->with(storage_path('install.lock'))
|
||||||
|
->andReturn(true);
|
||||||
|
|
||||||
option(['version' => '0.1.0']);
|
$mock->shouldReceive('put')
|
||||||
$this->get('/setup/update')
|
->with(storage_path('install.lock'), '')
|
||||||
->assertSee(trans('setup.updates.welcome.title'));
|
->once()
|
||||||
}
|
->andReturn(true);
|
||||||
|
|
||||||
public function testDoUpdate()
|
$mock->shouldReceive('files')
|
||||||
{
|
->with(database_path('update_scripts'))
|
||||||
$current_version = config('app.version');
|
->once()
|
||||||
|
->andReturn([
|
||||||
|
new SplFileInfo('/1.0.0.php', '', ''),
|
||||||
|
new SplFileInfo('/99.0.0.php', '', ''),
|
||||||
|
new SplFileInfo('/100.0.0.php', '', ''),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$mock->shouldNotReceive('getRequire')->with('/1.0.0.php');
|
||||||
|
|
||||||
|
$mock->shouldReceive('getRequire')
|
||||||
|
->with('/99.0.0.php')
|
||||||
|
->once();
|
||||||
|
|
||||||
|
$mock->shouldReceive('getRequire')
|
||||||
|
->with('/100.0.0.php')
|
||||||
|
->once();
|
||||||
|
});
|
||||||
|
Artisan::shouldReceive('call')->with('view:clear')->once();
|
||||||
config(['app.version' => '100.0.0']);
|
config(['app.version' => '100.0.0']);
|
||||||
copy(
|
|
||||||
database_path('update_scripts/update-3.1-to-3.1.1.php'),
|
|
||||||
database_path("update_scripts/update-$current_version-to-100.0.0.php")
|
|
||||||
); // Just a fixture
|
|
||||||
|
|
||||||
config(['options.new_option' => 'value']);
|
$this->actAs('superAdmin')
|
||||||
$this->actAs('superAdmin')->get('/setup/exec-update')->assertViewHas('tips');
|
->get('/setup/exec-update')
|
||||||
$this->assertEquals('value', option('new_option'));
|
->assertViewIs('setup.updates.success');
|
||||||
$this->assertEquals('100.0.0', option('version'));
|
$this->assertEquals('100.0.0', option('version'));
|
||||||
unlink(database_path("update_scripts/update-$current_version-to-100.0.0.php"));
|
|
||||||
|
|
||||||
option(['version' => '3.0.0']); // Fake old version
|
|
||||||
$this->get('/setup/exec-update');
|
|
||||||
$this->assertEquals('100.0.0', option('version'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCheckDirectories()
|
|
||||||
{
|
|
||||||
Storage::shouldReceive('disk')
|
|
||||||
->with('root')
|
|
||||||
->andReturnSelf();
|
|
||||||
Storage::shouldReceive('has')
|
|
||||||
->with('storage/textures')
|
|
||||||
->andReturn(false);
|
|
||||||
Storage::shouldReceive('makeDirectory')
|
|
||||||
->with('storage/textures')
|
|
||||||
->andThrow(new Exception());
|
|
||||||
|
|
||||||
$this->assertFalse(\App\Http\Controllers\SetupController::checkDirectories());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,11 @@ class TestCase extends \Illuminate\Foundation\Testing\TestCase
|
||||||
|
|
||||||
Artisan::call('migrate:refresh');
|
Artisan::call('migrate:refresh');
|
||||||
|
|
||||||
|
$files = $app->make('files');
|
||||||
|
if (! $files->exists(storage_path('install.lock'))) {
|
||||||
|
$files->put(storage_path('install.lock'), '');
|
||||||
|
}
|
||||||
|
|
||||||
return $app;
|
return $app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,7 @@ class UpdateControllerTest extends TestCase
|
||||||
});
|
});
|
||||||
$this->mock(\Illuminate\Filesystem\Filesystem::class, function ($mock) {
|
$this->mock(\Illuminate\Filesystem\Filesystem::class, function ($mock) {
|
||||||
$mock->shouldReceive('delete')->with(storage_path('options/cache.php'))->once();
|
$mock->shouldReceive('delete')->with(storage_path('options/cache.php'))->once();
|
||||||
|
$mock->shouldReceive('exists')->with(storage_path('install.lock'))->andReturn(true);
|
||||||
});
|
});
|
||||||
$this->getJson('/admin/update/download?action=download')
|
$this->getJson('/admin/update/download?action=download')
|
||||||
->assertJson(['code' => 0, 'message' => trans('admin.update.complete')]);
|
->assertJson(['code' => 0, 'message' => trans('admin.update.complete')]);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user