Merge branch 'laravel_upgrade'

This commit is contained in:
Dan Brown 2021-11-04 22:42:35 +00:00
commit c9c4dbcb5b
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
308 changed files with 3347 additions and 2831 deletions

View File

@ -13,12 +13,12 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
php: ['7.3', '7.4', '8.0']
php: ['7.3', '7.4', '8.0', '8.1']
steps:
- uses: actions/checkout@v1
- name: Setup PHP
uses: shivammathur/setup-php@b7d1d9c9a92d8d8463ce36d7f60da34d461724f8
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: gd, mbstring, json, curl, xml, mysql, ldap

View File

@ -13,12 +13,12 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
php: ['7.3', '7.4', '8.0']
php: ['7.3', '7.4', '8.0', '8.1']
steps:
- uses: actions/checkout@v1
- name: Setup PHP
uses: shivammathur/setup-php@b7d1d9c9a92d8d8463ce36d7f60da34d461724f8
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: gd, mbstring, json, curl, xml, mysql, ldap

View File

@ -61,7 +61,7 @@ class Activity extends Model
/**
* Checks if another Activity matches the general information of another.
*/
public function isSimilarTo(Activity $activityB): bool
public function isSimilarTo(self $activityB): bool
{
return [$this->type, $this->entity_type, $this->entity_id] === [$activityB->type, $activityB->entity_type, $activityB->entity_id];
}

View File

