Merge branch 'laravel-upgrade'
@ -89,7 +89,7 @@ REDIS_SERVERS=127.0.0.1:6379:0
|
|||||||
# Queue driver to use
|
# Queue driver to use
|
||||||
# Queue not really currently used but may be configurable in the future.
|
# Queue not really currently used but may be configurable in the future.
|
||||||
# Would advise not to change this for now.
|
# Would advise not to change this for now.
|
||||||
QUEUE_DRIVER=sync
|
QUEUE_CONNECTION=sync
|
||||||
|
|
||||||
# Storage system to use
|
# Storage system to use
|
||||||
# Can be 'local', 'local_secure' or 's3'
|
# Can be 'local', 'local_secure' or 's3'
|
||||||
|
3
.gitignore
vendored
@ -21,4 +21,5 @@ nbproject
|
|||||||
.buildpath
|
.buildpath
|
||||||
.project
|
.project
|
||||||
.settings/
|
.settings/
|
||||||
webpack-stats.json
|
webpack-stats.json
|
||||||
|
.phpunit.result.cache
|
15
.travis.yml
@ -1,9 +1,11 @@
|
|||||||
dist: trusty
|
dist: bionic
|
||||||
sudo: false
|
|
||||||
language: php
|
language: php
|
||||||
php:
|
php:
|
||||||
- 7.0.20
|
- '7.2'
|
||||||
- 7.1.9
|
- '7.3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
- mysql
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
@ -21,8 +23,7 @@ before_script:
|
|||||||
- php artisan migrate --force -n --database=mysql_testing
|
- php artisan migrate --force -n --database=mysql_testing
|
||||||
- php artisan db:seed --force -n --class=DummyContentSeeder --database=mysql_testing
|
- php artisan db:seed --force -n --class=DummyContentSeeder --database=mysql_testing
|
||||||
|
|
||||||
|
script: vendor/bin/phpunit --configuration phpunit.xml
|
||||||
|
|
||||||
after_failure:
|
after_failure:
|
||||||
- cat storage/logs/laravel.log
|
- cat storage/logs/laravel.log
|
||||||
|
|
||||||
script:
|
|
||||||
- phpunit
|
|
||||||
|
@ -13,7 +13,12 @@ class Application extends \Illuminate\Foundation\Application
|
|||||||
*/
|
*/
|
||||||
public function configPath($path = '')
|
public function configPath($path = '')
|
||||||
{
|
{
|
||||||
return $this->basePath.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR.'Config'.($path ? DIRECTORY_SEPARATOR.$path : $path);
|
return $this->basePath
|
||||||
|
. DIRECTORY_SEPARATOR
|
||||||
|
. 'app'
|
||||||
|
. DIRECTORY_SEPARATOR
|
||||||
|
. 'Config'
|
||||||
|
. ($path ? DIRECTORY_SEPARATOR.$path : $path);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -5,6 +5,7 @@ use BookStack\Auth\UserRepo;
|
|||||||
use BookStack\Exceptions\SocialDriverNotConfigured;
|
use BookStack\Exceptions\SocialDriverNotConfigured;
|
||||||
use BookStack\Exceptions\SocialSignInAccountNotUsed;
|
use BookStack\Exceptions\SocialSignInAccountNotUsed;
|
||||||
use BookStack\Exceptions\UserRegistrationException;
|
use BookStack\Exceptions\UserRegistrationException;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use Laravel\Socialite\Contracts\Factory as Socialite;
|
use Laravel\Socialite\Contracts\Factory as Socialite;
|
||||||
use Laravel\Socialite\Contracts\User as SocialUser;
|
use Laravel\Socialite\Contracts\User as SocialUser;
|
||||||
|
|
||||||
@ -104,6 +105,7 @@ class SocialAuthService
|
|||||||
$socialAccount = $this->socialAccount->where('driver_id', '=', $socialId)->first();
|
$socialAccount = $this->socialAccount->where('driver_id', '=', $socialId)->first();
|
||||||
$isLoggedIn = auth()->check();
|
$isLoggedIn = auth()->check();
|
||||||
$currentUser = user();
|
$currentUser = user();
|
||||||
|
$titleCaseDriver = Str::title($socialDriver);
|
||||||
|
|
||||||
// When a user is not logged in and a matching SocialAccount exists,
|
// When a user is not logged in and a matching SocialAccount exists,
|
||||||
// Simply log the user into the application.
|
// Simply log the user into the application.
|
||||||
@ -117,26 +119,26 @@ class SocialAuthService
|
|||||||
if ($isLoggedIn && $socialAccount === null) {
|
if ($isLoggedIn && $socialAccount === null) {
|
||||||
$this->fillSocialAccount($socialDriver, $socialUser);
|
$this->fillSocialAccount($socialDriver, $socialUser);
|
||||||
$currentUser->socialAccounts()->save($this->socialAccount);
|
$currentUser->socialAccounts()->save($this->socialAccount);
|
||||||
session()->flash('success', trans('settings.users_social_connected', ['socialAccount' => title_case($socialDriver)]));
|
session()->flash('success', trans('settings.users_social_connected', ['socialAccount' => $titleCaseDriver]));
|
||||||
return redirect($currentUser->getEditUrl());
|
return redirect($currentUser->getEditUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
// When a user is logged in and the social account exists and is already linked to the current user.
|
// When a user is logged in and the social account exists and is already linked to the current user.
|
||||||
if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id === $currentUser->id) {
|
if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id === $currentUser->id) {
|
||||||
session()->flash('error', trans('errors.social_account_existing', ['socialAccount' => title_case($socialDriver)]));
|
session()->flash('error', trans('errors.social_account_existing', ['socialAccount' => $titleCaseDriver]));
|
||||||
return redirect($currentUser->getEditUrl());
|
return redirect($currentUser->getEditUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
// When a user is logged in, A social account exists but the users do not match.
|
// When a user is logged in, A social account exists but the users do not match.
|
||||||
if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id != $currentUser->id) {
|
if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id != $currentUser->id) {
|
||||||
session()->flash('error', trans('errors.social_account_already_used_existing', ['socialAccount' => title_case($socialDriver)]));
|
session()->flash('error', trans('errors.social_account_already_used_existing', ['socialAccount' => $titleCaseDriver]));
|
||||||
return redirect($currentUser->getEditUrl());
|
return redirect($currentUser->getEditUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise let the user know this social account is not used by anyone.
|
// Otherwise let the user know this social account is not used by anyone.
|
||||||
$message = trans('errors.social_account_not_used', ['socialAccount' => title_case($socialDriver)]);
|
$message = trans('errors.social_account_not_used', ['socialAccount' => $titleCaseDriver]);
|
||||||
if (setting('registration-enabled')) {
|
if (setting('registration-enabled')) {
|
||||||
$message .= trans('errors.social_account_register_instructions', ['socialAccount' => title_case($socialDriver)]);
|
$message .= trans('errors.social_account_register_instructions', ['socialAccount' => $titleCaseDriver]);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new SocialSignInAccountNotUsed($message, '/login');
|
throw new SocialSignInAccountNotUsed($message, '/login');
|
||||||
@ -157,7 +159,7 @@ class SocialAuthService
|
|||||||
abort(404, trans('errors.social_driver_not_found'));
|
abort(404, trans('errors.social_driver_not_found'));
|
||||||
}
|
}
|
||||||
if (!$this->checkDriverConfigured($driver)) {
|
if (!$this->checkDriverConfigured($driver)) {
|
||||||
throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => title_case($socialDriver)]));
|
throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => Str::title($socialDriver)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $driver;
|
return $driver;
|
||||||
@ -244,7 +246,7 @@ class SocialAuthService
|
|||||||
public function detachSocialAccount($socialDriver)
|
public function detachSocialAccount($socialDriver)
|
||||||
{
|
{
|
||||||
user()->socialAccounts()->where('driver', '=', $socialDriver)->delete();
|
user()->socialAccounts()->where('driver', '=', $socialDriver)->delete();
|
||||||
session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => title_case($socialDriver)]));
|
session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => Str::title($socialDriver)]));
|
||||||
return redirect(user()->getEditUrl());
|
return redirect(user()->getEditUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ use BookStack\Exceptions\UserTokenExpiredException;
|
|||||||
use BookStack\Exceptions\UserTokenNotFoundException;
|
use BookStack\Exceptions\UserTokenNotFoundException;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Database\Connection as Database;
|
use Illuminate\Database\Connection as Database;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
|
||||||
class UserTokenService
|
class UserTokenService
|
||||||
@ -73,9 +74,9 @@ class UserTokenService
|
|||||||
*/
|
*/
|
||||||
protected function generateToken() : string
|
protected function generateToken() : string
|
||||||
{
|
{
|
||||||
$token = str_random(24);
|
$token = Str::random(24);
|
||||||
while ($this->tokenExists($token)) {
|
while ($this->tokenExists($token)) {
|
||||||
$token = str_random(25);
|
$token = Str::random(25);
|
||||||
}
|
}
|
||||||
return $token;
|
return $token;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use BookStack\Auth\Permissions;
|
use BookStack\Auth\Permissions;
|
||||||
use BookStack\Auth\Role;
|
use BookStack\Auth\Role;
|
||||||
use BookStack\Exceptions\PermissionsException;
|
use BookStack\Exceptions\PermissionsException;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class PermissionsRepo
|
class PermissionsRepo
|
||||||
{
|
{
|
||||||
@ -66,7 +67,7 @@ class PermissionsRepo
|
|||||||
$role->name = str_replace(' ', '-', strtolower($roleData['display_name']));
|
$role->name = str_replace(' ', '-', strtolower($roleData['display_name']));
|
||||||
// Prevent duplicate names
|
// Prevent duplicate names
|
||||||
while ($this->role->where('name', '=', $role->name)->count() > 0) {
|
while ($this->role->where('name', '=', $role->name)->count() > 0) {
|
||||||
$role->name .= strtolower(str_random(2));
|
$role->name .= strtolower(Str::random(2));
|
||||||
}
|
}
|
||||||
$role->save();
|
$role->save();
|
||||||
|
|
||||||
|
@ -57,6 +57,9 @@ return [
|
|||||||
// Application Fallback Locale
|
// Application Fallback Locale
|
||||||
'fallback_locale' => 'en',
|
'fallback_locale' => 'en',
|
||||||
|
|
||||||
|
// Faker Locale
|
||||||
|
'faker_locale' => 'en_GB',
|
||||||
|
|
||||||
// Enable right-to-left text control.
|
// Enable right-to-left text control.
|
||||||
'rtl' => false,
|
'rtl' => false,
|
||||||
|
|
||||||
@ -72,10 +75,6 @@ return [
|
|||||||
// Encryption cipher
|
// Encryption cipher
|
||||||
'cipher' => 'AES-256-CBC',
|
'cipher' => 'AES-256-CBC',
|
||||||
|
|
||||||
// Logging configuration
|
|
||||||
// Options: single, daily, syslog, errorlog
|
|
||||||
'log' => env('APP_LOGGING', 'single'),
|
|
||||||
|
|
||||||
// Application Services Provides
|
// Application Services Provides
|
||||||
'providers' => [
|
'providers' => [
|
||||||
|
|
||||||
@ -137,6 +136,7 @@ return [
|
|||||||
|
|
||||||
// Laravel
|
// Laravel
|
||||||
'App' => Illuminate\Support\Facades\App::class,
|
'App' => Illuminate\Support\Facades\App::class,
|
||||||
|
'Arr' => Illuminate\Support\Arr::class,
|
||||||
'Artisan' => Illuminate\Support\Facades\Artisan::class,
|
'Artisan' => Illuminate\Support\Facades\Artisan::class,
|
||||||
'Auth' => Illuminate\Support\Facades\Auth::class,
|
'Auth' => Illuminate\Support\Facades\Auth::class,
|
||||||
'Blade' => Illuminate\Support\Facades\Blade::class,
|
'Blade' => Illuminate\Support\Facades\Blade::class,
|
||||||
@ -166,6 +166,7 @@ return [
|
|||||||
'Schema' => Illuminate\Support\Facades\Schema::class,
|
'Schema' => Illuminate\Support\Facades\Schema::class,
|
||||||
'Session' => Illuminate\Support\Facades\Session::class,
|
'Session' => Illuminate\Support\Facades\Session::class,
|
||||||
'Storage' => Illuminate\Support\Facades\Storage::class,
|
'Storage' => Illuminate\Support\Facades\Storage::class,
|
||||||
|
'Str' => Illuminate\Support\Str::class,
|
||||||
'URL' => Illuminate\Support\Facades\URL::class,
|
'URL' => Illuminate\Support\Facades\URL::class,
|
||||||
'Validator' => Illuminate\Support\Facades\Validator::class,
|
'Validator' => Illuminate\Support\Facades\Validator::class,
|
||||||
'View' => Illuminate\Support\Facades\View::class,
|
'View' => Illuminate\Support\Facades\View::class,
|
||||||
|
@ -36,6 +36,7 @@ return [
|
|||||||
'api' => [
|
'api' => [
|
||||||
'driver' => 'token',
|
'driver' => 'token',
|
||||||
'provider' => 'users',
|
'provider' => 'users',
|
||||||
|
'hash' => false,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -24,9 +24,13 @@ return [
|
|||||||
|
|
||||||
'pusher' => [
|
'pusher' => [
|
||||||
'driver' => 'pusher',
|
'driver' => 'pusher',
|
||||||
'key' => env('PUSHER_KEY'),
|
'key' => env('PUSHER_APP_KEY'),
|
||||||
'secret' => env('PUSHER_SECRET'),
|
'secret' => env('PUSHER_APP_SECRET'),
|
||||||
'app_id' => env('PUSHER_APP_ID'),
|
'app_id' => env('PUSHER_APP_ID'),
|
||||||
|
'options' => [
|
||||||
|
'cluster' => env('PUSHER_APP_CLUSTER'),
|
||||||
|
'useTLS' => true,
|
||||||
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
'redis' => [
|
'redis' => [
|
||||||
@ -38,6 +42,11 @@ return [
|
|||||||
'driver' => 'log',
|
'driver' => 'log',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'null' => [
|
||||||
|
'driver' => 'null',
|
||||||
|
],
|
||||||
|
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -62,6 +62,6 @@ return [
|
|||||||
|
|
||||||
// Cache key prefix
|
// Cache key prefix
|
||||||
// Used to prevent collisions in shared cache systems.
|
// Used to prevent collisions in shared cache systems.
|
||||||
'prefix' => env('CACHE_PREFIX', 'bookstack'),
|
'prefix' => env('CACHE_PREFIX', 'bookstack_cache'),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -14,7 +14,7 @@ if (env('REDIS_SERVERS', false)) {
|
|||||||
|
|
||||||
$redisDefaults = ['host' => '127.0.0.1', 'port' => '6379', 'database' => '0', 'password' => null];
|
$redisDefaults = ['host' => '127.0.0.1', 'port' => '6379', 'database' => '0', 'password' => null];
|
||||||
$redisServers = explode(',', trim(env('REDIS_SERVERS', '127.0.0.1:6379:0'), ','));
|
$redisServers = explode(',', trim(env('REDIS_SERVERS', '127.0.0.1:6379:0'), ','));
|
||||||
$redisConfig = [];
|
$redisConfig = ['client' => 'predis'];
|
||||||
$cluster = count($redisServers) > 1;
|
$cluster = count($redisServers) > 1;
|
||||||
|
|
||||||
if ($cluster) {
|
if ($cluster) {
|
||||||
@ -59,14 +59,9 @@ return [
|
|||||||
// Many of those shown here are unsupported by BookStack.
|
// Many of those shown here are unsupported by BookStack.
|
||||||
'connections' => [
|
'connections' => [
|
||||||
|
|
||||||
'sqlite' => [
|
|
||||||
'driver' => 'sqlite',
|
|
||||||
'database' => storage_path('database.sqlite'),
|
|
||||||
'prefix' => '',
|
|
||||||
],
|
|
||||||
|
|
||||||
'mysql' => [
|
'mysql' => [
|
||||||
'driver' => 'mysql',
|
'driver' => 'mysql',
|
||||||
|
'url' => env('DATABASE_URL'),
|
||||||
'host' => $mysql_host,
|
'host' => $mysql_host,
|
||||||
'database' => env('DB_DATABASE', 'forge'),
|
'database' => env('DB_DATABASE', 'forge'),
|
||||||
'username' => env('DB_USERNAME', 'forge'),
|
'username' => env('DB_USERNAME', 'forge'),
|
||||||
@ -76,43 +71,28 @@ return [
|
|||||||
'charset' => 'utf8mb4',
|
'charset' => 'utf8mb4',
|
||||||
'collation' => 'utf8mb4_unicode_ci',
|
'collation' => 'utf8mb4_unicode_ci',
|
||||||
'prefix' => '',
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
'strict' => false,
|
'strict' => false,
|
||||||
'engine' => null,
|
'engine' => null,
|
||||||
|
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||||
|
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||||
|
]) : [],
|
||||||
],
|
],
|
||||||
|
|
||||||
'mysql_testing' => [
|
'mysql_testing' => [
|
||||||
'driver' => 'mysql',
|
'driver' => 'mysql',
|
||||||
|
'url' => env('TEST_DATABASE_URL'),
|
||||||
'host' => '127.0.0.1',
|
'host' => '127.0.0.1',
|
||||||
'database' => 'bookstack-test',
|
'database' => 'bookstack-test',
|
||||||
'username' => env('MYSQL_USER', 'bookstack-test'),
|
'username' => env('MYSQL_USER', 'bookstack-test'),
|
||||||
'password' => env('MYSQL_PASSWORD', 'bookstack-test'),
|
'password' => env('MYSQL_PASSWORD', 'bookstack-test'),
|
||||||
'charset' => 'utf8',
|
'charset' => 'utf8mb4',
|
||||||
'collation' => 'utf8_unicode_ci',
|
'collation' => 'utf8mb4_unicode_ci',
|
||||||
'prefix' => '',
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
'strict' => false,
|
'strict' => false,
|
||||||
],
|
],
|
||||||
|
|
||||||
'pgsql' => [
|
|
||||||
'driver' => 'pgsql',
|
|
||||||
'host' => env('DB_HOST', 'localhost'),
|
|
||||||
'database' => env('DB_DATABASE', 'forge'),
|
|
||||||
'username' => env('DB_USERNAME', 'forge'),
|
|
||||||
'password' => env('DB_PASSWORD', ''),
|
|
||||||
'charset' => 'utf8',
|
|
||||||
'prefix' => '',
|
|
||||||
'schema' => 'public',
|
|
||||||
],
|
|
||||||
|
|
||||||
'sqlsrv' => [
|
|
||||||
'driver' => 'sqlsrv',
|
|
||||||
'host' => env('DB_HOST', 'localhost'),
|
|
||||||
'database' => env('DB_DATABASE', 'forge'),
|
|
||||||
'username' => env('DB_USERNAME', 'forge'),
|
|
||||||
'password' => env('DB_PASSWORD', ''),
|
|
||||||
'charset' => 'utf8',
|
|
||||||
'prefix' => '',
|
|
||||||
],
|
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
// Migration Repository Table
|
// Migration Repository Table
|
||||||
|
37
app/Config/hashing.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hashing configuration options.
|
||||||
|
*
|
||||||
|
* Changes to these config files are not supported by BookStack and may break upon updates.
|
||||||
|
* Configuration should be altered via the `.env` file or environment variables.
|
||||||
|
* Do not edit this file unless you're happy to maintain any changes yourself.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
// Default Hash Driver
|
||||||
|
// This option controls the default hash driver that will be used to hash
|
||||||
|
// passwords for your application. By default, the bcrypt algorithm is used.
|
||||||
|
// Supported: "bcrypt", "argon", "argon2id"
|
||||||
|
'driver' => 'bcrypt',
|
||||||
|
|
||||||
|
// Bcrypt Options
|
||||||
|
// Here you may specify the configuration options that should be used when
|
||||||
|
// passwords are hashed using the Bcrypt algorithm. This will allow you
|
||||||
|
// to control the amount of time it takes to hash the given password.
|
||||||
|
'bcrypt' => [
|
||||||
|
'rounds' => env('BCRYPT_ROUNDS', 10),
|
||||||
|
],
|
||||||
|
|
||||||
|
// Argon Options
|
||||||
|
// Here you may specify the configuration options that should be used when
|
||||||
|
// passwords are hashed using the Argon algorithm. These will allow you
|
||||||
|
// to control the amount of time it takes to hash the given password.
|
||||||
|
'argon' => [
|
||||||
|
'memory' => 1024,
|
||||||
|
'threads' => 2,
|
||||||
|
'time' => 2,
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
82
app/Config/logging.php
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Monolog\Handler\NullHandler;
|
||||||
|
use Monolog\Handler\StreamHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logging configuration options.
|
||||||
|
*
|
||||||
|
* Changes to these config files are not supported by BookStack and may break upon updates.
|
||||||
|
* Configuration should be altered via the `.env` file or environment variables.
|
||||||
|
* Do not edit this file unless you're happy to maintain any changes yourself.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
// Default Log Channel
|
||||||
|
// This option defines the default log channel that gets used when writing
|
||||||
|
// messages to the logs. The name specified in this option should match
|
||||||
|
// one of the channels defined in the "channels" configuration array.
|
||||||
|
'default' => env('LOG_CHANNEL', 'single'),
|
||||||
|
|
||||||
|
// Log Channels
|
||||||
|
// Here you may configure the log channels for your application. Out of
|
||||||
|
// the box, Laravel uses the Monolog PHP logging library. This gives
|
||||||
|
// you a variety of powerful log handlers / formatters to utilize.
|
||||||
|
// Available Drivers: "single", "daily", "slack", "syslog",
|
||||||
|
// "errorlog", "monolog",
|
||||||
|
// "custom", "stack"
|
||||||
|
'channels' => [
|
||||||
|
'stack' => [
|
||||||
|
'driver' => 'stack',
|
||||||
|
'channels' => ['daily'],
|
||||||
|
'ignore_exceptions' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'single' => [
|
||||||
|
'driver' => 'single',
|
||||||
|
'path' => storage_path('logs/laravel.log'),
|
||||||
|
'level' => 'debug',
|
||||||
|
'days' => 14,
|
||||||
|
],
|
||||||
|
|
||||||
|
'daily' => [
|
||||||
|
'driver' => 'daily',
|
||||||
|
'path' => storage_path('logs/laravel.log'),
|
||||||
|
'level' => 'debug',
|
||||||
|
'days' => 7,
|
||||||
|
],
|
||||||
|
|
||||||
|
'slack' => [
|
||||||
|
'driver' => 'slack',
|
||||||
|
'url' => env('LOG_SLACK_WEBHOOK_URL'),
|
||||||
|
'username' => 'Laravel Log',
|
||||||
|
'emoji' => ':boom:',
|
||||||
|
'level' => 'critical',
|
||||||
|
],
|
||||||
|
|
||||||
|
'stderr' => [
|
||||||
|
'driver' => 'monolog',
|
||||||
|
'handler' => StreamHandler::class,
|
||||||
|
'with' => [
|
||||||
|
'stream' => 'php://stderr',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'syslog' => [
|
||||||
|
'driver' => 'syslog',
|
||||||
|
'level' => 'debug',
|
||||||
|
],
|
||||||
|
|
||||||
|
'errorlog' => [
|
||||||
|
'driver' => 'errorlog',
|
||||||
|
'level' => 'debug',
|
||||||
|
],
|
||||||
|
|
||||||
|
'null' => [
|
||||||
|
'driver' => 'monolog',
|
||||||
|
'handler' => NullHandler::class,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
@ -46,4 +46,10 @@ return [
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// Log Channel
|
||||||
|
// If you are using the "log" driver, you may specify the logging channel
|
||||||
|
// if you prefer to keep mail messages separate from other log entries
|
||||||
|
// for simpler reading. Otherwise, the default channel will be used.
|
||||||
|
'log_channel' => env('MAIL_LOG_CHANNEL'),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -12,11 +12,12 @@ return [
|
|||||||
|
|
||||||
// Default driver to use for the queue
|
// Default driver to use for the queue
|
||||||
// Options: null, sync, redis
|
// Options: null, sync, redis
|
||||||
'default' => env('QUEUE_DRIVER', 'sync'),
|
'default' => env('QUEUE_CONNECTION', 'sync'),
|
||||||
|
|
||||||
// Queue connection configuration
|
// Queue connection configuration
|
||||||
'connections' => [
|
'connections' => [
|
||||||
|
|
||||||
|
|
||||||
'sync' => [
|
'sync' => [
|
||||||
'driver' => 'sync',
|
'driver' => 'sync',
|
||||||
],
|
],
|
||||||
@ -25,38 +26,15 @@ return [
|
|||||||
'driver' => 'database',
|
'driver' => 'database',
|
||||||
'table' => 'jobs',
|
'table' => 'jobs',
|
||||||
'queue' => 'default',
|
'queue' => 'default',
|
||||||
'expire' => 60,
|
'retry_after' => 90,
|
||||||
],
|
|
||||||
|
|
||||||
'beanstalkd' => [
|
|
||||||
'driver' => 'beanstalkd',
|
|
||||||
'host' => 'localhost',
|
|
||||||
'queue' => 'default',
|
|
||||||
'ttr' => 60,
|
|
||||||
],
|
|
||||||
|
|
||||||
'sqs' => [
|
|
||||||
'driver' => 'sqs',
|
|
||||||
'key' => 'your-public-key',
|
|
||||||
'secret' => 'your-secret-key',
|
|
||||||
'queue' => 'your-queue-url',
|
|
||||||
'region' => 'us-east-1',
|
|
||||||
],
|
|
||||||
|
|
||||||
'iron' => [
|
|
||||||
'driver' => 'iron',
|
|
||||||
'host' => 'mq-aws-us-east-1.iron.io',
|
|
||||||
'token' => 'your-token',
|
|
||||||
'project' => 'your-project-id',
|
|
||||||
'queue' => 'your-queue-name',
|
|
||||||
'encrypt' => true,
|
|
||||||
],
|
],
|
||||||
|
|
||||||
'redis' => [
|
'redis' => [
|
||||||
'driver' => 'redis',
|
'driver' => 'redis',
|
||||||
'connection' => 'default',
|
'connection' => 'default',
|
||||||
'queue' => 'default',
|
'queue' => env('REDIS_QUEUE', 'default'),
|
||||||
'expire' => 60,
|
'retry_after' => 90,
|
||||||
|
'block_for' => null,
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
|
@ -22,23 +22,6 @@ return [
|
|||||||
// Callback URL for social authentication methods
|
// Callback URL for social authentication methods
|
||||||
'callback_url' => env('APP_URL', false),
|
'callback_url' => env('APP_URL', false),
|
||||||
|
|
||||||
'mailgun' => [
|
|
||||||
'domain' => '',
|
|
||||||
'secret' => '',
|
|
||||||
],
|
|
||||||
|
|
||||||
'ses' => [
|
|
||||||
'key' => '',
|
|
||||||
'secret' => '',
|
|
||||||
'region' => 'us-east-1',
|
|
||||||
],
|
|
||||||
|
|
||||||
'stripe' => [
|
|
||||||
'model' => \BookStack\Auth\User::class,
|
|
||||||
'key' => '',
|
|
||||||
'secret' => '',
|
|
||||||
],
|
|
||||||
|
|
||||||
'github' => [
|
'github' => [
|
||||||
'client_id' => env('GITHUB_APP_ID', false),
|
'client_id' => env('GITHUB_APP_ID', false),
|
||||||
'client_secret' => env('GITHUB_APP_SECRET', false),
|
'client_secret' => env('GITHUB_APP_SECRET', false),
|
||||||
|
@ -35,13 +35,18 @@ return [
|
|||||||
// Session database table, if database driver is in use
|
// Session database table, if database driver is in use
|
||||||
'table' => 'sessions',
|
'table' => 'sessions',
|
||||||
|
|
||||||
|
// Session Cache Store
|
||||||
|
// When using the "apc" or "memcached" session drivers, you may specify a
|
||||||
|
// cache store that should be used for these sessions. This value must
|
||||||
|
// correspond with one of the application's configured cache stores.
|
||||||
|
'store' => null,
|
||||||
|
|
||||||
// Session Sweeping Lottery
|
// Session Sweeping Lottery
|
||||||
// Some session drivers must manually sweep their storage location to get
|
// Some session drivers must manually sweep their storage location to get
|
||||||
// rid of old sessions from storage. Here are the chances that it will
|
// rid of old sessions from storage. Here are the chances that it will
|
||||||
// happen on a given request. By default, the odds are 2 out of 100.
|
// happen on a given request. By default, the odds are 2 out of 100.
|
||||||
'lottery' => [2, 100],
|
'lottery' => [2, 100],
|
||||||
|
|
||||||
|
|
||||||
// Session Cookie Name
|
// Session Cookie Name
|
||||||
// Here you may change the name of the cookie used to identify a session
|
// Here you may change the name of the cookie used to identify a session
|
||||||
// instance by ID. The name specified here will get used every time a
|
// instance by ID. The name specified here will get used every time a
|
||||||
|
@ -23,8 +23,9 @@ class BreadcrumbsViewComposer
|
|||||||
public function compose(View $view)
|
public function compose(View $view)
|
||||||
{
|
{
|
||||||
$crumbs = $view->getData()['crumbs'];
|
$crumbs = $view->getData()['crumbs'];
|
||||||
if (array_first($crumbs) instanceof Book) {
|
$firstCrumb = $crumbs[0] ?? null;
|
||||||
$shelf = $this->entityContextManager->getContextualShelfForBook(array_first($crumbs));
|
if ($firstCrumb instanceof Book) {
|
||||||
|
$shelf = $this->entityContextManager->getContextualShelfForBook($firstCrumb);
|
||||||
if ($shelf) {
|
if ($shelf) {
|
||||||
array_unshift($crumbs, $shelf);
|
array_unshift($crumbs, $shelf);
|
||||||
$view->with('crumbs', $crumbs);
|
$view->with('crumbs', $crumbs);
|
||||||
|
@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
|||||||
use Illuminate\Database\Query\Builder;
|
use Illuminate\Database\Query\Builder;
|
||||||
use Illuminate\Database\Query\JoinClause;
|
use Illuminate\Database\Query\JoinClause;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class SearchService
|
class SearchService
|
||||||
{
|
{
|
||||||
@ -210,7 +211,7 @@ class SearchService
|
|||||||
|
|
||||||
// Handle filters
|
// Handle filters
|
||||||
foreach ($terms['filters'] as $filterTerm => $filterValue) {
|
foreach ($terms['filters'] as $filterTerm => $filterValue) {
|
||||||
$functionName = camel_case('filter_' . $filterTerm);
|
$functionName = Str::camel('filter_' . $filterTerm);
|
||||||
if (method_exists($this, $functionName)) {
|
if (method_exists($this, $functionName)) {
|
||||||
$this->$functionName($entitySelect, $entity, $filterValue);
|
$this->$functionName($entitySelect, $entity, $filterValue);
|
||||||
}
|
}
|
||||||
@ -514,7 +515,7 @@ class SearchService
|
|||||||
|
|
||||||
protected function filterSortBy(EloquentBuilder $query, Entity $model, $input)
|
protected function filterSortBy(EloquentBuilder $query, Entity $model, $input)
|
||||||
{
|
{
|
||||||
$functionName = camel_case('sort_by_' . $input);
|
$functionName = Str::camel('sort_by_' . $input);
|
||||||
if (method_exists($this, $functionName)) {
|
if (method_exists($this, $functionName)) {
|
||||||
$this->$functionName($query, $model);
|
$this->$functionName($query, $model);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ use Illuminate\Http\RedirectResponse;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Illuminate\Routing\Redirector;
|
use Illuminate\Routing\Redirector;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use Laravel\Socialite\Contracts\User as SocialUser;
|
use Laravel\Socialite\Contracts\User as SocialUser;
|
||||||
use Validator;
|
use Validator;
|
||||||
|
|
||||||
@ -77,7 +79,7 @@ class RegisterController extends Controller
|
|||||||
return Validator::make($data, [
|
return Validator::make($data, [
|
||||||
'name' => 'required|min:2|max:255',
|
'name' => 'required|min:2|max:255',
|
||||||
'email' => 'required|email|max:255|unique:users',
|
'email' => 'required|email|max:255|unique:users',
|
||||||
'password' => 'required|min:6',
|
'password' => 'required|min:8',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +131,7 @@ class RegisterController extends Controller
|
|||||||
return User::create([
|
return User::create([
|
||||||
'name' => $data['name'],
|
'name' => $data['name'],
|
||||||
'email' => $data['email'],
|
'email' => $data['email'],
|
||||||
'password' => bcrypt($data['password']),
|
'password' => Hash::make($data['password']),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +263,7 @@ class RegisterController extends Controller
|
|||||||
$userData = [
|
$userData = [
|
||||||
'name' => $socialUser->getName(),
|
'name' => $socialUser->getName(),
|
||||||
'email' => $socialUser->getEmail(),
|
'email' => $socialUser->getEmail(),
|
||||||
'password' => str_random(30)
|
'password' => Str::random(30)
|
||||||
];
|
];
|
||||||
return $this->registerUser($userData, $socialAccount, $emailVerified);
|
return $this->registerUser($userData, $socialAccount, $emailVerified);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ namespace BookStack\Http\Controllers\Auth;
|
|||||||
|
|
||||||
use BookStack\Http\Controllers\Controller;
|
use BookStack\Http\Controllers\Controller;
|
||||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class ResetPasswordController extends Controller
|
class ResetPasswordController extends Controller
|
||||||
{
|
{
|
||||||
@ -36,10 +37,11 @@ class ResetPasswordController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Get the response for a successful password reset.
|
* Get the response for a successful password reset.
|
||||||
*
|
*
|
||||||
* @param string $response
|
* @param Request $request
|
||||||
|
* @param string $response
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
protected function sendResetResponse($response)
|
protected function sendResetResponse(Request $request, $response)
|
||||||
{
|
{
|
||||||
$message = trans('auth.reset_password_success');
|
$message = trans('auth.reset_password_success');
|
||||||
session()->flash('success', $message);
|
session()->flash('success', $message);
|
||||||
|
@ -62,7 +62,7 @@ class UserInviteController extends Controller
|
|||||||
public function setPassword(string $token, Request $request)
|
public function setPassword(string $token, Request $request)
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'password' => 'required|min:6'
|
'password' => 'required|min:8'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -8,6 +8,7 @@ use BookStack\Exceptions\UserUpdateException;
|
|||||||
use BookStack\Uploads\ImageRepo;
|
use BookStack\Uploads\ImageRepo;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class UserController extends Controller
|
class UserController extends Controller
|
||||||
{
|
{
|
||||||
@ -92,7 +93,7 @@ class UserController extends Controller
|
|||||||
$user = $this->user->fill($request->all());
|
$user = $this->user->fill($request->all());
|
||||||
|
|
||||||
if ($authMethod === 'standard') {
|
if ($authMethod === 'standard') {
|
||||||
$user->password = bcrypt($request->get('password', str_random(32)));
|
$user->password = bcrypt($request->get('password', Str::random(32)));
|
||||||
} elseif ($authMethod === 'ldap') {
|
} elseif ($authMethod === 'ldap') {
|
||||||
$user->external_auth_id = $request->get('external_auth_id');
|
$user->external_auth_id = $request->get('external_auth_id');
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ class Kernel extends HttpKernel
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $middleware = [
|
protected $middleware = [
|
||||||
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
|
\BookStack\Http\Middleware\CheckForMaintenanceMode::class,
|
||||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||||
\BookStack\Http\Middleware\TrimStrings::class,
|
\BookStack\Http\Middleware\TrimStrings::class,
|
||||||
\BookStack\Http\Middleware\TrustProxies::class,
|
\BookStack\Http\Middleware\TrustProxies::class,
|
||||||
@ -29,6 +29,7 @@ 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,
|
||||||
|
\Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
\BookStack\Http\Middleware\VerifyCsrfToken::class,
|
\BookStack\Http\Middleware\VerifyCsrfToken::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
\BookStack\Http\Middleware\Localization::class
|
\BookStack\Http\Middleware\Localization::class
|
||||||
|
17
app/Http/Middleware/CheckForMaintenanceMode.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BookStack\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
|
||||||
|
|
||||||
|
class CheckForMaintenanceMode extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The URIs that should be reachable while maintenance mode is enabled.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $except = [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
@ -16,17 +16,11 @@ class TrustProxies extends Middleware
|
|||||||
protected $proxies;
|
protected $proxies;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current proxy header mappings.
|
* The headers that should be used to detect proxies.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var int
|
||||||
*/
|
*/
|
||||||
protected $headers = [
|
protected $headers = Request::HEADER_X_FORWARDED_ALL;
|
||||||
Request::HEADER_FORWARDED => 'FORWARDED',
|
|
||||||
Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR',
|
|
||||||
Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST',
|
|
||||||
Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
|
|
||||||
Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the request, Set the correct user-configured proxy information.
|
* Handle the request, Set the correct user-configured proxy information.
|
||||||
|
@ -6,6 +6,13 @@ use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
|
|||||||
|
|
||||||
class VerifyCsrfToken extends Middleware
|
class VerifyCsrfToken extends Middleware
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $addHttpCookie = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The URIs that should be excluded from CSRF verification.
|
* The URIs that should be excluded from CSRF verification.
|
||||||
*
|
*
|
||||||
|
@ -13,7 +13,7 @@ class Attachment extends Ownable
|
|||||||
*/
|
*/
|
||||||
public function getFileName()
|
public function getFileName()
|
||||||
{
|
{
|
||||||
if (str_contains($this->name, '.')) {
|
if (strpos($this->name, '.') !== false) {
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
return $this->name . '.' . $this->extension;
|
return $this->name . '.' . $this->extension;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use BookStack\Exceptions\FileUploadException;
|
use BookStack\Exceptions\FileUploadException;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
|
|
||||||
class AttachmentService extends UploadService
|
class AttachmentService extends UploadService
|
||||||
@ -185,9 +186,9 @@ class AttachmentService extends UploadService
|
|||||||
$storage = $this->getStorage();
|
$storage = $this->getStorage();
|
||||||
$basePath = 'uploads/files/' . Date('Y-m-M') . '/';
|
$basePath = 'uploads/files/' . Date('Y-m-M') . '/';
|
||||||
|
|
||||||
$uploadFileName = str_random(16) . '.' . $uploadedFile->getClientOriginalExtension();
|
$uploadFileName = Str::random(16) . '.' . $uploadedFile->getClientOriginalExtension();
|
||||||
while ($storage->exists($basePath . $uploadFileName)) {
|
while ($storage->exists($basePath . $uploadFileName)) {
|
||||||
$uploadFileName = str_random(3) . $uploadFileName;
|
$uploadFileName = Str::random(3) . $uploadFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
$attachmentPath = $basePath . $uploadFileName;
|
$attachmentPath = $basePath . $uploadFileName;
|
||||||
|
@ -7,6 +7,7 @@ use DB;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Contracts\Cache\Repository as Cache;
|
use Illuminate\Contracts\Cache\Repository as Cache;
|
||||||
use Illuminate\Contracts\Filesystem\Factory as FileSystem;
|
use Illuminate\Contracts\Filesystem\Factory as FileSystem;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use Intervention\Image\Exception\NotSupportedException;
|
use Intervention\Image\Exception\NotSupportedException;
|
||||||
use Intervention\Image\ImageManager;
|
use Intervention\Image\ImageManager;
|
||||||
use phpDocumentor\Reflection\Types\Integer;
|
use phpDocumentor\Reflection\Types\Integer;
|
||||||
@ -140,12 +141,12 @@ class ImageService extends UploadService
|
|||||||
$imagePath = '/uploads/images/' . $type . '/' . Date('Y-m') . '/';
|
$imagePath = '/uploads/images/' . $type . '/' . Date('Y-m') . '/';
|
||||||
|
|
||||||
while ($storage->exists($imagePath . $imageName)) {
|
while ($storage->exists($imagePath . $imageName)) {
|
||||||
$imageName = str_random(3) . $imageName;
|
$imageName = Str::random(3) . $imageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fullPath = $imagePath . $imageName;
|
$fullPath = $imagePath . $imageName;
|
||||||
if ($secureUploads) {
|
if ($secureUploads) {
|
||||||
$fullPath = $imagePath . str_random(16) . '-' . $imageName;
|
$fullPath = $imagePath . Str::random(16) . '-' . $imageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -220,7 +221,7 @@ class ImageService extends UploadService
|
|||||||
|
|
||||||
$storage->put($thumbFilePath, $thumbData);
|
$storage->put($thumbFilePath, $thumbData);
|
||||||
$storage->setVisibility($thumbFilePath, 'public');
|
$storage->setVisibility($thumbFilePath, 'public');
|
||||||
$this->cache->put('images-' . $image->id . '-' . $thumbFilePath, $thumbFilePath, 60 * 72);
|
$this->cache->put('images-' . $image->id . '-' . $thumbFilePath, $thumbFilePath, 60 * 60 * 72);
|
||||||
|
|
||||||
return $this->getPublicUrl($thumbFilePath);
|
return $this->getPublicUrl($thumbFilePath);
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ function icon($name, $attrs = [])
|
|||||||
$attrString .= $attrName . '="' . $attr . '" ';
|
$attrString .= $attrName . '="' . $attr . '" ';
|
||||||
}
|
}
|
||||||
|
|
||||||
$iconPath = resource_path('assets/icons/' . $name . '.svg');
|
$iconPath = resource_path('icons/' . $name . '.svg');
|
||||||
$themeIconPath = theme_path('icons/' . $name . '.svg');
|
$themeIconPath = theme_path('icons/' . $name . '.svg');
|
||||||
if ($themeIconPath && file_exists($themeIconPath)) {
|
if ($themeIconPath && file_exists($themeIconPath)) {
|
||||||
$iconPath = $themeIconPath;
|
$iconPath = $themeIconPath;
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$app = new \BookStack\Application(
|
$app = new BookStack\Application(
|
||||||
realpath(__DIR__.'/../')
|
dirname(__DIR__)
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5,46 +5,46 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.0.5",
|
"php": "^7.2",
|
||||||
"ext-json": "*",
|
|
||||||
"ext-tidy": "*",
|
|
||||||
"ext-dom": "*",
|
|
||||||
"ext-xml": "*",
|
|
||||||
"ext-mbstring": "*",
|
|
||||||
"ext-gd": "*",
|
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"laravel/framework": "~5.5.44",
|
"ext-dom": "*",
|
||||||
"fideloper/proxy": "~3.3",
|
"ext-gd": "*",
|
||||||
"intervention/image": "^2.4",
|
"ext-json": "*",
|
||||||
"laravel/socialite": "3.0.x-dev",
|
"ext-mbstring": "*",
|
||||||
"league/flysystem-aws-s3-v3": "^1.0",
|
"ext-tidy": "*",
|
||||||
"barryvdh/laravel-dompdf": "^0.8.1",
|
"ext-xml": "*",
|
||||||
"predis/predis": "^1.1",
|
"barryvdh/laravel-dompdf": "^0.8.5",
|
||||||
|
"barryvdh/laravel-snappy": "^0.4.5",
|
||||||
|
"doctrine/dbal": "^2.9",
|
||||||
|
"fideloper/proxy": "^4.0",
|
||||||
"gathercontent/htmldiff": "^0.2.1",
|
"gathercontent/htmldiff": "^0.2.1",
|
||||||
"barryvdh/laravel-snappy": "^0.4.0",
|
"intervention/image": "^2.5",
|
||||||
"socialiteproviders/slack": "^3.0",
|
"laravel/framework": "^6.0",
|
||||||
|
"laravel/socialite": "^4.2",
|
||||||
|
"league/flysystem-aws-s3-v3": "^1.0",
|
||||||
|
"predis/predis": "^1.1",
|
||||||
|
"socialiteproviders/discord": "^2.0",
|
||||||
|
"socialiteproviders/gitlab": "^3.0",
|
||||||
"socialiteproviders/microsoft-azure": "^3.0",
|
"socialiteproviders/microsoft-azure": "^3.0",
|
||||||
"socialiteproviders/okta": "^1.0",
|
"socialiteproviders/okta": "^1.0",
|
||||||
"socialiteproviders/gitlab": "^3.0",
|
"socialiteproviders/slack": "^3.0",
|
||||||
"socialiteproviders/twitch": "^3.0",
|
"socialiteproviders/twitch": "^3.0"
|
||||||
"socialiteproviders/discord": "^2.0",
|
|
||||||
"doctrine/dbal": "^2.5"
|
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"filp/whoops": "~2.0",
|
"facade/ignition": "^1.4",
|
||||||
"fzaninotto/faker": "~1.4",
|
"fzaninotto/faker": "^1.4",
|
||||||
"mockery/mockery": "~1.0",
|
"mockery/mockery": "^1.0",
|
||||||
"phpunit/phpunit": "~6.0",
|
"phpunit/phpunit": "^8.0",
|
||||||
"symfony/css-selector": "3.1.*",
|
"nunomaduro/collision": "^3.0",
|
||||||
"symfony/dom-crawler": "3.1.*",
|
"laravel/browser-kit-testing": "^5.1",
|
||||||
"laravel/browser-kit-testing": "^2.0",
|
"barryvdh/laravel-ide-helper": "^2.6.4",
|
||||||
"barryvdh/laravel-ide-helper": "^2.4.1",
|
"barryvdh/laravel-debugbar": "^3.2.8",
|
||||||
"barryvdh/laravel-debugbar": "^3.1.0",
|
"squizlabs/php_codesniffer": "^3.4"
|
||||||
"squizlabs/php_codesniffer": "^3.2"
|
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": [
|
"classmap": [
|
||||||
"database"
|
"database/seeds",
|
||||||
|
"database/factories"
|
||||||
],
|
],
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"BookStack\\": "app/"
|
"BookStack\\": "app/"
|
||||||
@ -57,37 +57,45 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"post-root-package-install": [
|
"post-root-package-install": [
|
||||||
"php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||||
],
|
],
|
||||||
"post-create-project-cmd": [
|
"post-create-project-cmd": [
|
||||||
"php artisan key:generate"
|
"@php artisan key:generate --ansi"
|
||||||
],
|
],
|
||||||
"pre-update-cmd": [
|
"pre-update-cmd": [
|
||||||
"php -r \"!file_exists('bootstrap/cache/services.php') || @unlink('bootstrap/cache/services.php');\"",
|
"@php -r \"!file_exists('bootstrap/cache/services.php') || @unlink('bootstrap/cache/services.php');\"",
|
||||||
"php -r \"!file_exists('bootstrap/cache/compiled.php') || @unlink('bootstrap/cache/compiled.php');\""
|
"@php -r \"!file_exists('bootstrap/cache/compiled.php') || @unlink('bootstrap/cache/compiled.php');\""
|
||||||
],
|
],
|
||||||
"pre-install-cmd": [
|
"pre-install-cmd": [
|
||||||
"php -r \"!file_exists('bootstrap/cache/services.php') || @unlink('bootstrap/cache/services.php');\"",
|
"@php -r \"!file_exists('bootstrap/cache/services.php') || @unlink('bootstrap/cache/services.php');\"",
|
||||||
"php -r \"!file_exists('bootstrap/cache/compiled.php') || @unlink('bootstrap/cache/compiled.php');\""
|
"@php -r \"!file_exists('bootstrap/cache/compiled.php') || @unlink('bootstrap/cache/compiled.php');\""
|
||||||
],
|
],
|
||||||
"post-install-cmd": [
|
"post-install-cmd": [
|
||||||
"php artisan cache:clear",
|
"@php artisan cache:clear",
|
||||||
"php artisan view:clear"
|
"@php artisan view:clear"
|
||||||
],
|
],
|
||||||
"post-autoload-dump": [
|
"post-autoload-dump": [
|
||||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||||
"@php artisan package:discover"
|
"@php artisan package:discover --ansi"
|
||||||
],
|
],
|
||||||
"refresh-test-database": [
|
"refresh-test-database": [
|
||||||
"php artisan migrate:refresh --database=mysql_testing",
|
"@php artisan migrate:refresh --database=mysql_testing",
|
||||||
"php artisan db:seed --class=DummyContentSeeder --database=mysql_testing"
|
"@php artisan db:seed --class=DummyContentSeeder --database=mysql_testing"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"optimize-autoloader": true,
|
"optimize-autoloader": true,
|
||||||
"preferred-install": "dist",
|
"preferred-install": "dist",
|
||||||
|
"sort-packages": true,
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": "7.0.5"
|
"php": "7.2.0"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"dont-discover": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"prefer-stable": true
|
||||||
}
|
}
|
||||||
|
2974
composer.lock
generated
@ -15,8 +15,8 @@ $factory->define(\BookStack\Auth\User::class, function ($faker) {
|
|||||||
return [
|
return [
|
||||||
'name' => $faker->name,
|
'name' => $faker->name,
|
||||||
'email' => $faker->email,
|
'email' => $faker->email,
|
||||||
'password' => str_random(10),
|
'password' => Str::random(10),
|
||||||
'remember_token' => str_random(10),
|
'remember_token' => Str::random(10),
|
||||||
'email_confirmed' => 1
|
'email_confirmed' => 1
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
@ -24,7 +24,7 @@ $factory->define(\BookStack\Auth\User::class, function ($faker) {
|
|||||||
$factory->define(\BookStack\Entities\Bookshelf::class, function ($faker) {
|
$factory->define(\BookStack\Entities\Bookshelf::class, function ($faker) {
|
||||||
return [
|
return [
|
||||||
'name' => $faker->sentence,
|
'name' => $faker->sentence,
|
||||||
'slug' => str_random(10),
|
'slug' => Str::random(10),
|
||||||
'description' => $faker->paragraph
|
'description' => $faker->paragraph
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
@ -32,7 +32,7 @@ $factory->define(\BookStack\Entities\Bookshelf::class, function ($faker) {
|
|||||||
$factory->define(\BookStack\Entities\Book::class, function ($faker) {
|
$factory->define(\BookStack\Entities\Book::class, function ($faker) {
|
||||||
return [
|
return [
|
||||||
'name' => $faker->sentence,
|
'name' => $faker->sentence,
|
||||||
'slug' => str_random(10),
|
'slug' => Str::random(10),
|
||||||
'description' => $faker->paragraph
|
'description' => $faker->paragraph
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
@ -40,7 +40,7 @@ $factory->define(\BookStack\Entities\Book::class, function ($faker) {
|
|||||||
$factory->define(\BookStack\Entities\Chapter::class, function ($faker) {
|
$factory->define(\BookStack\Entities\Chapter::class, function ($faker) {
|
||||||
return [
|
return [
|
||||||
'name' => $faker->sentence,
|
'name' => $faker->sentence,
|
||||||
'slug' => str_random(10),
|
'slug' => Str::random(10),
|
||||||
'description' => $faker->paragraph
|
'description' => $faker->paragraph
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
@ -49,7 +49,7 @@ $factory->define(\BookStack\Entities\Page::class, function ($faker) {
|
|||||||
$html = '<p>' . implode('</p>', $faker->paragraphs(5)) . '</p>';
|
$html = '<p>' . implode('</p>', $faker->paragraphs(5)) . '</p>';
|
||||||
return [
|
return [
|
||||||
'name' => $faker->sentence,
|
'name' => $faker->sentence,
|
||||||
'slug' => str_random(10),
|
'slug' => Str::random(10),
|
||||||
'html' => $html,
|
'html' => $html,
|
||||||
'text' => strip_tags($html),
|
'text' => strip_tags($html),
|
||||||
'revision_count' => 1
|
'revision_count' => 1
|
||||||
|
@ -6,7 +6,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
class DatabaseSeeder extends Seeder
|
class DatabaseSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Run the database seeds.
|
* Seed the application's database.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use BookStack\Auth\Permissions\PermissionService;
|
||||||
|
use BookStack\Auth\Role;
|
||||||
|
use BookStack\Auth\User;
|
||||||
|
use BookStack\Entities\Bookshelf;
|
||||||
|
use BookStack\Entities\Chapter;
|
||||||
|
use BookStack\Entities\Page;
|
||||||
|
use BookStack\Entities\SearchService;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class DummyContentSeeder extends Seeder
|
class DummyContentSeeder extends Seeder
|
||||||
{
|
{
|
||||||
@ -12,39 +20,39 @@ class DummyContentSeeder extends Seeder
|
|||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
// Create an editor user
|
// Create an editor user
|
||||||
$editorUser = factory(\BookStack\Auth\User::class)->create();
|
$editorUser = factory(User::class)->create();
|
||||||
$editorRole = \BookStack\Auth\Role::getRole('editor');
|
$editorRole = Role::getRole('editor');
|
||||||
$editorUser->attachRole($editorRole);
|
$editorUser->attachRole($editorRole);
|
||||||
|
|
||||||
// Create a viewer user
|
// Create a viewer user
|
||||||
$viewerUser = factory(\BookStack\Auth\User::class)->create();
|
$viewerUser = factory(User::class)->create();
|
||||||
$role = \BookStack\Auth\Role::getRole('viewer');
|
$role = Role::getRole('viewer');
|
||||||
$viewerUser->attachRole($role);
|
$viewerUser->attachRole($role);
|
||||||
|
|
||||||
$byData = ['created_by' => $editorUser->id, 'updated_by' => $editorUser->id];
|
$byData = ['created_by' => $editorUser->id, 'updated_by' => $editorUser->id];
|
||||||
|
|
||||||
factory(\BookStack\Entities\Book::class, 5)->create($byData)
|
factory(\BookStack\Entities\Book::class, 5)->create($byData)
|
||||||
->each(function($book) use ($editorUser, $byData) {
|
->each(function($book) use ($editorUser, $byData) {
|
||||||
$chapters = factory(\BookStack\Entities\Chapter::class, 3)->create($byData)
|
$chapters = factory(Chapter::class, 3)->create($byData)
|
||||||
->each(function($chapter) use ($editorUser, $book, $byData){
|
->each(function($chapter) use ($editorUser, $book, $byData){
|
||||||
$pages = factory(\BookStack\Entities\Page::class, 3)->make(array_merge($byData, ['book_id' => $book->id]));
|
$pages = factory(Page::class, 3)->make(array_merge($byData, ['book_id' => $book->id]));
|
||||||
$chapter->pages()->saveMany($pages);
|
$chapter->pages()->saveMany($pages);
|
||||||
});
|
});
|
||||||
$pages = factory(\BookStack\Entities\Page::class, 3)->make($byData);
|
$pages = factory(Page::class, 3)->make($byData);
|
||||||
$book->chapters()->saveMany($chapters);
|
$book->chapters()->saveMany($chapters);
|
||||||
$book->pages()->saveMany($pages);
|
$book->pages()->saveMany($pages);
|
||||||
});
|
});
|
||||||
|
|
||||||
$largeBook = factory(\BookStack\Entities\Book::class)->create(array_merge($byData, ['name' => 'Large book' . str_random(10)]));
|
$largeBook = factory(\BookStack\Entities\Book::class)->create(array_merge($byData, ['name' => 'Large book' . Str::random(10)]));
|
||||||
$pages = factory(\BookStack\Entities\Page::class, 200)->make($byData);
|
$pages = factory(Page::class, 200)->make($byData);
|
||||||
$chapters = factory(\BookStack\Entities\Chapter::class, 50)->make($byData);
|
$chapters = factory(Chapter::class, 50)->make($byData);
|
||||||
$largeBook->pages()->saveMany($pages);
|
$largeBook->pages()->saveMany($pages);
|
||||||
$largeBook->chapters()->saveMany($chapters);
|
$largeBook->chapters()->saveMany($chapters);
|
||||||
|
|
||||||
$shelves = factory(\BookStack\Entities\Bookshelf::class, 10)->create($byData);
|
$shelves = factory(Bookshelf::class, 10)->create($byData);
|
||||||
$largeBook->shelves()->attach($shelves->pluck('id'));
|
$largeBook->shelves()->attach($shelves->pluck('id'));
|
||||||
|
|
||||||
app(\BookStack\Auth\Permissions\PermissionService::class)->buildJointPermissions();
|
app(PermissionService::class)->buildJointPermissions();
|
||||||
app(\BookStack\Entities\SearchService::class)->indexAllEntities();
|
app(SearchService::class)->indexAllEntities();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use BookStack\Auth\Permissions\PermissionService;
|
||||||
|
use BookStack\Auth\Role;
|
||||||
|
use BookStack\Auth\User;
|
||||||
|
use BookStack\Entities\Chapter;
|
||||||
|
use BookStack\Entities\Page;
|
||||||
|
use BookStack\Entities\SearchService;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class LargeContentSeeder extends Seeder
|
class LargeContentSeeder extends Seeder
|
||||||
{
|
{
|
||||||
@ -12,16 +19,16 @@ class LargeContentSeeder extends Seeder
|
|||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
// Create an editor user
|
// Create an editor user
|
||||||
$editorUser = factory(\BookStack\Auth\User::class)->create();
|
$editorUser = factory(User::class)->create();
|
||||||
$editorRole = \BookStack\Auth\Role::getRole('editor');
|
$editorRole = Role::getRole('editor');
|
||||||
$editorUser->attachRole($editorRole);
|
$editorUser->attachRole($editorRole);
|
||||||
|
|
||||||
$largeBook = factory(\BookStack\Entities\Book::class)->create(['name' => 'Large book' . str_random(10), 'created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
|
$largeBook = factory(\BookStack\Entities\Book::class)->create(['name' => 'Large book' . Str::random(10), 'created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
|
||||||
$pages = factory(\BookStack\Entities\Page::class, 200)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
|
$pages = factory(Page::class, 200)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
|
||||||
$chapters = factory(\BookStack\Entities\Chapter::class, 50)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
|
$chapters = factory(Chapter::class, 50)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
|
||||||
$largeBook->pages()->saveMany($pages);
|
$largeBook->pages()->saveMany($pages);
|
||||||
$largeBook->chapters()->saveMany($chapters);
|
$largeBook->chapters()->saveMany($chapters);
|
||||||
app(\BookStack\Auth\Permissions\PermissionService::class)->buildJointPermissions();
|
app(PermissionService::class)->buildJointPermissions();
|
||||||
app(\BookStack\Entities\SearchService::class)->indexAllEntities();
|
app(SearchService::class)->indexAllEntities();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
59
phpunit.xml
@ -7,8 +7,7 @@
|
|||||||
convertNoticesToExceptions="true"
|
convertNoticesToExceptions="true"
|
||||||
convertWarningsToExceptions="true"
|
convertWarningsToExceptions="true"
|
||||||
processIsolation="false"
|
processIsolation="false"
|
||||||
stopOnFailure="false"
|
stopOnFailure="false">
|
||||||
syntaxCheck="false">
|
|
||||||
<testsuites>
|
<testsuites>
|
||||||
<testsuite name="Application Test Suite">
|
<testsuite name="Application Test Suite">
|
||||||
<directory>./tests/</directory>
|
<directory>./tests/</directory>
|
||||||
@ -20,32 +19,34 @@
|
|||||||
</whitelist>
|
</whitelist>
|
||||||
</filter>
|
</filter>
|
||||||
<php>
|
<php>
|
||||||
<env name="APP_ENV" value="testing"/>
|
<server name="APP_ENV" value="testing"/>
|
||||||
<env name="APP_DEBUG" value="false"/>
|
<server name="APP_DEBUG" value="false"/>
|
||||||
<env name="APP_LANG" value="en"/>
|
<server name="APP_LANG" value="en"/>
|
||||||
<env name="APP_AUTO_LANG_PUBLIC" value="true"/>
|
<server name="APP_AUTO_LANG_PUBLIC" value="true"/>
|
||||||
<env name="CACHE_DRIVER" value="array"/>
|
<server name="CACHE_DRIVER" value="array"/>
|
||||||
<env name="SESSION_DRIVER" value="array"/>
|
<server name="SESSION_DRIVER" value="array"/>
|
||||||
<env name="QUEUE_DRIVER" value="sync"/>
|
<server name="QUEUE_CONNECTION" value="sync"/>
|
||||||
<env name="DB_CONNECTION" value="mysql_testing"/>
|
<server name="DB_CONNECTION" value="mysql_testing"/>
|
||||||
<env name="MAIL_DRIVER" value="log"/>
|
<server name="BCRYPT_ROUNDS" value="4"/>
|
||||||
<env name="AUTH_METHOD" value="standard"/>
|
<server name="MAIL_DRIVER" value="array"/>
|
||||||
<env name="DISABLE_EXTERNAL_SERVICES" value="true"/>
|
<server name="LOG_CHANNEL" value="null"/>
|
||||||
<env name="AVATAR_URL" value=""/>
|
<server name="AUTH_METHOD" value="standard"/>
|
||||||
<env name="LDAP_VERSION" value="3"/>
|
<server name="DISABLE_EXTERNAL_SERVICES" value="true"/>
|
||||||
<env name="STORAGE_TYPE" value="local"/>
|
<server name="AVATAR_URL" value=""/>
|
||||||
<env name="STORAGE_ATTACHMENT_TYPE" value="local"/>
|
<server name="LDAP_VERSION" value="3"/>
|
||||||
<env name="STORAGE_IMAGE_TYPE" value="local"/>
|
<server name="STORAGE_TYPE" value="local"/>
|
||||||
<env name="GITHUB_APP_ID" value="aaaaaaaaaaaaaa"/>
|
<server name="STORAGE_ATTACHMENT_TYPE" value="local"/>
|
||||||
<env name="GITHUB_APP_SECRET" value="aaaaaaaaaaaaaa"/>
|
<server name="STORAGE_IMAGE_TYPE" value="local"/>
|
||||||
<env name="GITHUB_AUTO_REGISTER" value=""/>
|
<server name="GITHUB_APP_ID" value="aaaaaaaaaaaaaa"/>
|
||||||
<env name="GITHUB_AUTO_CONFIRM_EMAIL" value=""/>
|
<server name="GITHUB_APP_SECRET" value="aaaaaaaaaaaaaa"/>
|
||||||
<env name="GOOGLE_APP_ID" value="aaaaaaaaaaaaaa"/>
|
<server name="GITHUB_AUTO_REGISTER" value=""/>
|
||||||
<env name="GOOGLE_APP_SECRET" value="aaaaaaaaaaaaaa"/>
|
<server name="GITHUB_AUTO_CONFIRM_EMAIL" value=""/>
|
||||||
<env name="GOOGLE_AUTO_REGISTER" value=""/>
|
<server name="GOOGLE_APP_ID" value="aaaaaaaaaaaaaa"/>
|
||||||
<env name="GOOGLE_AUTO_CONFIRM_EMAIL" value=""/>
|
<server name="GOOGLE_APP_SECRET" value="aaaaaaaaaaaaaa"/>
|
||||||
<env name="GOOGLE_SELECT_ACCOUNT" value=""/>
|
<server name="GOOGLE_AUTO_REGISTER" value=""/>
|
||||||
<env name="APP_URL" value="http://bookstack.dev"/>
|
<server name="GOOGLE_AUTO_CONFIRM_EMAIL" value=""/>
|
||||||
<env name="DEBUGBAR_ENABLED" value="false"/>
|
<server name="GOOGLE_SELECT_ACCOUNT" value=""/>
|
||||||
|
<server name="APP_URL" value="http://bookstack.dev"/>
|
||||||
|
<server name="DEBUGBAR_ENABLED" value="false"/>
|
||||||
</php>
|
</php>
|
||||||
</phpunit>
|
</phpunit>
|
||||||
|
28
public/web.config
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<!--
|
||||||
|
Rewrites requires Microsoft URL Rewrite Module for IIS
|
||||||
|
Download: https://www.microsoft.com/en-us/download/details.aspx?id=47337
|
||||||
|
Debug Help: https://docs.microsoft.com/en-us/iis/extensions/url-rewrite-module/using-failed-request-tracing-to-trace-rewrite-rules
|
||||||
|
-->
|
||||||
|
<configuration>
|
||||||
|
<system.webServer>
|
||||||
|
<rewrite>
|
||||||
|
<rules>
|
||||||
|
<rule name="Imported Rule 1" stopProcessing="true">
|
||||||
|
<match url="^(.*)/$" ignoreCase="false" />
|
||||||
|
<conditions>
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
|
||||||
|
</conditions>
|
||||||
|
<action type="Redirect" redirectType="Permanent" url="/{R:1}" />
|
||||||
|
</rule>
|
||||||
|
<rule name="Imported Rule 2" stopProcessing="true">
|
||||||
|
<match url="^" ignoreCase="false" />
|
||||||
|
<conditions>
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
|
||||||
|
</conditions>
|
||||||
|
<action type="Rewrite" url="index.php" />
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
</rewrite>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
Before Width: | Height: | Size: 284 B After Width: | Height: | Size: 284 B |
Before Width: | Height: | Size: 166 B After Width: | Height: | Size: 166 B |
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
Before Width: | Height: | Size: 258 B After Width: | Height: | Size: 258 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 541 B After Width: | Height: | Size: 541 B |
Before Width: | Height: | Size: 871 B After Width: | Height: | Size: 871 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 906 B After Width: | Height: | Size: 906 B |
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 392 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 392 B |
Before Width: | Height: | Size: 746 B After Width: | Height: | Size: 746 B |
Before Width: | Height: | Size: 186 B After Width: | Height: | Size: 186 B |
Before Width: | Height: | Size: 227 B After Width: | Height: | Size: 227 B |
Before Width: | Height: | Size: 416 B After Width: | Height: | Size: 416 B |
Before Width: | Height: | Size: 373 B After Width: | Height: | Size: 373 B |
Before Width: | Height: | Size: 301 B After Width: | Height: | Size: 301 B |
Before Width: | Height: | Size: 140 B After Width: | Height: | Size: 140 B |
Before Width: | Height: | Size: 197 B After Width: | Height: | Size: 197 B |
Before Width: | Height: | Size: 216 B After Width: | Height: | Size: 216 B |
Before Width: | Height: | Size: 133 B After Width: | Height: | Size: 133 B |
Before Width: | Height: | Size: 280 B After Width: | Height: | Size: 280 B |
Before Width: | Height: | Size: 243 B After Width: | Height: | Size: 243 B |
Before Width: | Height: | Size: 151 B After Width: | Height: | Size: 151 B |
Before Width: | Height: | Size: 157 B After Width: | Height: | Size: 157 B |
Before Width: | Height: | Size: 161 B After Width: | Height: | Size: 161 B |
Before Width: | Height: | Size: 172 B After Width: | Height: | Size: 172 B |
Before Width: | Height: | Size: 227 B After Width: | Height: | Size: 227 B |
Before Width: | Height: | Size: 248 B After Width: | Height: | Size: 248 B |
Before Width: | Height: | Size: 211 B After Width: | Height: | Size: 211 B |
Before Width: | Height: | Size: 298 B After Width: | Height: | Size: 298 B |
Before Width: | Height: | Size: 203 B After Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 364 B After Width: | Height: | Size: 364 B |
Before Width: | Height: | Size: 275 B After Width: | Height: | Size: 275 B |
Before Width: | Height: | Size: 247 B After Width: | Height: | Size: 247 B |
Before Width: | Height: | Size: 256 B After Width: | Height: | Size: 256 B |
Before Width: | Height: | Size: 221 B After Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 217 B After Width: | Height: | Size: 217 B |
Before Width: | Height: | Size: 213 B After Width: | Height: | Size: 213 B |
Before Width: | Height: | Size: 171 B After Width: | Height: | Size: 171 B |
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B |
Before Width: | Height: | Size: 246 B After Width: | Height: | Size: 246 B |
Before Width: | Height: | Size: 270 B After Width: | Height: | Size: 270 B |
Before Width: | Height: | Size: 264 B After Width: | Height: | Size: 264 B |
Before Width: | Height: | Size: 222 B After Width: | Height: | Size: 222 B |
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 282 B |
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 295 B |
Before Width: | Height: | Size: 213 B After Width: | Height: | Size: 213 B |
Before Width: | Height: | Size: 357 B After Width: | Height: | Size: 357 B |
Before Width: | Height: | Size: 537 B After Width: | Height: | Size: 537 B |
Before Width: | Height: | Size: 271 B After Width: | Height: | Size: 271 B |
Before Width: | Height: | Size: 270 B After Width: | Height: | Size: 270 B |
Before Width: | Height: | Size: 271 B After Width: | Height: | Size: 271 B |
Before Width: | Height: | Size: 267 B After Width: | Height: | Size: 267 B |
Before Width: | Height: | Size: 690 B After Width: | Height: | Size: 690 B |
Before Width: | Height: | Size: 252 B After Width: | Height: | Size: 252 B |
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 282 B |
Before Width: | Height: | Size: 431 B After Width: | Height: | Size: 431 B |