@ -4,6 +4,7 @@ namespace BookStack\Actions;
use BookStack\Model;
use BookStack\Traits\HasCreatorAndUpdater;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\MorphTo;
/**
@ -15,6 +16,7 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
*/
class Comment extends Model
{
use HasFactory;
use HasCreatorAndUpdater;
protected $fillable = ['text', 'parent_id'];

View File

@ -3,10 +3,13 @@
namespace BookStack\Actions;
use BookStack\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class Tag extends Model
{
use HasFactory;
protected $fillable = ['name', 'value', 'order'];
protected $hidden = ['id', 'entity_id', 'entity_type', 'created_at', 'updated_at'];

View File

@ -43,7 +43,7 @@ class ApiToken extends Model implements Loggable
}
/**
* @inheritdoc
* {@inheritdoc}
*/
public function logDescriptor(): string
{

View File

@ -42,7 +42,7 @@ class ApiTokenGuard implements Guard
}
/**
* @inheritDoc
* {@inheritdoc}
*/
public function user()
{
@ -152,7 +152,7 @@ class ApiTokenGuard implements Guard
}
/**
* @inheritDoc
* {@inheritdoc}
*/
public function validate(array $credentials = [])
{

View File

@ -7,6 +7,7 @@ use BookStack\Auth\Permissions\RolePermission;
use BookStack\Interfaces\Loggable;
use BookStack\Model;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
@ -23,6 +24,8 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
*/
class Role extends Model implements Loggable
{
use HasFactory;
protected $fillable = ['display_name', 'description', 'external_auth_id'];
/**
@ -83,7 +86,7 @@ class Role extends Model implements Loggable
/**
* Get the role of the specified display name.
*/
public static function getRole(string $displayName): ?Role
public static function getRole(string $displayName): ?self
{
return static::query()->where('display_name', '=', $displayName)->first();
}
@ -91,7 +94,7 @@ class Role extends Model implements Loggable
/**
* Get the role object for the specified system role.
*/
public static function getSystemRole(string $systemName): ?Role
public static function getSystemRole(string $systemName): ?self
{
return static::query()->where('system_name', '=', $systemName)->first();
}
@ -116,7 +119,7 @@ class Role extends Model implements Loggable
}
/**
* @inheritdoc
* {@inheritdoc}
*/
public function logDescriptor(): string
{

View File

@ -21,7 +21,7 @@ class SocialAccount extends Model implements Loggable
}
/**
* @inheritDoc
* {@inheritdoc}
*/
public function logDescriptor(): string
{

View File

@ -18,6 +18,7 @@ use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
@ -43,6 +44,7 @@ use Illuminate\Support\Collection;
*/
class User extends Model implements AuthenticatableContract, CanResetPasswordContract, Loggable, Sluggable
{
use HasFactory;
use Authenticatable;
use CanResetPassword;
use Notifiable;
@ -90,7 +92,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
/**
* Returns the default public user.
*/
public static function getDefault(): User
public static function getDefault(): self
{
if (!is_null(static::$defaultUser)) {
return static::$defaultUser;
@ -336,7 +338,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
}
/**
* @inheritdoc
* {@inheritdoc}
*/
public function logDescriptor(): string
{
@ -344,7 +346,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
}
/**
* @inheritDoc
* {@inheritdoc}
*/
public function refreshSlug(): string
{

11
app/Config/app.php Executable file → Normal file
View File

@ -143,7 +143,6 @@ return [
// Class aliases, Registered on application start
'aliases' => [
// Laravel
'App' => Illuminate\Support\Facades\App::class,
'Arr' => Illuminate\Support\Arr::class,
@ -155,21 +154,23 @@ return [
'Config' => Illuminate\Support\Facades\Config::class,
'Cookie' => Illuminate\Support\Facades\Cookie::class,
'Crypt' => Illuminate\Support\Facades\Crypt::class,
'Date' => Illuminate\Support\Facades\Date::class,
'DB' => Illuminate\Support\Facades\DB::class,
'Eloquent' => Illuminate\Database\Eloquent\Model::class,
'Event' => Illuminate\Support\Facades\Event::class,
'File' => Illuminate\Support\Facades\File::class,
'Gate' => Illuminate\Support\Facades\Gate::class,
'Hash' => Illuminate\Support\Facades\Hash::class,
'Input' => Illuminate\Support\Facades\Input::class,
'Inspiring' => Illuminate\Foundation\Inspiring::class,
'Http' => Illuminate\Support\Facades\Http::class,
'Lang' => Illuminate\Support\Facades\Lang::class,
'Log' => Illuminate\Support\Facades\Log::class,
'Mail' => Illuminate\Support\Facades\Mail::class,
'Notification' => Illuminate\Support\Facades\Notification::class,
'Password' => Illuminate\Support\Facades\Password::class,
'Queue' => Illuminate\Support\Facades\Queue::class,
'RateLimiter' => Illuminate\Support\Facades\RateLimiter::class,
'Redirect' => Illuminate\Support\Facades\Redirect::class,
'Redis' => Illuminate\Support\Facades\Redis::class,
// 'Redis' => Illuminate\Support\Facades\Redis::class,
'Request' => Illuminate\Support\Facades\Request::class,
'Response' => Illuminate\Support\Facades\Response::class,
'Route' => Illuminate\Support\Facades\Route::class,
@ -180,6 +181,8 @@ return [
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
// Laravel Packages
'Socialite' => Laravel\Socialite\Facades\Socialite::class,
// Third Party

View File

@ -10,7 +10,6 @@
return [
// Method of authentication to use
// Options: standard, ldap, saml2, oidc
'method' => env('AUTH_METHOD', 'standard'),
@ -45,7 +44,7 @@ return [
'provider' => 'external',
],
'api' => [
'driver' => 'api-token',
'driver' => 'api-token',
],
],
@ -58,10 +57,16 @@ return [
'driver' => 'eloquent',
'model' => \BookStack\Auth\User::class,
],
'external' => [
'driver' => 'external-users',
'model' => \BookStack\Auth\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
// Resetting Passwords
@ -78,4 +83,10 @@ return [
],
],
// Password Confirmation Timeout
// Here you may define the amount of seconds before a password confirmation
// times out and the user is prompted to re-enter their password via the
// confirmation screen. By default, the timeout lasts for three hours.
'password_timeout' => 10800,
];

View File

@ -1,51 +1,79 @@
<?php
/**
* Broadcasting configuration options.
* Caching 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.
*/
// MEMCACHED - Split out configuration into an array
if (env('CACHE_DRIVER') === 'memcached') {
$memcachedServerKeys = ['host', 'port', 'weight'];
$memcachedServers = explode(',', trim(env('MEMCACHED_SERVERS', '127.0.0.1:11211:100'), ','));
foreach ($memcachedServers as $index => $memcachedServer) {
$memcachedServerDetails = explode(':', $memcachedServer);
if (count($memcachedServerDetails) < 2) {
$memcachedServerDetails[] = '11211';
}
if (count($memcachedServerDetails) < 3) {
$memcachedServerDetails[] = '100';
}
$memcachedServers[$index] = array_combine($memcachedServerKeys, $memcachedServerDetails);
}
}
return [
// Default Broadcaster
// This option controls the default broadcaster that will be used by the
// framework when an event needs to be broadcast. This can be set to
// any of the connections defined in the "connections" array below.
'default' => env('BROADCAST_DRIVER', 'pusher'),
// Default cache store to use
// Can be overridden at cache call-time
'default' => env('CACHE_DRIVER', 'file'),
// Broadcast Connections
// Here you may define all of the broadcast connections that will be used
// to broadcast events to other systems or over websockets. Samples of
// each available type of connection are provided inside this array.
'connections' => [
// Available caches stores
'stores' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => true,
],
'apc' => [
'driver' => 'apc',
],
'array' => [
'driver' => 'array',
'serialize' => false,
],
'database' => [
'driver' => 'database',
'table' => 'cache',
'connection' => null,
'lock_connection' => null,
],
'file' => [
'driver' => 'file',
'path' => storage_path('framework/cache'),
],
'memcached' => [
'driver' => 'memcached',
'servers' => env('CACHE_DRIVER') === 'memcached' ? $memcachedServers : [],
'options' => [],
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'driver' => 'redis',
'connection' => 'default',
'lock_connection' => 'default',
],
'log' => [
'driver' => 'log',
],
'null' => [
'driver' => 'null',
'octane' => [
'driver' => 'octane',
],
],
// Cache key prefix
// Used to prevent collisions in shared cache systems.
'prefix' => env('CACHE_PREFIX', 'bookstack_cache'),
];

View File

@ -1,36 +1,36 @@
<?php
/**
* Caching 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.
*/
// MEMCACHED - Split out configuration into an array
if (env('CACHE_DRIVER') === 'memcached') {
$memcachedServerKeys = ['host', 'port', 'weight'];
$memcachedServers = explode(',', trim(env('MEMCACHED_SERVERS', '127.0.0.1:11211:100'), ','));
foreach ($memcachedServers as $index => $memcachedServer) {
$memcachedServerDetails = explode(':', $memcachedServer);
if (count($memcachedServerDetails) < 2) {
$memcachedServerDetails[] = '11211';
}
if (count($memcachedServerDetails) < 3) {
$memcachedServerDetails[] = '100';
}
$memcachedServers[$index] = array_combine($memcachedServerKeys, $memcachedServerDetails);
}
}
use Illuminate\Support\Str;
return [
// Default cache store to use
// Can be overridden at cache call-time
/*
|--------------------------------------------------------------------------
| Default Cache Store
|--------------------------------------------------------------------------
|
| This option controls the default cache connection that gets used while
| using this caching library. This connection is used when another is
| not explicitly specified when executing a given caching function.
|
*/
'default' => env('CACHE_DRIVER', 'file'),
// Available caches stores
/*
|--------------------------------------------------------------------------
| Cache Stores
|--------------------------------------------------------------------------
|
| Here you may define all of the cache "stores" for your application as
| well as their drivers. You may even define multiple stores for the
| same cache driver to group types of items stored in your caches.
|
| Supported drivers: "apc", "array", "database", "file",
| "memcached", "redis", "dynamodb", "octane", "null"
|
*/
'stores' => [
'apc' => [
@ -38,13 +38,15 @@ return [
],
'array' => [
'driver' => 'array',
'driver' => 'array',
'serialize' => false,
],
'database' => [
'driver' => 'database',
'table' => 'cache',
'connection' => null,
'driver' => 'database',
'table' => 'cache',
'connection' => null,
'lock_connection' => null,
],
'file' => [
@ -53,19 +55,50 @@ return [
],
'memcached' => [
'driver' => 'memcached',
'driver' => 'memcached',
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
'sasl' => [
env('MEMCACHED_USERNAME'),
env('MEMCACHED_PASSWORD'),
],
'options' => [
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
],
'servers' => env('CACHE_DRIVER') === 'memcached' ? $memcachedServers : [],
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'driver' => 'redis',
'connection' => 'default',
'lock_connection' => 'default',
],
'dynamodb' => [
'driver' => 'dynamodb',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
'endpoint' => env('DYNAMODB_ENDPOINT'),
],
'octane' => [
'driver' => 'octane',
],
],
// Cache key prefix
// Used to prevent collisions in shared cache systems.
'prefix' => env('CACHE_PREFIX', 'bookstack_cache'),
/*
|--------------------------------------------------------------------------
| Cache Key Prefix
|--------------------------------------------------------------------------
|
| When utilizing a RAM based store such as APC or Memcached, there might
| be other applications utilizing the same cache. So, we'll specify a
| value to get prefixed to all our keys so we can avoid collisions.
|
*/
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_') . '_cache'),
];

415
app/Config/clockwork.php Normal file
View File

@ -0,0 +1,415 @@
<?php
return [
/*
|------------------------------------------------------------------------------------------------------------------
| Enable Clockwork
|------------------------------------------------------------------------------------------------------------------
|
| Clockwork is enabled by default only when your application is in debug mode. Here you can explicitly enable or
| disable Clockwork. When disabled, no data is collected and the api and web ui are inactive.
|
*/
'enable' => env('CLOCKWORK_ENABLE', false),
/*
|------------------------------------------------------------------------------------------------------------------
| Features
|------------------------------------------------------------------------------------------------------------------
|
| You can enable or disable various Clockwork features here. Some features have additional settings (eg. slow query
| threshold for database queries).
|
*/
'features' => [
// Cache usage stats and cache queries including results
'cache' => [
'enabled' => true,
// Collect cache queries
'collect_queries' => true,
// Collect values from cache queries (high performance impact with a very high number of queries)
'collect_values' => false
],
// Database usage stats and queries
'database' => [
'enabled' => true,
// Collect database queries (high performance impact with a very high number of queries)
'collect_queries' => true,
// Collect details of models updates (high performance impact with a lot of model updates)
'collect_models_actions' => true,
// Collect details of retrieved models (very high performance impact with a lot of models retrieved)
'collect_models_retrieved' => false,
// Query execution time threshold in miliseconds after which the query will be marked as slow
'slow_threshold' => null,
// Collect only slow database queries
'slow_only' => false,
// Detect and report duplicate (N+1) queries
'detect_duplicate_queries' => false
],
// Dispatched events
'events' => [
'enabled' => true,
// Ignored events (framework events are ignored by default)
'ignored_events' => [
// App\Events\UserRegistered::class,
// 'user.registered'
],
],
// Laravel log (you can still log directly to Clockwork with laravel log disabled)
'log' => [
'enabled' => true
],
// Sent notifications
'notifications' => [
'enabled' => true,
],
// Performance metrics
'performance' => [
// Allow collecting of client metrics. Requires separate clockwork-browser npm package.
'client_metrics' => true
],
// Dispatched queue jobs
'queue' => [
'enabled' => true
],
// Redis commands
'redis' => [
'enabled' => true
],
// Routes list
'routes' => [
'enabled' => false,
// Collect only routes from particular namespaces (only application routes by default)
'only_namespaces' => [ 'App' ]
],
// Rendered views
'views' => [
'enabled' => true,
// Collect views including view data (high performance impact with a high number of views)
'collect_data' => false,
// Use Twig profiler instead of Laravel events for apps using laravel-twigbridge (more precise, but does
// not support collecting view data)
'use_twig_profiler' => false
]
],
/*
|------------------------------------------------------------------------------------------------------------------
| Enable web UI
|------------------------------------------------------------------------------------------------------------------
|
| Clockwork comes with a web UI accessibla via http://your.app/clockwork. Here you can enable or disable this
| feature. You can also set a custom path for the web UI.
|
*/
'web' => true,
/*
|------------------------------------------------------------------------------------------------------------------
| Enable toolbar
|------------------------------------------------------------------------------------------------------------------
|
| Clockwork can show a toolbar with basic metrics on all responses. Here you can enable or disable this feature.
| Requires a separate clockwork-browser npm library.
| For installation instructions see https://underground.works/clockwork/#docs-viewing-data
|
*/
'toolbar' => true,
/*
|------------------------------------------------------------------------------------------------------------------
| HTTP requests collection
|------------------------------------------------------------------------------------------------------------------
|
| Clockwork collects data about HTTP requests to your app. Here you can choose which requests should be collected.
|
*/
'requests' => [
// With on-demand mode enabled, Clockwork will only profile requests when the browser extension is open or you
// manually pass a "clockwork-profile" cookie or get/post data key.
// Optionally you can specify a "secret" that has to be passed as the value to enable profiling.
'on_demand' => false,
// Collect only errors (requests with HTTP 4xx and 5xx responses)
'errors_only' => false,
// Response time threshold in miliseconds after which the request will be marked as slow
'slow_threshold' => null,
// Collect only slow requests
'slow_only' => false,
// Sample the collected requests (eg. set to 100 to collect only 1 in 100 requests)
'sample' => false,
// List of URIs that should not be collected
'except' => [
'/horizon/.*', // Laravel Horizon requests
'/telescope/.*', // Laravel Telescope requests
'/_debugbar/.*', // Laravel DebugBar requests
],
// List of URIs that should be collected, any other URI will not be collected if not empty
'only' => [
// '/api/.*'
],
// Don't collect OPTIONS requests, mostly used in the CSRF pre-flight requests and are rarely of interest
'except_preflight' => true
],
/*
|------------------------------------------------------------------------------------------------------------------
| Artisan commands collection
|------------------------------------------------------------------------------------------------------------------
|
| Clockwork can collect data about executed artisan commands. Here you can enable and configure which commands
| should be collected.
|
*/
'artisan' => [
// Enable or disable collection of executed Artisan commands
'collect' => false,
// List of commands that should not be collected (built-in commands are not collected by default)
'except' => [
// 'inspire'
],
// List of commands that should be collected, any other command will not be collected if not empty
'only' => [
// 'inspire'
],
// Enable or disable collection of command output
'collect_output' => false,
// Enable or disable collection of built-in Laravel commands
'except_laravel_commands' => true
],
/*
|------------------------------------------------------------------------------------------------------------------
| Queue jobs collection
|------------------------------------------------------------------------------------------------------------------
|
| Clockwork can collect data about executed queue jobs. Here you can enable and configure which queue jobs should
| be collected.
|
*/
'queue' => [
// Enable or disable collection of executed queue jobs
'collect' => false,
// List of queue jobs that should not be collected
'except' => [
// App\Jobs\ExpensiveJob::class
],
// List of queue jobs that should be collected, any other queue job will not be collected if not empty
'only' => [
// App\Jobs\BuggyJob::class
]
],
/*
|------------------------------------------------------------------------------------------------------------------
| Tests collection
|------------------------------------------------------------------------------------------------------------------
|
| Clockwork can collect data about executed tests. Here you can enable and configure which tests should be
| collected.
|
*/
'tests' => [
// Enable or disable collection of ran tests
'collect' => false,
// List of tests that should not be collected
'except' => [
// Tests\Unit\ExampleTest::class
]
],
/*
|------------------------------------------------------------------------------------------------------------------
| Enable data collection when Clockwork is disabled
|------------------------------------------------------------------------------------------------------------------
|
| You can enable this setting to collect data even when Clockwork is disabled. Eg. for future analysis.
|
*/
'collect_data_always' => false,
/*
|------------------------------------------------------------------------------------------------------------------
| Metadata storage
|------------------------------------------------------------------------------------------------------------------
|
| Configure how is the metadata collected by Clockwork stored. Two options are available:
| - files - A simple fast storage implementation storing data in one-per-request files.
| - sql - Stores requests in a sql database. Supports MySQL, Postgresql, Sqlite and requires PDO.
|
*/
'storage' => 'files',
// Path where the Clockwork metadata is stored
'storage_files_path' => storage_path('clockwork'),
// Compress the metadata files using gzip, trading a little bit of performance for lower disk usage
'storage_files_compress' => false,
// SQL database to use, can be a name of database configured in database.php or a path to a sqlite file
'storage_sql_database' => storage_path('clockwork.sqlite'),
// SQL table name to use, the table is automatically created and udpated when needed
'storage_sql_table' => 'clockwork',
// Maximum lifetime of collected metadata in minutes, older requests will automatically be deleted, false to disable
'storage_expiration' => 60 * 24 * 7,
/*
|------------------------------------------------------------------------------------------------------------------
| Authentication
|------------------------------------------------------------------------------------------------------------------
|
| Clockwork can be configured to require authentication before allowing access to the collected data. This might be
| useful when the application is publicly accessible. Setting to true will enable a simple authentication with a
| pre-configured password. You can also pass a class name of a custom implementation.
|
*/
'authentication' => false,
// Password for the simple authentication
'authentication_password' => 'VerySecretPassword',
/*
|------------------------------------------------------------------------------------------------------------------
| Stack traces collection
|------------------------------------------------------------------------------------------------------------------
|
| Clockwork can collect stack traces for log messages and certain data like database queries. Here you can set
| whether to collect stack traces, limit the number of collected frames and set further configuration. Collecting
| long stack traces considerably increases metadata size.
|
*/
'stack_traces' => [
// Enable or disable collecting of stack traces
'enabled' => true,
// Limit the number of frames to be collected
'limit' => 10,
// List of vendor names to skip when determining caller, common vendors are automatically added
'skip_vendors' => [
// 'phpunit'
],
// List of namespaces to skip when determining caller
'skip_namespaces' => [
// 'Laravel'
],
// List of class names to skip when determining caller
'skip_classes' => [
// App\CustomLog::class
]
],
/*
|------------------------------------------------------------------------------------------------------------------
| Serialization
|------------------------------------------------------------------------------------------------------------------
|
| Clockwork serializes the collected data to json for storage and transfer. Here you can configure certain aspects
| of serialization. Serialization has a large effect on the cpu time and memory usage.
|
*/
// Maximum depth of serialized multi-level arrays and objects
'serialization_depth' => 10,
// A list of classes that will never be serialized (eg. a common service container class)
'serialization_blackbox' => [
\Illuminate\Container\Container::class,
\Illuminate\Foundation\Application::class,
],
/*
|------------------------------------------------------------------------------------------------------------------
| Register helpers
|------------------------------------------------------------------------------------------------------------------
|
| Clockwork comes with a "clock" global helper function. You can use this helper to quickly log something and to
| access the Clockwork instance.
|
*/
'register_helpers' => true,
/*
|------------------------------------------------------------------------------------------------------------------
| Send Headers for AJAX request
|------------------------------------------------------------------------------------------------------------------
|
| When trying to collect data the AJAX method can sometimes fail if it is missing required headers. For example, an
| API might require a version number using Accept headers to route the HTTP request to the correct codebase.
|
*/
'headers' => [
// 'Accept' => 'application/vnd.com.whatever.v1+json',
],
/*
|------------------------------------------------------------------------------------------------------------------
| Server-Timing
|------------------------------------------------------------------------------------------------------------------
|
| Clockwork supports the W3C Server Timing specification, which allows for collecting a simple performance metrics
| in a cross-browser way. Eg. in Chrome, your app, database and timeline event timings will be shown in the Dev
| Tools network tab. This setting specifies the max number of timeline events that will be sent. Setting to false
| will disable the feature.
|
*/
'server_timing' => 10
];

View File

@ -25,9 +25,6 @@ return [
// file storage service, such as s3, to store publicly accessible assets.
'url' => env('STORAGE_URL', false),
// Default Cloud Filesystem Disk
'cloud' => 's3',
// Available filesystem disks
// Only local, local_secure & s3 are supported by BookStack
'disks' => [
@ -35,6 +32,7 @@ return [
'local' => [
'driver' => 'local',
'root' => public_path(),
'visibility' => 'public',
],
'local_secure_attachments' => [
@ -45,6 +43,7 @@ return [
'local_secure_images' => [
'driver' => 'local',
'root' => storage_path('uploads/images/'),
'visibility' => 'public',
],
's3' => [
@ -59,4 +58,12 @@ return [
],
// Symbolic Links
// Here you may configure the symbolic links that will be created when the
// `storage:link` Artisan command is executed. The array keys should be
// the locations of the links and the values should be their targets.
'links' => [
public_path('storage') => storage_path('app/public'),
],
];

View File

@ -49,16 +49,9 @@ return [
'days' => 7,
],
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => 'Laravel Log',
'emoji' => ':boom:',
'level' => 'critical',
],
'stderr' => [
'driver' => 'monolog',
'level' => 'debug',
'handler' => StreamHandler::class,
'with' => [
'stream' => 'php://stderr',
@ -99,6 +92,10 @@ return [
'testing' => [
'driver' => 'testing',
],
'emergency' => [
'path' => storage_path('logs/laravel.log'),
],
],
// Failed Login Message

View File

@ -11,6 +11,8 @@
return [
// Mail driver to use.
// From Laravel 7+ this is MAIL_MAILER in laravel.
// Kept as MAIL_DRIVER in BookStack to prevent breaking change.
// Options: smtp, sendmail, log, array
'driver' => env('MAIL_DRIVER', 'smtp'),

View File

@ -22,25 +22,29 @@ return [
],
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
'after_commit' => false,
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => null,
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => null,
'after_commit' => false,
],
],
// Failed queue job logging
'failed' => [
'database' => 'mysql', 'table' => 'failed_jobs',
'driver' => 'database-uuids',
'database' => 'mysql',
'table' => 'failed_jobs',
],
];

View File

@ -4,6 +4,7 @@ namespace BookStack\Entities\Models;
use BookStack\Uploads\Image;
use Exception;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
@ -21,6 +22,8 @@ use Illuminate\Support\Collection;
*/
class Book extends Entity implements HasCoverImage
{
use HasFactory;
public $searchFactor = 2;
protected $fillable = ['name', 'description'];

View File

@ -3,11 +3,14 @@
namespace BookStack\Entities\Models;
use BookStack\Uploads\Image;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Bookshelf extends Entity implements HasCoverImage
{
use HasFactory;
protected $table = 'bookshelves';
public $searchFactor = 3;

View File

@ -2,6 +2,7 @@
namespace BookStack\Entities\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Support\Collection;
/**
@ -12,6 +13,8 @@ use Illuminate\Support\Collection;
*/
class Chapter extends BookChild
{
use HasFactory;
public $searchFactor = 1.3;
protected $fillable = ['name', 'description', 'priority', 'book_id'];

View File

@ -32,7 +32,7 @@ class Deletion extends Model implements Loggable
/**
* Create a new deletion record for the provided entity.
*/
public static function createForEntity(Entity $entity): Deletion
public static function createForEntity(Entity $entity): self
{
$record = (new self())->forceFill([
'deleted_by' => user()->id,

View File

@ -106,7 +106,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
* Compares this entity to another given entity.
* Matches by comparing class and id.
*/
public function matches(Entity $entity): bool
public function matches(self $entity): bool
{
return [get_class($this), $this->id] === [get_class($entity), $entity->id];
}
@ -114,7 +114,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
/**
* Checks if the current entity matches or contains the given.
*/
public function matchesOrContains(Entity $entity): bool
public function matchesOrContains(self $entity): bool
{
if ($this->matches($entity)) {
return true;
@ -270,7 +270,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
* This is the "static" parent and does not include dynamic
* relations such as shelves to books.
*/
public function getParent(): ?Entity
public function getParent(): ?self
{
if ($this instanceof Page) {
return $this->chapter_id ? $this->chapter()->withTrashed()->first() : $this->book()->withTrashed()->first();
@ -300,7 +300,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
}
/**
* @inheritdoc
* {@inheritdoc}
*/
public function refreshSlug(): string
{
@ -310,7 +310,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
}
/**
* @inheritdoc
* {@inheritdoc}
*/
public function favourites(): MorphMany
{

View File

@ -6,6 +6,7 @@ use BookStack\Entities\Tools\PageContent;
use BookStack\Uploads\Attachment;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Permissions;
@ -25,6 +26,8 @@ use Permissions;
*/
class Page extends BookChild
{
use HasFactory;
public static $listAttributes = ['name', 'id', 'slug', 'book_id', 'chapter_id', 'draft', 'template', 'text', 'created_at', 'updated_at', 'priority'];
public static $contentAttributes = ['name', 'id', 'slug', 'book_id', 'chapter_id', 'draft', 'template', 'html', 'text', 'created_at', 'updated_at', 'priority'];
@ -129,7 +132,7 @@ class Page extends BookChild
/**
* Get this page for JSON display.
*/
public function forJsonDisplay(): Page
public function forJsonDisplay(): self
{
$refreshed = $this->refresh()->unsetRelations()->load(['tags', 'createdBy', 'updatedBy', 'ownedBy']);
$refreshed->setHidden(array_diff($refreshed->getHidden(), ['html', 'markdown']));

View File

@ -29,7 +29,7 @@ class SearchOptions
/**
* Create a new instance from a search string.
*/
public static function fromString(string $search): SearchOptions
public static function fromString(string $search): self
{
$decoded = static::decode($search);
$instance = new static();
@ -45,7 +45,7 @@ class SearchOptions
* Will look for a classic string term and use that
* Otherwise we'll use the details from an advanced search form.
*/
public static function fromRequest(Request $request): SearchOptions
public static function fromRequest(Request $request): self
{
if (!$request->has('search') && !$request->has('term')) {
return static::fromString('');

View File

@ -196,7 +196,7 @@ class SearchRunner
$escapedOperators[] = preg_quote($operator);
}
return join('|', $escapedOperators);
return implode('|', $escapedOperators);
}
/**

View File

@ -9,6 +9,7 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Throwable;
class Handler extends ExceptionHandler
{
@ -27,6 +28,7 @@ class Handler extends ExceptionHandler
* @var array
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
@ -34,13 +36,13 @@ class Handler extends ExceptionHandler
/**
* Report or log an exception.
*
* @param Exception $exception
* @param \Throwable $exception
*
* @throws Exception
* @throws \Throwable
*
* @return void
*/
public function report(Exception $exception)
public function report(Throwable $exception)
{
parent::report($exception);
}
@ -53,7 +55,7 @@ class Handler extends ExceptionHandler
*
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
public function render($request, Throwable $e)
{
if ($this->isApiRequest($request)) {
return $this->renderApiException($e);

View File

@ -23,7 +23,7 @@ class NotifyException extends Exception implements Responsable
/**
* Send the response for this type of exception.
*
* @inheritdoc
* {@inheritdoc}
*/
public function toResponse($request)
{

View File

@ -20,7 +20,7 @@ class PrettyException extends Exception implements Responsable
/**
* Render a response for when this exception occurs.
*
* @inheritdoc
* {@inheritdoc}
*/
public function toResponse($request)
{

View File

@ -23,7 +23,7 @@ class StoppedAuthenticationException extends \Exception implements Responsable
}
/**
* @inheritdoc
* {@inheritdoc}
*/
public function toResponse($request)
{

View File

@ -176,7 +176,7 @@ class PageController extends Controller
{
$page = $this->pageRepo->getById($pageId);
$page->setHidden(array_diff($page->getHidden(), ['html', 'markdown']));
$page->addHidden(['book']);
$page->makeHidden(['book']);
return response()->json($page);
}

View File

@ -11,7 +11,7 @@ class Kernel extends HttpKernel
* These middleware are run during every request to your application.
*/
protected $middleware = [
\BookStack\Http\Middleware\CheckForMaintenanceMode::class,
\BookStack\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\BookStack\Http\Middleware\TrimStrings::class,
\BookStack\Http\Middleware\TrustProxies::class,

View File

@ -2,9 +2,9 @@
namespace BookStack\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware;
class CheckForMaintenanceMode extends Middleware
class PreventRequestsDuringMaintenance extends Middleware
{
/**
* The URIs that should be reachable while maintenance mode is enabled.

View File

@ -2,45 +2,31 @@
namespace BookStack\Http\Middleware;
use BookStack\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
*
* @return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null ...$guards
* @return mixed
*/
public function handle($request, Closure $next)
public function handle(Request $request, Closure $next, ...$guards)
{
$requireConfirmation = setting('registration-confirmation');
if ($this->auth->check() && (!$requireConfirmation || ($requireConfirmation && $this->auth->user()->email_confirmed))) {
return redirect('/');
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
}
return $next($request);
}
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace BookStack\Http\Middleware;
use Illuminate\Http\Middleware\TrustHosts as Middleware;
class TrustHosts extends Middleware
{
/**
* Get the host patterns that should be trusted.
*
* @return array
*/
public function hosts()
{
return [
$this->allSubdomainsOfApplicationUrl(),
];
}
}

View File

@ -3,7 +3,7 @@
namespace BookStack\Http\Middleware;
use Closure;
use Fideloper\Proxy\TrustProxies as Middleware;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
@ -20,7 +20,7 @@ class TrustProxies extends Middleware
*
* @var int
*/
protected $headers = Request::HEADER_X_FORWARDED_ALL;
protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_AWS_ELB;
/**
* Handle the request, Set the correct user-configured proxy information.

View File

@ -16,6 +16,7 @@ use BookStack\Util\CspService;
use GuzzleHttp\Client;
use Illuminate\Contracts\Cache\Repository;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\URL;
@ -60,6 +61,9 @@ class AppServiceProvider extends ServiceProvider
// View Composers
View::composer('entities.breadcrumbs', BreadcrumbsViewComposer::class);
// Set paginator to use bootstrap-style pagination
Paginator::useBootstrap();
}
/**

View File

@ -30,6 +30,5 @@ class EventServiceProvider extends ServiceProvider
*/
public function boot()
{
parent::boot();
}
}

View File

@ -2,11 +2,23 @@
namespace BookStack\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* The path to the "home" route for your application.
*
* This is used by Laravel authentication to redirect users after login.
*
* @var string
*/
public const HOME = '/';
/**
* This namespace is applied to the controller routes in your routes file.
*
@ -14,7 +26,6 @@ class RouteServiceProvider extends ServiceProvider
*
* @var string
*/
protected $namespace = 'BookStack\Http\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
@ -23,18 +34,12 @@ class RouteServiceProvider extends ServiceProvider
*/
public function boot()
{
parent::boot();
}
$this->configureRateLimiting();
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapWebRoutes();
$this->mapApiRoutes();
$this->routes(function () {
$this->mapWebRoutes();
$this->mapApiRoutes();
});
}
/**
@ -71,4 +76,16 @@ class RouteServiceProvider extends ServiceProvider
require base_path('routes/api.php');
});
}
/**
* Configure the rate limiters for the application.
*
* @return void
*/
protected function configureRateLimiting()
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
});
}
}

View File

@ -93,7 +93,7 @@ class Attachment extends Model
return $permissionService->filterRelatedEntity(
Page::class,
Attachment::query(),
self::query(),
'attachments',
'uploaded_to'
);

View File

@ -5,6 +5,7 @@ namespace BookStack\Uploads;
use BookStack\Entities\Models\Page;
use BookStack\Model;
use BookStack\Traits\HasCreatorAndUpdater;
use Illuminate\Database\Eloquent\Factories\HasFactory;
/**
* @property int $id
@ -18,6 +19,7 @@ use BookStack\Traits\HasCreatorAndUpdater;
*/
class Image extends Model
{
use HasFactory;
use HasCreatorAndUpdater;
protected $fillable = ['name'];

View File

@ -1,7 +1,10 @@
{
"name": "bookstackapp/bookstack",
"description": "BookStack documentation platform",
"keywords": ["BookStack", "Documentation"],
"keywords": [
"BookStack",
"Documentation"
],
"license": "MIT",
"type": "project",
"require": {
@ -16,48 +19,47 @@
"bacon/bacon-qr-code": "^2.0",
"barryvdh/laravel-dompdf": "^0.9.0",
"barryvdh/laravel-snappy": "^0.4.8",
"doctrine/dbal": "^2.12.1",
"fideloper/proxy": "^4.4.1",
"doctrine/dbal": "^3.1",
"filp/whoops": "^2.14",
"intervention/image": "^2.5.1",
"laravel/framework": "^6.20.33",
"laravel/socialite": "^5.1",
"league/commonmark": "^1.5",
"guzzlehttp/guzzle": "^7.4",
"intervention/image": "^2.7",
"laravel/framework": "^8.68",
"laravel/socialite": "^5.2",
"laravel/tinker": "^2.6",
"laravel/ui": "^3.3",
"league/commonmark": "^1.6",
"league/flysystem-aws-s3-v3": "^1.0.29",
"league/html-to-markdown": "^5.0.0",
"league/oauth2-client": "^2.6",
"nunomaduro/collision": "^3.1",
"onelogin/php-saml": "^4.0",
"phpseclib/phpseclib": "~3.0",
"pragmarx/google2fa": "^8.0",
"predis/predis": "^1.1.6",
"predis/predis": "^1.1",
"socialiteproviders/discord": "^4.1",
"socialiteproviders/gitlab": "^4.1",
"socialiteproviders/microsoft-azure": "^5.0.1",
"socialiteproviders/okta": "^4.1",
"socialiteproviders/slack": "^4.1",
"socialiteproviders/twitch": "^5.3",
"ssddanbrown/htmldiff": "^v1.0.1"
"ssddanbrown/htmldiff": "^1.0.1"
},
"require-dev": {
"barryvdh/laravel-debugbar": "^3.5.1",
"barryvdh/laravel-ide-helper": "^2.8.2",
"fakerphp/faker": "^1.13.0",
"mockery/mockery": "^1.3.3",
"phpunit/phpunit": "^9.5.3",
"symfony/dom-crawler": "^5.3"
"fakerphp/faker": "^1.16",
"itsgoingd/clockwork": "^5.1",
"mockery/mockery": "^1.4",
"phpunit/phpunit": "^9.5",
"symfony/dom-crawler": "^5.3",
"nunomaduro/collision": "^5.10"
},
"autoload": {
"classmap": [
"database/seeds",
"database/factories"
],
"psr-4": {
"BookStack\\": "app/"
"BookStack\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
},
"files": [
"app/helpers.php"
]
"files": [
"app/helpers.php"
]
},
"autoload-dev": {
"psr-4": {
@ -65,6 +67,10 @@
}
},
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
@ -78,10 +84,6 @@
"@php artisan cache:clear",
"@php artisan view:clear"
],
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
"refresh-test-database": [
"@php artisan migrate:refresh --database=mysql_testing",
"@php artisan db:seed --class=DummyContentSeeder --database=mysql_testing"

3144
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
<?php
namespace Database\Factories\Actions;
use Illuminate\Database\Eloquent\Factories\Factory;
class CommentFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = \BookStack\Actions\Comment::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
$text = $this->faker->paragraph(1);
$html = '<p>' . $text . '</p>';
return [
'html' => $html,
'text' => $text,
'parent_id' => null,
];
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Database\Factories\Actions;
use Illuminate\Database\Eloquent\Factories\Factory;
class TagFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = \BookStack\Actions\Tag::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->city,
'value' => $this->faker->sentence(3),
];
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Database\Factories\Auth;
use Illuminate\Database\Eloquent\Factories\Factory;
class RoleFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = \BookStack\Auth\Role::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'display_name' => $this->faker->sentence(3),
'description' => $this->faker->sentence(10),
];
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Database\Factories\Auth;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = \BookStack\Auth\User::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
$name = $this->faker->name;
return [
'name' => $name,
'email' => $this->faker->email,
'slug' => \Illuminate\Support\Str::slug($name . '-' . \Illuminate\Support\Str::random(5)),
'password' => Str::random(10),
'remember_token' => Str::random(10),
'email_confirmed' => 1,
];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Database\Factories\Entities\Models;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class BookFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = \BookStack\Entities\Models\Book::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->sentence,
'slug' => Str::random(10),
'description' => $this->faker->paragraph,
];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Database\Factories\Entities\Models;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class BookshelfFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = \BookStack\Entities\Models\Bookshelf::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->sentence,
'slug' => Str::random(10),
'description' => $this->faker->paragraph,
];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Database\Factories\Entities\Models;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class ChapterFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = \BookStack\Entities\Models\Chapter::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->sentence,
'slug' => Str::random(10),
'description' => $this->faker->paragraph,
];
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace Database\Factories\Entities\Models;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class PageFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = \BookStack\Entities\Models\Page::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
$html = '<p>' . implode('</p>', $this->faker->paragraphs(5)) . '</p>';
return [
'name' => $this->faker->sentence,
'slug' => Str::random(10),
'html' => $html,
'text' => strip_tags($html),
'revision_count' => 1,
];
}
}

View File

@ -1,96 +0,0 @@
<?php
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| Here you may define all of your model factories. Model factories give
| you a convenient way to create models for testing and seeding your
| database. Just tell the factory how a default model should look.
|
*/
$factory->define(\BookStack\Auth\User::class, function ($faker) {
$name = $faker->name;
return [
'name' => $name,
'email' => $faker->email,
'slug' => \Illuminate\Support\Str::slug($name . '-' . \Illuminate\Support\Str::random(5)),
'password' => Str::random(10),
'remember_token' => Str::random(10),
'email_confirmed' => 1,
];
});
$factory->define(\BookStack\Entities\Models\Bookshelf::class, function ($faker) {
return [
'name' => $faker->sentence,
'slug' => Str::random(10),
'description' => $faker->paragraph,
];
});
$factory->define(\BookStack\Entities\Models\Book::class, function ($faker) {
return [
'name' => $faker->sentence,
'slug' => Str::random(10),
'description' => $faker->paragraph,
];
});
$factory->define(\BookStack\Entities\Models\Chapter::class, function ($faker) {
return [
'name' => $faker->sentence,
'slug' => Str::random(10),
'description' => $faker->paragraph,
];
});
$factory->define(\BookStack\Entities\Models\Page::class, function ($faker) {
$html = '<p>' . implode('</p>', $faker->paragraphs(5)) . '</p>';
return [
'name' => $faker->sentence,
'slug' => Str::random(10),
'html' => $html,
'text' => strip_tags($html),
'revision_count' => 1,
];
});
$factory->define(\BookStack\Auth\Role::class, function ($faker) {
return [
'display_name' => $faker->sentence(3),
'description' => $faker->sentence(10),
];
});
$factory->define(\BookStack\Actions\Tag::class, function ($faker) {
return [
'name' => $faker->city,
'value' => $faker->sentence(3),
];
});
$factory->define(\BookStack\Uploads\Image::class, function ($faker) {
return [
'name' => $faker->slug . '.jpg',
'url' => $faker->url,
'path' => $faker->url,
'type' => 'gallery',
'uploaded_to' => 0,
];
});
$factory->define(\BookStack\Actions\Comment::class, function ($faker) {
$text = $faker->paragraph(1);
$html = '<p>' . $text . '</p>';
return [
'html' => $html,
'text' => $text,
'parent_id' => null,
];
});

View File

@ -0,0 +1,31 @@
<?php
namespace Database\Factories\Uploads;
use Illuminate\Database\Eloquent\Factories\Factory;
class ImageFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = \BookStack\Uploads\Image::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->slug . '.jpg',
'url' => $this->faker->url,
'path' => $this->faker->url,
'type' => 'gallery',
'uploaded_to' => 0,
];
}
}

View File

@ -2,6 +2,7 @@
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class CreateBookshelvesTable extends Migration

View File

@ -1,5 +1,7 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Seeder;

View File

@ -1,5 +1,7 @@
<?php
namespace Database\Seeders;
use BookStack\Api\ApiToken;
use BookStack\Auth\Permissions\PermissionService;
use BookStack\Auth\Permissions\RolePermission;
@ -10,6 +12,7 @@ use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Tools\SearchIndex;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class DummyContentSeeder extends Seeder
@ -22,36 +25,36 @@ class DummyContentSeeder extends Seeder
public function run()
{
// Create an editor user
$editorUser = factory(User::class)->create();
$editorUser = User::factory()->create();
$editorRole = Role::getRole('editor');
$editorUser->attachRole($editorRole);
// Create a viewer user
$viewerUser = factory(User::class)->create();
$viewerUser = User::factory()->create();
$role = Role::getRole('viewer');
$viewerUser->attachRole($role);
$byData = ['created_by' => $editorUser->id, 'updated_by' => $editorUser->id, 'owned_by' => $editorUser->id];
factory(\BookStack\Entities\Models\Book::class, 5)->create($byData)
\BookStack\Entities\Models\Book::factory()->count(5)->create($byData)
->each(function ($book) use ($byData) {
$chapters = factory(Chapter::class, 3)->create($byData)
$chapters = Chapter::factory()->count(3)->create($byData)
->each(function ($chapter) use ($book, $byData) {
$pages = factory(Page::class, 3)->make(array_merge($byData, ['book_id' => $book->id]));
$pages = Page::factory()->count(3)->make(array_merge($byData, ['book_id' => $book->id]));
$chapter->pages()->saveMany($pages);
});
$pages = factory(Page::class, 3)->make($byData);
$pages = Page::factory()->count(3)->make($byData);
$book->chapters()->saveMany($chapters);
$book->pages()->saveMany($pages);
});
$largeBook = factory(\BookStack\Entities\Models\Book::class)->create(array_merge($byData, ['name' => 'Large book' . Str::random(10)]));
$pages = factory(Page::class, 200)->make($byData);
$chapters = factory(Chapter::class, 50)->make($byData);
$largeBook = \BookStack\Entities\Models\Book::factory()->create(array_merge($byData, ['name' => 'Large book' . Str::random(10)]));
$pages = Page::factory()->count(200)->make($byData);
$chapters = Chapter::factory()->count(50)->make($byData);
$largeBook->pages()->saveMany($pages);
$largeBook->chapters()->saveMany($chapters);
$shelves = factory(Bookshelf::class, 10)->create($byData);
$shelves = Bookshelf::factory()->count(10)->create($byData);
$largeBook->shelves()->attach($shelves->pluck('id'));
// Assign API permission to editor role and create an API key

View File

@ -1,5 +1,7 @@
<?php
namespace Database\Seeders;
use BookStack\Auth\Permissions\PermissionService;
use BookStack\Auth\Role;
use BookStack\Auth\User;
@ -19,13 +21,13 @@ class LargeContentSeeder extends Seeder
public function run()
{
// Create an editor user
$editorUser = factory(User::class)->create();
$editorUser = User::factory()->create();
$editorRole = Role::getRole('editor');
$editorUser->attachRole($editorRole);
$largeBook = factory(\BookStack\Entities\Models\Book::class)->create(['name' => 'Large book' . Str::random(10), 'created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
$pages = factory(Page::class, 200)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
$chapters = factory(Chapter::class, 50)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
$largeBook = \BookStack\Entities\Models\Book::factory()->create(['name' => 'Large book' . Str::random(10), 'created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
$pages = Page::factory()->count(200)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
$chapters = Chapter::factory()->count(50)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
$largeBook->pages()->saveMany($pages);
$largeBook->chapters()->saveMany($chapters);
app(PermissionService::class)->buildJointPermissions();

View File

@ -7,6 +7,6 @@
"order": 2,
"created_by": 1,
"updated_by": 1,
"created_at": "2021-10-20 06:35:46",
"updated_at": "2021-10-20 06:35:46"
"created_at": "2021-10-20T06:35:46.000000Z",
"updated_at": "2021-10-20T06:35:46.000000Z"
}

View File

@ -7,8 +7,8 @@
"uploaded_to": 8,
"external": false,
"order": 1,
"created_at": "2021-10-11 06:18:49",
"updated_at": "2021-10-20 06:31:10",
"created_at": "2021-10-11T06:18:49.000000Z",
"updated_at": "2021-10-20T06:31:10.000000Z",
"created_by": 1,
"updated_by": 1
},
@ -19,8 +19,8 @@
"uploaded_to": 9,
"external": true,
"order": 1,
"created_at": "2021-10-20 06:30:11",
"updated_at": "2021-10-20 06:30:11",
"created_at": "2021-10-20T06:30:11.000000Z",
"updated_at": "2021-10-20T06:30:11.000000Z",
"created_by": 1,
"updated_by": 1
}

View File

@ -15,8 +15,8 @@
"name": "Admin",
"slug": "admin"
},
"created_at": "2021-10-20 06:35:46",
"updated_at": "2021-10-20 06:37:11",
"created_at": "2021-10-20T06:35:46.000000Z",
"updated_at": "2021-10-20T06:37:11.000000Z",
"links": {
"html": "<a target=\"_blank\" href=\"https://bookstack.local/attachments/5\">My updated attachment</a>",
"markdown": "[My updated attachment](https://bookstack.local/attachments/5)"

View File

@ -7,6 +7,6 @@
"order": 2,
"created_by": 1,
"updated_by": 1,
"created_at": "2021-10-20 06:35:46",
"updated_at": "2021-10-20 06:37:11"
"created_at": "2021-10-20T06:35:46.000000Z",
"updated_at": "2021-10-20T06:37:11.000000Z"
}

View File

@ -5,7 +5,7 @@
"updated_by": 1,
"owned_by": 1,
"slug": "my-new-book",
"updated_at": "2020-01-12 14:05:11",
"created_at": "2020-01-12 14:05:11",
"updated_at": "2020-01-12T14:05:11.000000Z",
"created_at": "2020-01-12T14:05:11.000000Z",
"id": 15
}

View File

@ -5,8 +5,8 @@
"name": "BookStack User Guide",
"slug": "bookstack-user-guide",
"description": "This is a general guide on using BookStack on a day-to-day basis.",
"created_at": "2019-05-05 21:48:46",
"updated_at": "2019-12-11 20:57:31",
"created_at": "2019-05-05T21:48:46.000000Z",
"updated_at": "2019-12-11T20:57:31.000000Z",
"created_by": 1,
"updated_by": 1,
"owned_by": 1,
@ -17,8 +17,8 @@
"name": "Inventore inventore quia voluptatem.",
"slug": "inventore-inventore-quia-voluptatem",
"description": "Veniam nihil voluptas enim laborum corporis quos sint. Ab rerum voluptas ut iste voluptas magni quibusdam ut. Amet omnis enim voluptate neque facilis.",
"created_at": "2019-05-05 22:10:14",
"updated_at": "2019-12-11 20:57:23",
"created_at": "2019-05-05T22:10:14.000000Z",
"updated_at": "2019-12-11T20:57:23.000000Z",
"created_by": 4,
"updated_by": 3,
"owned_by": 3,

View File

@ -3,8 +3,8 @@
"name": "My own book",
"slug": "my-own-book",
"description": "This is my own little book",
"created_at": "2020-01-12 14:09:59",
"updated_at": "2020-01-12 14:11:51",
"created_at": "2020-01-12T14:09:59.000000Z",
"updated_at": "2020-01-12T14:11:51.000000Z",
"created_by": {
"id": 1,
"name": "Admin"
@ -29,8 +29,8 @@
"id": 452,
"name": "sjovall_m117hUWMu40.jpg",
"url": "http:\/\/bookstack.local\/uploads\/images\/cover_book\/2020-01\/sjovall_m117hUWMu40.jpg",
"created_at": "2020-01-12 14:11:51",
"updated_at": "2020-01-12 14:11:51",
"created_at": "2020-01-12T14:11:51.000000Z",
"updated_at": "2020-01-12T14:11:51.000000Z",
"created_by": 1,
"updated_by": 1,
"path": "\/uploads\/images\/cover_book\/2020-01\/sjovall_m117hUWMu40.jpg",

View File

@ -3,8 +3,8 @@
"name": "My own book",
"slug": "my-own-book",
"description": "This is my own little book - updated",
"created_at": "2020-01-12 14:09:59",
"updated_at": "2020-01-12 14:16:10",
"created_at": "2020-01-12T14:09:59.000000Z",
"updated_at": "2020-01-12T14:16:10.000000Z",
"created_by": 1,
"updated_by": 1,
"owned_by": 1,

View File

@ -7,16 +7,16 @@
"updated_by": 1,
"owned_by": 1,
"slug": "my-fantastic-new-chapter",
"updated_at": "2020-05-22 22:59:55",
"created_at": "2020-05-22 22:59:55",
"updated_at": "2020-05-22T22:59:55.000000Z",
"created_at": "2020-05-22T22:59:55.000000Z",
"id": 74,
"book": {
"id": 1,
"name": "BookStack User Guide",
"slug": "bookstack-user-guide",
"description": "This is a general guide on using BookStack on a day-to-day basis.",
"created_at": "2019-05-05 21:48:46",
"updated_at": "2019-12-11 20:57:31",
"created_at": "2019-05-05T21:48:46.000000Z",
"updated_at": "2019-12-11T20:57:31.000000Z",
"created_by": 1,
"updated_by": 1
},
@ -25,15 +25,15 @@
"name": "Category",
"value": "Top Content",
"order": 0,
"created_at": "2020-05-22 22:59:55",
"updated_at": "2020-05-22 22:59:55"
"created_at": "2020-05-22T22:59:55.000000Z",
"updated_at": "2020-05-22T22:59:55.000000Z"
},
{
"name": "Rating",
"value": "Highest",
"order": 0,
"created_at": "2020-05-22 22:59:55",
"updated_at": "2020-05-22 22:59:55"
"created_at": "2020-05-22T22:59:55.000000Z",
"updated_at": "2020-05-22T22:59:55.000000Z"
}
]
}

View File

@ -7,8 +7,8 @@
"slug": "content-creation",
"description": "How to create documentation on whatever subject you need to write about.",
"priority": 3,
"created_at": "2019-05-05 21:49:56",
"updated_at": "2019-09-28 11:24:23",
"created_at": "2019-05-05:",
"updated_at": "2019-09-28T11:24:23.000000Z",
"created_by": 1,
"updated_by": 1,
"owned_by": 1
@ -20,8 +20,8 @@
"slug": "managing-content",
"description": "How to keep things organised and orderly in the system for easier navigation and better user experience.",
"priority": 5,
"created_at": "2019-05-05 21:58:07",
"updated_at": "2019-10-17 15:05:34",
"created_at": "2019-05-05T21:58:07.000000Z",
"updated_at": "2019-10-17T15:05:34.000000Z",
"created_by": 3,
"updated_by": 3,
"owned_by": 3

View File

@ -5,8 +5,8 @@
"name": "Content Creation",
"description": "How to create documentation on whatever subject you need to write about.",
"priority": 3,
"created_at": "2019-05-05 21:49:56",
"updated_at": "2019-09-28 11:24:23",
"created_at": "2019-05-05T21:49:56.000000Z",
"updated_at": "2019-09-28T11:24:23.000000Z",
"created_by": {
"id": 1,
"name": "Admin"
@ -34,8 +34,8 @@
"name": "How to create page content",
"slug": "how-to-create-page-content",
"priority": 0,
"created_at": "2019-05-05 21:49:58",
"updated_at": "2019-08-26 14:32:59",
"created_at": "2019-05-05T21:49:58.000000Z",
"updated_at": "2019-08-26T14:32:59.000000Z",
"created_by": 1,
"updated_by": 1,
"draft": false,
@ -49,8 +49,8 @@
"name": "Good book structure",
"slug": "good-book-structure",
"priority": 1,
"created_at": "2019-05-05 22:01:55",
"updated_at": "2019-06-06 12:03:04",
"created_at": "2019-05-05T22:01:55.000000Z",
"updated_at": "2019-06-06T12:03:04.000000Z",
"created_by": 3,
"updated_by": 3,
"draft": false,

View File

@ -5,8 +5,8 @@
"name": "My fantastic updated chapter",
"description": "This is an updated chapter that I've altered via the API",
"priority": 7,
"created_at": "2020-05-22 23:03:35",
"updated_at": "2020-05-22 23:07:20",
"created_at": "2020-05-22T23:03:35.000000Z",
"updated_at": "2020-05-22T23:07:20.000000Z",
"created_by": 1,
"updated_by": 1,
"owned_by": 1,
@ -15,8 +15,8 @@
"name": "BookStack User Guide",
"slug": "bookstack-user-guide",
"description": "This is a general guide on using BookStack on a day-to-day basis.",
"created_at": "2019-05-05 21:48:46",
"updated_at": "2019-12-11 20:57:31",
"created_at": "2019-05-05T21:48:46.000000Z",
"updated_at": "2019-12-11T20:57:31.000000Z",
"created_by": 1,
"updated_by": 1
},
@ -25,15 +25,15 @@
"name": "Category",
"value": "Kinda Good Content",
"order": 0,
"created_at": "2020-05-22 23:07:20",
"updated_at": "2020-05-22 23:07:20"
"created_at": "2020-05-22T23:07:20.000000Z",
"updated_at": "2020-05-22T23:07:20.000000Z"
},
{
"name": "Rating",
"value": "Medium",
"order": 0,
"created_at": "2020-05-22 23:07:20",
"updated_at": "2020-05-22 23:07:20"
"created_at": "2020-05-22T23:07:20.000000Z",
"updated_at": "2020-05-22T23:07:20.000000Z"
}
]
}

View File

@ -6,8 +6,8 @@
"slug": "my-api-page",
"html": "<p id=\"bkmrk-my-new-api-page\">my new API page</p>",
"priority": 14,
"created_at": "2020-11-28 15:01:39",
"updated_at": "2020-11-28 15:01:39",
"created_at": "2020-11-28T15:01:39.000000Z",
"updated_at": "2020-11-28T15:01:39.000000Z",
"created_by": {
"id": 1,
"name": "Admin"

View File

@ -9,8 +9,8 @@
"priority": 0,
"draft": false,
"template": false,
"created_at": "2019-05-05 21:49:58",
"updated_at": "2020-07-04 15:50:58",
"created_at": "2019-05-05T21:49:58.000000Z",
"updated_at": "2020-07-04T15:50:58.000000Z",
"created_by": 1,
"updated_by": 1,
"owned_by": 1
@ -24,8 +24,8 @@
"priority": 2,
"draft": false,
"template": false,
"created_at": "2019-05-05 21:53:30",
"updated_at": "2019-06-06 12:03:04",
"created_at": "2019-05-05T21:53:30.000000Z",
"updated_at": "2019-06-06T12:03:04.000000Z",
"created_by": 1,
"updated_by": 1,
"owned_by": 1
@ -39,8 +39,8 @@
"priority": 3,
"draft": false,
"template": false,
"created_at": "2019-05-05 21:53:49",
"updated_at": "2019-12-18 21:56:52",
"created_at": "2019-05-05T21:53:49.000000Z",
"updated_at": "2019-12-18T21:56:52.000000Z",
"created_by": 1,
"updated_by": 1,
"owned_by": 1

View File

@ -6,8 +6,8 @@
"slug": "a-page-written-in-markdown",
"html": "<h1 id=\"bkmrk-how-this-is-built\">How this is built</h1>\r\n<p id=\"bkmrk-this-page-is-written\">This page is written in markdown. BookStack stores the page data in HTML.</p>\r\n<p id=\"bkmrk-here%27s-a-cute-pictur\">Here's a cute picture of my cat:</p>\r\n<p id=\"bkmrk-\"><a href=\"http://example.com/uploads/images/gallery/2020-04/yXSrubes.jpg\"><img src=\"http://example.com/uploads/images/gallery/2020-04/scaled-1680-/yXSrubes.jpg\" alt=\"yXSrubes.jpg\"></a></p>",
"priority": 13,
"created_at": "2020-02-02 21:40:38",
"updated_at": "2020-11-28 14:43:20",
"created_at": "2020-02-02T21:40:38.000000Z",
"updated_at": "2020-11-28T14:43:20.000000Z",
"created_by": {
"id": 1,
"name": "Admin"

View File

@ -6,8 +6,8 @@
"slug": "my-updated-api-page",
"html": "<p id=\"bkmrk-my-new-api-page---up\">my new API page - Updated</p>",
"priority": 16,
"created_at": "2020-11-28 15:10:54",
"updated_at": "2020-11-28 15:13:03",
"created_at": "2020-11-28T15:10:54.000000Z",
"updated_at": "2020-11-28T15:13:03.000000Z",
"created_by": {
"id": 1,
"name": "Admin"

View File

@ -5,7 +5,7 @@
"updated_by": 1,
"owned_by": 1,
"slug": "my-shelf",
"updated_at": "2020-04-10 13:24:09",
"created_at": "2020-04-10 13:24:09",
"updated_at": "2020-04-10T13:24:09.000000Z",
"created_at": "2020-04-10T13:24:09.000000Z",
"id": 14
}

View File

@ -5,8 +5,8 @@
"name": "Qui qui aspernatur autem molestiae libero necessitatibus molestias.",
"slug": "qui-qui-aspernatur-autem-molestiae-libero-necessitatibus-molestias",
"description": "Enim dolor ut quia error dolores est. Aut distinctio consequuntur non nisi nostrum. Labore cupiditate error labore aliquid provident impedit voluptatibus. Quaerat impedit excepturi eius qui eius voluptatem reiciendis.",
"created_at": "2019-05-05 22:10:16",
"updated_at": "2020-04-10 13:00:45",
"created_at": "2019-05-05T22:10:16.000000Z",
"updated_at": "2020-04-10T13:00:45.000000Z",
"created_by": 4,
"updated_by": 1,
"owned_by": 1,
@ -17,8 +17,8 @@
"name": "Ipsum aut inventore fuga libero non facilis.",
"slug": "ipsum-aut-inventore-fuga-libero-non-facilis",
"description": "Labore culpa modi perspiciatis harum sit. Maxime non et nam est. Quae ut laboriosam repellendus sunt quisquam. Velit at est perspiciatis nesciunt adipisci nobis illo. Sed possimus odit optio officiis nisi voluptates officiis dolor.",
"created_at": "2019-05-05 22:10:16",
"updated_at": "2020-04-10 13:00:58",
"created_at": "2019-05-05T22:10:16.000000Z",
"updated_at": "2020-04-10T13:00:58.000000Z",
"created_by": 4,
"updated_by": 1,
"owned_by": 1,
@ -29,8 +29,8 @@
"name": "Omnis reiciendis aut molestias sint accusantium.",
"slug": "omnis-reiciendis-aut-molestias-sint-accusantium",
"description": "Qui ea occaecati alias est dolores voluptatem doloribus. Ad reiciendis corporis vero nostrum omnis et. Non doloribus ut eaque ut quos dolores.",
"created_at": "2019-05-05 22:10:16",
"updated_at": "2020-04-10 13:00:53",
"created_at": "2019-05-05T22:10:16.000000Z",
"updated_at": "2020-04-10T13:00:53.000000Z",
"created_by": 4,
"updated_by": 1,
"owned_by": 4,

View File

@ -15,8 +15,8 @@
"id": 1,
"name": "Admin"
},
"created_at": "2020-04-10 13:24:09",
"updated_at": "2020-04-10 13:31:04",
"created_at": "2020-04-10T13:24:09.000000Z",
"updated_at": "2020-04-10T13:31:04.000000Z",
"tags": [
{
"id": 16,
@ -29,8 +29,8 @@
"id": 501,
"name": "anafrancisconi_Sp04AfFCPNM.jpg",
"url": "http://bookstack.local/uploads/images/cover_book/2020-04/anafrancisconi_Sp04AfFCPNM.jpg",
"created_at": "2020-04-10 13:31:04",
"updated_at": "2020-04-10 13:31:04",
"created_at": "2020-04-10T13:31:04.000000Z",
"updated_at": "2020-04-10T13:31:04.000000Z",
"created_by": 1,
"updated_by": 1,
"path": "/uploads/images/cover_book/2020-04/anafrancisconi_Sp04AfFCPNM.jpg",

View File

@ -7,6 +7,6 @@
"updated_by": 1,
"owned_by": 1,
"image_id": 501,
"created_at": "2020-04-10 13:24:09",
"updated_at": "2020-04-10 13:48:22"
"created_at": "2020-04-10T13:24:09.000000Z",
"updated_at": "2020-04-10T13:48:22.000000Z"
}

View File

@ -1,15 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
colors="true">
<coverage>
<include>
<directory suffix=".php">app/</directory>

View File

@ -1,21 +1,33 @@
<?php
/**
* Laravel - A PHP Framework For Web Artisans.
*
* @author Taylor Otwell <taylor@laravel.com>
*/
use Illuminate\Contracts\Http\Kernel;
use BookStack\Http\Request;
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Check If The Application Is Under Maintenance
|--------------------------------------------------------------------------
|
| If the application is in maintenance / demo mode via the "down" command
| we will load this file so that any pre-rendered content can be shown
| instead of starting the framework, which could cause an exception.
|
*/
if (file_exists(__DIR__ . '/../storage/framework/maintenance.php')) {
require __DIR__ . '/../storage/framework/maintenance.php';
}
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels great to relax.
| this application. We just need to utilize it! We'll simply require it
| into the script here so we don't need to manually load our classes.
|
*/
@ -23,37 +35,22 @@ require __DIR__ . '/../vendor/autoload.php';
/*
|--------------------------------------------------------------------------
| Turn On The Lights
| Run The Application
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
| Once we have the application, we can handle the incoming request using
| the application's HTTP kernel. Then, we will send the response back
| to this client's browser, allowing them to enjoy our application.
|
*/
$app = require_once __DIR__ . '/../bootstrap/app.php';
$app->alias('request', \BookStack\Http\Request::class);
$app->alias('request', Request::class);
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/
$kernel = $app->make(Kernel::class);
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = tap($kernel->handle(
$request = Request::capture()
))->send();
$response = $kernel->handle(
$request = \BookStack\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response);
$kernel->terminate($request, $response);

View File

@ -206,11 +206,8 @@ These are the great open-source projects used to help build BookStack:
* [Dropzone.js](http://www.dropzonejs.com/)
* [clipboard.js](https://clipboardjs.com/)
* [markdown-it](https://github.com/markdown-it/markdown-it) and [markdown-it-task-lists](https://github.com/revin/markdown-it-task-lists)
* [BarryVD](https://github.com/barryvdh)
* [Debugbar](https://github.com/barryvdh/laravel-debugbar)
* [Dompdf](https://github.com/barryvdh/laravel-dompdf)
* [Snappy (WKHTML2PDF)](https://github.com/barryvdh/laravel-snappy)
* [Laravel IDE helper](https://github.com/barryvdh/laravel-ide-helper)
* [BarryVD/Dompdf](https://github.com/barryvdh/laravel-dompdf)
* [BarryVD/Snappy (WKHTML2PDF)](https://github.com/barryvdh/laravel-snappy)
* [WKHTMLtoPDF](http://wkhtmltopdf.org/index.html)
* [diagrams.net](https://github.com/jgraph/drawio)
* [OneLogin's SAML PHP Toolkit](https://github.com/onelogin/php-saml)
@ -219,4 +216,5 @@ These are the great open-source projects used to help build BookStack:
* [StyleCI](https://styleci.io/)
* [pragmarx/google2fa](https://github.com/antonioribeiro/google2fa)
* [Bacon/BaconQrCode](https://github.com/Bacon/BaconQrCode)
* [phpseclib](https://github.com/phpseclib/phpseclib)
* [phpseclib](https://github.com/phpseclib/phpseclib)
* [Clockwork](https://github.com/itsgoingd/clockwork)

View File

@ -38,7 +38,6 @@ return [
'registration_email_domain_invalid' => 'المجال الخاص بالبريد الإلكتروني لا يملك حق الوصول لهذا التطبيق',
'register_success' => 'شكراً لإنشاء حسابكم! تم تسجيلكم ودخولكم للحساب الخاص بكم.',
// Password Reset
'reset_password' => 'استعادة كلمة المرور',
'reset_password_send_instructions' => 'أدخل بريدك الإلكتروني بالأسفل وسيتم إرسال رسالة برابط لاستعادة كلمة المرور.',
@ -49,7 +48,6 @@ return [
'email_reset_text' => 'تم إرسال هذه الرسالة بسبب تلقينا لطلب استعادة كلمة المرور الخاصة بحسابكم.',
'email_reset_not_requested' => 'إذا لم يتم طلب استعادة كلمة المرور من قبلكم، فلا حاجة لاتخاذ أية خطوات.',
// Email Confirmation
'email_confirm_subject' => 'تأكيد بريدكم الإلكتروني لتطبيق :appName',
'email_confirm_greeting' => 'شكرا لانضمامكم إلى :appName!',
@ -109,4 +107,4 @@ return [
'mfa_verify_backup_code_enter_here' => 'Enter backup code here',
'mfa_verify_totp_desc' => 'Enter the code, generated using your mobile app, below:',
'mfa_setup_login_notification' => 'Multi-factor method configured, Please now login again using the configured method.',
];
];

View File

@ -20,7 +20,7 @@ return [
'role' => 'الدور',
'cover_image' => 'صورة الغلاف',
'cover_image_description' => 'الصورة يجب أن تكون مقاربة لحجم 440×250 بكسل.',
// Actions
'actions' => 'إجراءات',
'view' => 'عرض',

View File

@ -321,5 +321,5 @@ return [
'revision_delete_confirm' => 'هل أنت متأكد من أنك تريد حذف هذه المراجعة؟',
'revision_restore_confirm' => 'هل أنت متأكد من أنك تريد استعادة هذه المراجعة؟ سيتم استبدال محتوى الصفحة الحالية.',
'revision_delete_success' => 'تم حذف المراجعة',
'revision_cannot_delete_latest' => 'لايمكن حذف آخر مراجعة.'
'revision_cannot_delete_latest' => 'لايمكن حذف آخر مراجعة.',
];

View File

@ -7,7 +7,7 @@
return [
'password' => 'يجب أن تتكون كلمة المرور من ستة أحرف على الأقل وأن تطابق التأكيد.',
'user' => "لم يتم العثور على مستخدم بعنوان البريد الإلكتروني المعطى.",
'user' => 'لم يتم العثور على مستخدم بعنوان البريد الإلكتروني المعطى.',
'token' => 'رمز إعادة تعيين كلمة المرور غير صالح لعنوان هذا البريد الإلكتروني.',
'sent' => 'تم إرسال رابط تجديد كلمة المرور إلى بريدكم الإلكتروني!',
'reset' => 'تم تجديد كلمة المرور الخاصة بكم!',

View File

@ -72,7 +72,7 @@ return [
// Maintenance settings
'maint' => 'الصيانة',
'maint_image_cleanup' => 'تنظيف الصور',
'maint_image_cleanup_desc' => "مسح الصفحة ومراجعة المحتوى للتحقق من أي الصور والرسوم المستخدمة حاليًا وأي الصور زائدة عن الحاجة. تأكد من إنشاء قاعدة بيانات كاملة و نسخة احتياطية للصور قبل تشغيل هذا.",
'maint_image_cleanup_desc' => 'مسح الصفحة ومراجعة المحتوى للتحقق من أي الصور والرسوم المستخدمة حاليًا وأي الصور زائدة عن الحاجة. تأكد من إنشاء قاعدة بيانات كاملة و نسخة احتياطية للصور قبل تشغيل هذا.',
'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions',
'maint_image_cleanup_run' => 'بدء التنظيف',
'maint_image_cleanup_warning' => 'يوجد عدد :count من الصور المحتمل عدم استخدامها. تأكيد حذف الصور؟',
@ -132,7 +132,7 @@ return [
'role_delete' => 'حذف الدور',
'role_delete_confirm' => 'سيتم حذف الدور المسمى \':roleName\'.',
'role_delete_users_assigned' => 'هذا الدور له: عدد المستخدمين المعينين له. إذا كنت ترغب في ترحيل المستخدمين من هذا الدور ، فحدد دورًا جديدًا أدناه.',
'role_delete_no_migration' => "لا تقم بترجيل المستخدمين",
'role_delete_no_migration' => 'لا تقم بترجيل المستخدمين',
'role_delete_sure' => 'تأكيد حذف الدور؟',
'role_delete_success' => 'تم حذف الدور بنجاح',
'role_edit' => 'تعديل الدور',
@ -273,6 +273,6 @@ return [
'vi' => 'Tiếng Việt',
'zh_CN' => '简体中文',
'zh_TW' => '繁體中文',
]
],
//!////////////////////////////////
];

View File

@ -38,7 +38,6 @@ return [
'registration_email_domain_invalid' => 'Този емейл домейн към момента няма достъп до приложението',
'register_success' => 'Благодарим Ви за регистрацията! В момента сте регистриран и сте вписани в приложението.',
// Password Reset
'reset_password' => 'Нулиране на паролата',
'reset_password_send_instructions' => 'Въведете емейла си и ще ви бъде изпратен емейл с линк за нулиране на паролата.',
@ -49,7 +48,6 @@ return [
'email_reset_text' => 'Вие получихте този емейл, защото поискахте вашата парола да бъде занулена.',
'email_reset_not_requested' => 'Ако Вие не сте поискали зануляването на паролата, няма нужда от други действия.',
// Email Confirmation
'email_confirm_subject' => 'Потвърди емейла си за :appName',
'email_confirm_greeting' => 'Благодарим Ви, че се присъединихте към :appName!',
@ -109,4 +107,4 @@ return [
'mfa_verify_backup_code_enter_here' => 'Enter backup code here',
'mfa_verify_totp_desc' => 'Enter the code, generated using your mobile app, below:',
'mfa_setup_login_notification' => 'Multi-factor method configured, Please now login again using the configured method.',
];
];

View File

@ -20,7 +20,7 @@ return [
'role' => 'Роля',
'cover_image' => 'Основно изображение',
'cover_image_description' => 'Картината трябва да е приблизително 440х250 пиксела.',
// Actions
'actions' => 'Действия',
'view' => 'Преглед',

View File

@ -321,5 +321,5 @@ return [
'revision_delete_confirm' => 'Наистина ли искате да изтриете тази версия?',
'revision_restore_confirm' => 'Сигурни ли сте, че искате да изтриете тази версия? Настоящата страница ще бъде заместена.',
'revision_delete_success' => 'Версията беше изтрита',
'revision_cannot_delete_latest' => 'Не може да изтриете последната версия.'
'revision_cannot_delete_latest' => 'Не може да изтриете последната версия.',
];

View File

@ -7,7 +7,7 @@
return [
'password' => 'Паролите трябва да имат поне 8 символа и да съвпадат с потвърждението.',
'user' => "Не можем да намерим потребител с този имейл адрес.",
'user' => 'Не можем да намерим потребител с този имейл адрес.',
'token' => 'Кодът за зануляване на паролата е невалиден за този емейл адрес.',
'sent' => 'Пратихме връзка за нулиране на паролата до имейла ви!',
'reset' => 'Вашата парола е нулирана!',

View File

@ -72,7 +72,7 @@ return [
// Maintenance settings
'maint' => 'Maintenance',
'maint_image_cleanup' => 'Cleanup Images',
'maint_image_cleanup_desc' => "Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.",
'maint_image_cleanup_desc' => 'Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.',
'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions',
'maint_image_cleanup_run' => 'Run Cleanup',
'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?',
@ -132,7 +132,7 @@ return [
'role_delete' => 'Изтрий роля',
'role_delete_confirm' => 'Това ще изтрие ролята \':roleName\'.',
'role_delete_users_assigned' => 'В тази роля се намират :userCount потребители. Ако искате да преместите тези потребители в друга роля, моля изберете нова роля отдолу.',
'role_delete_no_migration' => "Не премествай потребителите в нова роля",
'role_delete_no_migration' => 'Не премествай потребителите в нова роля',
'role_delete_sure' => 'Сигурни ли сте, че искате да изтриете тази роля?',
'role_delete_success' => 'Ролята беше успешно изтрита',
'role_edit' => 'Редактиране на роля',
@ -273,6 +273,6 @@ return [
'vi' => 'Tiếng Việt',
'zh_CN' => '简体中文',
'zh_TW' => '繁體中文',
]
],
//!////////////////////////////////
];

View File

@ -38,7 +38,6 @@ return [
'registration_email_domain_invalid' => 'Ta e-mail domena nema pristup ovoj aplikaciji',
'register_success' => 'Hvala na registraciji! Sada ste registrovani i prijavljeni.',
// Password Reset
'reset_password' => 'Resetuj Lozinku',
'reset_password_send_instructions' => 'Unesite vašu e-mail adresu ispod i na nju ćemo vam poslati e-mail sa linkom za promjenu lozinke.',
@ -49,7 +48,6 @@ return [
'email_reset_text' => 'Primate ovaj e-mail jer smo dobili zahtjev za promjenu lozinke za vaš račun.',
'email_reset_not_requested' => 'Ako niste zahtijevali promjenu lozinke ne trebate ništa više uraditi.',
// Email Confirmation
'email_confirm_subject' => 'Potvrdite vaš e-mail na :appName',
'email_confirm_greeting' => 'Hvala na pristupanju :appName!',
@ -109,4 +107,4 @@ return [
'mfa_verify_backup_code_enter_here' => 'Enter backup code here',
'mfa_verify_totp_desc' => 'Enter the code, generated using your mobile app, below:',
'mfa_setup_login_notification' => 'Multi-factor method configured, Please now login again using the configured method.',
];
];

View File

@ -20,7 +20,7 @@ return [
'role' => 'Uloga',
'cover_image' => 'Naslovna slika',
'cover_image_description' => 'Ova slika treba biti približno 440x250px.',
// Actions
'actions' => 'Akcije',
'view' => 'Prikaz',

View File

@ -321,5 +321,5 @@ return [
'revision_delete_confirm' => 'Are you sure you want to delete this revision?',
'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.',
'revision_delete_success' => 'Revision deleted',
'revision_cannot_delete_latest' => 'Cannot delete the latest revision.'
'revision_cannot_delete_latest' => 'Cannot delete the latest revision.',
];

View File

@ -7,7 +7,7 @@
return [
'password' => 'Lozinke moraju sadržavati najmanje osam karaktera i podudarati se sa potvrdom lozinke.',
'user' => "Ne možemo naći korisnika sa tom e-mail adresom.",
'user' => 'Ne možemo naći korisnika sa tom e-mail adresom.',
'token' => 'Token za poništavanje lozinke nije validan za ovu e-mail adresu.',
'sent' => 'Poslali smo link za poništavanje vaše lozinke na e-mail!',
'reset' => 'Vaša lozinka je resetovana!',

View File

@ -72,7 +72,7 @@ return [
// Maintenance settings
'maint' => 'Maintenance',
'maint_image_cleanup' => 'Cleanup Images',
'maint_image_cleanup_desc' => "Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.",
'maint_image_cleanup_desc' => 'Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.',
'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions',
'maint_image_cleanup_run' => 'Run Cleanup',
'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?',
@ -273,6 +273,6 @@ return [
'vi' => 'Tiếng Việt',
'zh_CN' => '简体中文',
'zh_TW' => '繁體中文',
]
],
//!////////////////////////////////
];

View File

@ -38,7 +38,6 @@ return [
'registration_email_domain_invalid' => 'Aquest domini de correu electrònic no té accés a aquesta aplicació',
'register_success' => 'Gràcies per registrar-vos! Ja us hi heu registrat i heu iniciat la sessió.',
// Password Reset
'reset_password' => 'Restableix la contrasenya',
'reset_password_send_instructions' => 'Introduïu la vostra adreça electrònica a continuació i us enviarem un correu electrònic amb un enllaç per a restablir la contrasenya.',
@ -49,7 +48,6 @@ return [
'email_reset_text' => 'Rebeu aquest correu electrònic perquè heu rebut una petició de restabliment de contrasenya per al vostre compte.',
'email_reset_not_requested' => 'Si no heu demanat restablir la contrasenya, no cal que prengueu cap acció.',
// Email Confirmation
'email_confirm_subject' => 'Confirmeu la vostra adreça electrònica a :appName',
'email_confirm_greeting' => 'Gràcies per unir-vos a :appName!',
@ -109,4 +107,4 @@ return [
'mfa_verify_backup_code_enter_here' => 'Enter backup code here',
'mfa_verify_totp_desc' => 'Enter the code, generated using your mobile app, below:',
'mfa_setup_login_notification' => 'Multi-factor method configured, Please now login again using the configured method.',
];
];

View File

@ -20,7 +20,7 @@ return [
'role' => 'Rol',
'cover_image' => 'Imatge de portada',
'cover_image_description' => 'Aquesta imatge hauria de fer aproximadament 440x250 px.',
// Actions
'actions' => 'Accions',
'view' => 'Visualitza',

View File

@ -321,5 +321,5 @@ return [
'revision_delete_confirm' => 'Segur que voleu suprimir aquesta revisió?',
'revision_restore_confirm' => 'Segur que voleu restaurar aquesta revisió? Se substituirà el contingut de la pàgina actual.',
'revision_delete_success' => 'S\'ha suprimit la revisió',
'revision_cannot_delete_latest' => 'No es pot suprimir la darrera revisió.'
'revision_cannot_delete_latest' => 'No es pot suprimir la darrera revisió.',
];

Some files were not shown because too many files have changed in this diff Show More