Apply fixes from StyleCI

This commit is contained in:
Dan Brown 2021-06-26 15:23:15 +00:00 committed by StyleCI Bot
parent 3a402f6adc
commit 934a833818
349 changed files with 3655 additions and 2625 deletions

View File

@ -20,7 +20,6 @@ use Illuminate\Support\Str;
*/
class Activity extends Model
{
/**
* Get the entity for this activity.
*/
@ -29,6 +28,7 @@ class Activity extends Model
if ($this->entity_type === '') {
$this->entity_type = null;
}
return $this->morphTo('entity');
}
@ -54,7 +54,7 @@ class Activity extends Model
public function isForEntity(): bool
{
return Str::startsWith($this->type, [
'page_', 'chapter_', 'book_', 'bookshelf_'
'page_', 'chapter_', 'book_', 'bookshelf_',
]);
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Actions;
<?php
namespace BookStack\Actions;
use BookStack\Auth\Permissions\PermissionService;
use BookStack\Auth\User;
@ -33,6 +35,7 @@ class ActivityService
/**
* Add a generic activity event to the database.
*
* @param string|Loggable $detail
*/
public function add(string $type, $detail = '')
@ -98,10 +101,10 @@ class ActivityService
$queryIds = [$entity->getMorphClass() => [$entity->id]];
if ($entity->isA('book')) {
$queryIds[(new Chapter)->getMorphClass()] = $entity->chapters()->visible()->pluck('id');
$queryIds[(new Chapter())->getMorphClass()] = $entity->chapters()->visible()->pluck('id');
}
if ($entity->isA('book') || $entity->isA('chapter')) {
$queryIds[(new Page)->getMorphClass()] = $entity->pages()->visible()->pluck('id');
$queryIds[(new Page())->getMorphClass()] = $entity->pages()->visible()->pluck('id');
}
$query = $this->activity->newQuery();
@ -143,7 +146,9 @@ class ActivityService
/**
* Filters out similar activity.
*
* @param Activity[] $activities
*
* @return array
*/
protected function filterSimilar(iterable $activities): array
@ -185,7 +190,7 @@ class ActivityService
return;
}
$message = str_replace("%u", $username, $message);
$message = str_replace('%u', $username, $message);
$channel = config('logging.failed_login.channel');
Log::channel($channel)->warning($message);
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Actions;
<?php
namespace BookStack\Actions;
class ActivityType
{

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Actions;
<?php
namespace BookStack\Actions;
use BookStack\Model;
use BookStack\Traits\HasCreatorAndUpdater;
@ -18,7 +20,7 @@ class Comment extends Model
protected $appends = ['created', 'updated'];
/**
* Get the entity that this comment belongs to
* Get the entity that this comment belongs to.
*/
public function entity(): MorphTo
{
@ -35,6 +37,7 @@ class Comment extends Model
/**
* Get created date as a relative diff.
*
* @return mixed
*/
public function getCreatedAttribute()
@ -44,6 +47,7 @@ class Comment extends Model
/**
* Get updated date as a relative diff.
*
* @return mixed
*/
public function getUpdatedAttribute()

View File

@ -1,21 +1,21 @@
<?php namespace BookStack\Actions;
<?php
namespace BookStack\Actions;
use BookStack\Entities\Models\Entity;
use League\CommonMark\CommonMarkConverter;
use BookStack\Facades\Activity as ActivityService;
use League\CommonMark\CommonMarkConverter;
/**
* Class CommentRepo
* Class CommentRepo.
*/
class CommentRepo
{
/**
* @var Comment $comment
* @var Comment
*/
protected $comment;
public function __construct(Comment $comment)
{
$this->comment = $comment;
@ -46,6 +46,7 @@ class CommentRepo
$entity->comments()->save($comment);
ActivityService::addForEntity($entity, ActivityType::COMMENTED_ON);
return $comment;
}
@ -58,6 +59,7 @@ class CommentRepo
$comment->text = $text;
$comment->html = $this->commentToHtml($text);
$comment->save();
return $comment;
}
@ -89,6 +91,7 @@ class CommentRepo
protected function getNextLocalId(Entity $entity): int
{
$comments = $entity->comments(false)->orderBy('local_id', 'desc')->first();
return ($comments->local_id ?? 0) + 1;
}
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Actions;
<?php
namespace BookStack\Actions;
use BookStack\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Actions;
<?php
namespace BookStack\Actions;
use BookStack\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
@ -9,7 +11,7 @@ class Tag extends Model
protected $hidden = ['id', 'entity_id', 'entity_type', 'created_at', 'updated_at'];
/**
* Get the entity that this tag belongs to
* Get the entity that this tag belongs to.
*/
public function entity(): MorphTo
{

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Actions;
<?php
namespace BookStack\Actions;
use BookStack\Auth\Permissions\PermissionService;
use BookStack\Entities\Models\Entity;
@ -7,7 +9,6 @@ use Illuminate\Support\Collection;
class TagRepo
{
protected $tag;
protected $permissionService;
@ -37,6 +38,7 @@ class TagRepo
}
$query = $this->permissionService->filterRestrictedEntityRelations($query, 'tags', 'entity_id', 'entity_type');
return $query->get(['name'])->pluck('name');
}
@ -62,11 +64,12 @@ class TagRepo
}
$query = $this->permissionService->filterRestrictedEntityRelations($query, 'tags', 'entity_id', 'entity_type');
return $query->get(['value'])->pluck('value');
}
/**
* Save an array of tags to an entity
* Save an array of tags to an entity.
*/
public function saveTagsToEntity(Entity $entity, array $tags = []): iterable
{
@ -89,6 +92,7 @@ class TagRepo
{
$name = trim($input['name']);
$value = isset($input['value']) ? trim($input['value']) : '';
return $this->tag->newInstance(['name' => $name, 'value' => $value]);
}
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Actions;
<?php
namespace BookStack\Actions;
use BookStack\Interfaces\Viewable;
use BookStack\Model;
@ -16,7 +18,6 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
*/
class View extends Model
{
protected $fillable = ['user_id', 'views'];
/**

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Api;
<?php
namespace BookStack\Api;
use BookStack\Http\Controllers\Api\ApiController;
use Illuminate\Contracts\Container\BindingResolutionException;
@ -12,7 +14,6 @@ use ReflectionMethod;
class ApiDocsGenerator
{
protected $reflectionClasses = [];
protected $controllerClasses = [];
@ -30,6 +31,7 @@ class ApiDocsGenerator
$docs = (new static())->generate();
Cache::put($cacheKey, $docs, 60 * 24);
}
return $docs;
}
@ -42,6 +44,7 @@ class ApiDocsGenerator
$apiRoutes = $this->loadDetailsFromControllers($apiRoutes);
$apiRoutes = $this->loadDetailsFromFiles($apiRoutes);
$apiRoutes = $apiRoutes->groupBy('base_model');
return $apiRoutes;
}
@ -57,6 +60,7 @@ class ApiDocsGenerator
$exampleContent = file_exists($exampleFile) ? file_get_contents($exampleFile) : null;
$route["example_{$exampleType}"] = $exampleContent;
}
return $route;
});
}
@ -71,12 +75,14 @@ class ApiDocsGenerator
$comment = $method->getDocComment();
$route['description'] = $comment ? $this->parseDescriptionFromMethodComment($comment) : null;
$route['body_params'] = $this->getBodyParamsFromClass($route['controller'], $route['controller_method']);
return $route;
});
}
/**
* Load body params and their rules by inspecting the given class and method name.
*
* @throws BindingResolutionException
*/
protected function getBodyParamsFromClass(string $className, string $methodName): ?array
@ -92,6 +98,7 @@ class ApiDocsGenerator
foreach ($rules as $param => $ruleString) {
$rules[$param] = explode('|', $ruleString);
}
return count($rules) > 0 ? $rules : null;
}
@ -102,11 +109,13 @@ class ApiDocsGenerator
{
$matches = [];
preg_match_all('/^\s*?\*\s((?![@\s]).*?)$/m', $comment, $matches);
return implode(' ', $matches[1] ?? []);
}
/**
* Get a reflection method from the given class name and method name.
*
* @throws ReflectionException
*/
protected function getReflectionMethod(string $className, string $methodName): ReflectionMethod
@ -131,6 +140,7 @@ class ApiDocsGenerator
[$controller, $controllerMethod] = explode('@', $route->action['uses']);
$baseModelName = explode('.', explode('/', $route->uri)[1])[0];
$shortName = $baseModelName . '-' . $controllerMethod;
return [
'name' => $shortName,
'uri' => $route->uri,

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Api;
<?php
namespace BookStack\Api;
use BookStack\Auth\User;
use BookStack\Interfaces\Loggable;
@ -7,7 +9,8 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Carbon;
/**
* Class ApiToken
* Class ApiToken.
*
* @property int $id
* @property string $token_id
* @property string $secret
@ -19,7 +22,7 @@ class ApiToken extends Model implements Loggable
{
protected $fillable = ['name', 'expires_at'];
protected $casts = [
'expires_at' => 'date:Y-m-d'
'expires_at' => 'date:Y-m-d',
];
/**

View File

@ -12,7 +12,6 @@ use Symfony\Component\HttpFoundation\Request;
class ApiTokenGuard implements Guard
{
use GuardHelpers;
/**
@ -20,9 +19,9 @@ class ApiTokenGuard implements Guard
*/
protected $request;
/**
* The last auth exception thrown in this request.
*
* @var ApiAuthException
*/
protected $lastAuthException;
@ -47,6 +46,7 @@ class ApiTokenGuard implements Guard
}
$user = null;
try {
$user = $this->getAuthorisedUserFromRequest();
} catch (ApiAuthException $exception) {
@ -54,15 +54,16 @@ class ApiTokenGuard implements Guard
}
$this->user = $user;
return $user;
}
/**
* Determine if current user is authenticated. If not, throw an exception.
*
* @return \Illuminate\Contracts\Auth\Authenticatable
*
* @throws ApiAuthException
*
* @return \Illuminate\Contracts\Auth\Authenticatable
*/
public function authenticate()
{
@ -79,6 +80,7 @@ class ApiTokenGuard implements Guard
/**
* Check the API token in the request and fetch a valid authorised user.
*
* @throws ApiAuthException
*/
protected function getAuthorisedUserFromRequest(): Authenticatable
@ -98,6 +100,7 @@ class ApiTokenGuard implements Guard
/**
* Validate the format of the token header value string.
*
* @throws ApiAuthException
*/
protected function validateTokenHeaderValue(string $authToken): void
@ -114,6 +117,7 @@ class ApiTokenGuard implements Guard
/**
* Validate the given secret against the given token and ensure the token
* currently has access to the instance API.
*
* @throws ApiAuthException
*/
protected function validateToken(?ApiToken $token, string $secret): void

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Api;
<?php
namespace BookStack\Api;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
@ -6,7 +8,6 @@ use Illuminate\Http\Request;
class ListingResponseBuilder
{
protected $query;
protected $request;
protected $fields;
@ -18,7 +19,7 @@ class ListingResponseBuilder
'lt' => '<',
'gte' => '>=',
'lte' => '<=',
'like' => 'like'
'like' => 'like',
];
/**
@ -54,6 +55,7 @@ class ListingResponseBuilder
{
$query = $this->countAndOffsetQuery($query);
$query = $this->sortQuery($query);
return $query->get($this->fields);
}
@ -95,6 +97,7 @@ class ListingResponseBuilder
}
$queryOperator = $this->filterOperators[$filterOperator];
return [$field, $queryOperator, $value];
}

View File

@ -4,11 +4,11 @@ namespace BookStack;
class Application extends \Illuminate\Foundation\Application
{
/**
* Get the path to the application configuration files.
*
* @param string $path Optionally, a path to append to the config path
*
* @return string
*/
public function configPath($path = '')

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth\Access;
<?php
namespace BookStack\Auth\Access;
use BookStack\Auth\User;
use BookStack\Exceptions\ConfirmationEmailException;
@ -12,7 +14,9 @@ class EmailConfirmationService extends UserTokenService
/**
* Create new confirmation for a user,
* Also removes any existing old ones.
*
* @param User $user
*
* @throws ConfirmationEmailException
*/
public function sendConfirmation(User $user)
@ -29,6 +33,7 @@ class EmailConfirmationService extends UserTokenService
/**
* Check if confirmation is required in this instance.
*
* @return bool
*/
public function confirmationRequired(): bool

View File

@ -1,10 +1,10 @@
<?php namespace BookStack\Auth\Access;
<?php
namespace BookStack\Auth\Access;
use BookStack\Auth\Role;
use BookStack\Auth\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class ExternalAuthService
{
@ -19,6 +19,7 @@ class ExternalAuthService
}
$roleName = str_replace(' ', '-', trim(strtolower($role->display_name)));
return in_array($roleName, $groupNames);
}
@ -57,7 +58,7 @@ class ExternalAuthService
}
/**
* Sync the groups to the user roles for the current user
* Sync the groups to the user roles for the current user.
*/
public function syncWithGroups(User $user, array $userGroups): void
{

View File

@ -7,7 +7,6 @@ use Illuminate\Contracts\Auth\UserProvider;
class ExternalBaseUserProvider implements UserProvider
{
/**
* The user model.
*
@ -17,6 +16,7 @@ class ExternalBaseUserProvider implements UserProvider
/**
* LdapUserProvider constructor.
*
* @param $model
*/
public function __construct(string $model)
@ -32,13 +32,15 @@ class ExternalBaseUserProvider implements UserProvider
public function createModel()
{
$class = '\\' . ltrim($this->model, '\\');
return new $class;
return new $class();
}
/**
* Retrieve a user by their unique identifier.
*
* @param mixed $identifier
*
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById($identifier)
@ -51,6 +53,7 @@ class ExternalBaseUserProvider implements UserProvider
*
* @param mixed $identifier
* @param string $token
*
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByToken($identifier, $token)
@ -58,12 +61,12 @@ class ExternalBaseUserProvider implements UserProvider
return null;
}
/**
* Update the "remember me" token for the given user in storage.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string $token
*
* @return void
*/
public function updateRememberToken(Authenticatable $user, $token)
@ -75,12 +78,14 @@ class ExternalBaseUserProvider implements UserProvider
* Retrieve a user by the given credentials.
*
* @param array $credentials
*
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials)
{
// Search current user base by looking up a uid
$model = $this->createModel();
return $model->newQuery()
->where('external_auth_id', $credentials['external_auth_id'])
->first();
@ -91,6 +96,7 @@ class ExternalBaseUserProvider implements UserProvider
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param array $credentials
*
* @return bool
*/
public function validateCredentials(Authenticatable $user, array $credentials)

View File

@ -119,6 +119,7 @@ class ExternalBaseSessionGuard implements StatefulGuard
* Log a user into the application without sessions or cookies.
*
* @param array $credentials
*
* @return bool
*/
public function once(array $credentials = [])
@ -136,6 +137,7 @@ class ExternalBaseSessionGuard implements StatefulGuard
* Log the given user ID into the application without sessions or cookies.
*
* @param mixed $id
*
* @return \Illuminate\Contracts\Auth\Authenticatable|false
*/
public function onceUsingId($id)
@ -153,6 +155,7 @@ class ExternalBaseSessionGuard implements StatefulGuard
* Validate a user's credentials.
*
* @param array $credentials
*
* @return bool
*/
public function validate(array $credentials = [])
@ -160,12 +163,12 @@ class ExternalBaseSessionGuard implements StatefulGuard
return false;
}
/**
* Attempt to authenticate a user using the given credentials.
*
* @param array $credentials
* @param bool $remember
*
* @return bool
*/
public function attempt(array $credentials = [], $remember = false)
@ -178,6 +181,7 @@ class ExternalBaseSessionGuard implements StatefulGuard
*
* @param mixed $id
* @param bool $remember
*
* @return \Illuminate\Contracts\Auth\Authenticatable|false
*/
public function loginUsingId($id, $remember = false)
@ -196,6 +200,7 @@ class ExternalBaseSessionGuard implements StatefulGuard
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param bool $remember
*
* @return void
*/
public function login(AuthenticatableContract $user, $remember = false)
@ -209,6 +214,7 @@ class ExternalBaseSessionGuard implements StatefulGuard
* Update the session with the given ID.
*
* @param string $id
*
* @return void
*/
protected function updateSession($id)
@ -289,6 +295,7 @@ class ExternalBaseSessionGuard implements StatefulGuard
* Set the current user.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
*
* @return $this
*/
public function setUser(AuthenticatableContract $user)

View File

@ -6,8 +6,8 @@ use BookStack\Auth\Access\LdapService;
use BookStack\Auth\Access\RegistrationService;
use BookStack\Auth\User;
use BookStack\Exceptions\LdapException;
use BookStack\Exceptions\LoginAttemptException;
use BookStack\Exceptions\LoginAttemptEmailNeededException;
use BookStack\Exceptions\LoginAttemptException;
use BookStack\Exceptions\UserRegistrationException;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Session\Session;
@ -15,7 +15,6 @@ use Illuminate\Support\Str;
class LdapSessionGuard extends ExternalBaseSessionGuard
{
protected $ldapService;
/**
@ -36,8 +35,10 @@ class LdapSessionGuard extends ExternalBaseSessionGuard
* Validate a user's credentials.
*
* @param array $credentials
* @return bool
*
* @throws LdapException
*
* @return bool
*/
public function validate(array $credentials = [])
{
@ -45,7 +46,7 @@ class LdapSessionGuard extends ExternalBaseSessionGuard
if (isset($userDetails['uid'])) {
$this->lastAttempted = $this->provider->retrieveByCredentials([
'external_auth_id' => $userDetails['uid']
'external_auth_id' => $userDetails['uid'],
]);
}
@ -57,9 +58,11 @@ class LdapSessionGuard extends ExternalBaseSessionGuard
*
* @param array $credentials
* @param bool $remember
* @return bool
*
* @throws LoginAttemptException
* @throws LdapException
*
* @return bool
*/
public function attempt(array $credentials = [], $remember = false)
{
@ -69,7 +72,7 @@ class LdapSessionGuard extends ExternalBaseSessionGuard
$user = null;
if (isset($userDetails['uid'])) {
$this->lastAttempted = $user = $this->provider->retrieveByCredentials([
'external_auth_id' => $userDetails['uid']
'external_auth_id' => $userDetails['uid'],
]);
}
@ -96,11 +99,13 @@ class LdapSessionGuard extends ExternalBaseSessionGuard
}
$this->login($user, $remember);
return true;
}
/**
* Create a new user from the given ldap credentials and login credentials
* Create a new user from the given ldap credentials and login credentials.
*
* @throws LoginAttemptEmailNeededException
* @throws LoginAttemptException
* @throws UserRegistrationException
@ -122,6 +127,7 @@ class LdapSessionGuard extends ExternalBaseSessionGuard
$user = $this->registrationService->registerUser($details, null, false);
$this->ldapService->saveAndAttachAvatar($user, $ldapUserDetails);
return $user;
}
}

View File

@ -3,7 +3,7 @@
namespace BookStack\Auth\Access\Guards;
/**
* Saml2 Session Guard
* Saml2 Session Guard.
*
* The saml2 login process is async in nature meaning it does not fit very well
* into the default laravel 'Guard' auth flow. Instead most of the logic is done
@ -16,6 +16,7 @@ class Saml2SessionGuard extends ExternalBaseSessionGuard
* Validate a user's credentials.
*
* @param array $credentials
*
* @return bool
*/
public function validate(array $credentials = [])
@ -28,6 +29,7 @@ class Saml2SessionGuard extends ExternalBaseSessionGuard
*
* @param array $credentials
* @param bool $remember
*
* @return bool
*/
public function attempt(array $credentials = [], $remember = false)

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth\Access;
<?php
namespace BookStack\Auth\Access;
/**
* Class Ldap
@ -7,11 +9,12 @@
*/
class Ldap
{
/**
* Connect to a LDAP server.
*
* @param string $hostName
* @param int $port
*
* @return resource
*/
public function connect($hostName, $port)
@ -21,9 +24,11 @@ class Ldap
/**
* Set the value of a LDAP option for the given connection.
*
* @param resource $ldapConnection
* @param int $option
* @param mixed $value
*
* @return bool
*/
public function setOption($ldapConnection, $option, $value)
@ -41,8 +46,10 @@ class Ldap
/**
* Set the version number for the given ldap connection.
*
* @param $ldapConnection
* @param $version
*
* @return bool
*/
public function setVersion($ldapConnection, $version)
@ -52,10 +59,12 @@ class Ldap
/**
* Search LDAP tree using the provided filter.
*
* @param resource $ldapConnection
* @param string $baseDn
* @param string $filter
* @param array|null $attributes
*
* @return resource
*/
public function search($ldapConnection, $baseDn, $filter, array $attributes = null)
@ -65,8 +74,10 @@ class Ldap
/**
* Get entries from an ldap search result.
*
* @param resource $ldapConnection
* @param resource $ldapSearchResult
*
* @return array
*/
public function getEntries($ldapConnection, $ldapSearchResult)
@ -76,23 +87,28 @@ class Ldap
/**
* Search and get entries immediately.
*
* @param resource $ldapConnection
* @param string $baseDn
* @param string $filter
* @param array|null $attributes
*
* @return resource
*/
public function searchAndGetEntries($ldapConnection, $baseDn, $filter, array $attributes = null)
{
$search = $this->search($ldapConnection, $baseDn, $filter, $attributes);
return $this->getEntries($ldapConnection, $search);
}
/**
* Bind to LDAP directory.
*
* @param resource $ldapConnection
* @param string $bindRdn
* @param string $bindPassword
*
* @return bool
*/
public function bind($ldapConnection, $bindRdn = null, $bindPassword = null)
@ -102,8 +118,10 @@ class Ldap
/**
* Explode a LDAP dn string into an array of components.
*
* @param string $dn
* @param int $withAttrib
*
* @return array
*/
public function explodeDn(string $dn, int $withAttrib)
@ -113,12 +131,14 @@ class Ldap
/**
* Escape a string for use in an LDAP filter.
*
* @param string $value
* @param string $ignore
* @param int $flags
*
* @return string
*/
public function escape(string $value, string $ignore = "", int $flags = 0)
public function escape(string $value, string $ignore = '', int $flags = 0)
{
return ldap_escape($value, $ignore, $flags);
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth\Access;
<?php
namespace BookStack\Auth\Access;
use BookStack\Auth\User;
use BookStack\Exceptions\JsonDebugException;
@ -13,7 +15,6 @@ use Illuminate\Support\Facades\Log;
*/
class LdapService extends ExternalAuthService
{
protected $ldap;
protected $ldapConnection;
protected $userAvatars;
@ -33,6 +34,7 @@ class LdapService extends ExternalAuthService
/**
* Check if groups should be synced.
*
* @return bool
*/
public function shouldSyncGroups()
@ -42,6 +44,7 @@ class LdapService extends ExternalAuthService
/**
* Search for attributes for a specific user on the ldap.
*
* @throws LdapException
*/
private function getUserWithAttributes(string $userName, array $attributes): ?array
@ -73,6 +76,7 @@ class LdapService extends ExternalAuthService
/**
* Get the details of a user from LDAP using the given username.
* User found via configurable user filter.
*
* @throws LdapException
*/
public function getUserDetails(string $userName): ?array
@ -137,6 +141,7 @@ class LdapService extends ExternalAuthService
/**
* Check if the given credentials are valid for the given user.
*
* @throws LdapException
*/
public function validateUserCredentials(?array $ldapUserDetails, string $password): bool
@ -146,6 +151,7 @@ class LdapService extends ExternalAuthService
}
$ldapConnection = $this->getConnection();
try {
$ldapBind = $this->ldap->bind($ldapConnection, $ldapUserDetails['dn'], $password);
} catch (ErrorException $e) {
@ -158,7 +164,9 @@ class LdapService extends ExternalAuthService
/**
* Bind the system user to the LDAP connection using the given credentials
* otherwise anonymous access is attempted.
*
* @param $connection
*
* @throws LdapException
*/
protected function bindSystemUser($connection)
@ -181,8 +189,10 @@ class LdapService extends ExternalAuthService
/**
* Get the connection to the LDAP server.
* Creates a new connection if one does not exist.
* @return resource
*
* @throws LdapException
*
* @return resource
*/
protected function getConnection()
{
@ -222,6 +232,7 @@ class LdapService extends ExternalAuthService
}
$this->ldapConnection = $ldapConnection;
return $this->ldapConnection;
}
@ -241,6 +252,7 @@ class LdapService extends ExternalAuthService
// Otherwise, extract the port out
$hostName = $serverNameParts[0];
$ldapPort = (count($serverNameParts) > 1) ? intval($serverNameParts[1]) : 389;
return ['host' => $hostName, 'port' => $ldapPort];
}
@ -254,11 +266,13 @@ class LdapService extends ExternalAuthService
$newKey = '${' . $key . '}';
$newAttrs[$newKey] = $this->ldap->escape($attrText);
}
return strtr($filterString, $newAttrs);
}
/**
* Get the groups a user is a part of on ldap.
*
* @throws LdapException
*/
public function getUserGroups(string $userName): array
@ -272,11 +286,13 @@ class LdapService extends ExternalAuthService
$userGroups = $this->groupFilter($user);
$userGroups = $this->getGroupsRecursive($userGroups, []);
return $userGroups;
}
/**
* Get the parent groups of an array of groups.
*
* @throws LdapException
*/
private function getGroupsRecursive(array $groupsArray, array $checked): array
@ -303,6 +319,7 @@ class LdapService extends ExternalAuthService
/**
* Get the parent groups of a single group.
*
* @throws LdapException
*/
private function getGroupGroups(string $groupName): array
@ -351,6 +368,7 @@ class LdapService extends ExternalAuthService
/**
* Sync the LDAP groups to the user roles for the current user.
*
* @throws LdapException
*/
public function syncGroups(User $user, string $username)

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth\Access;
<?php
namespace BookStack\Auth\Access;
use BookStack\Actions\ActivityType;
use BookStack\Auth\SocialAccount;
@ -12,7 +14,6 @@ use Exception;
class RegistrationService
{
protected $userRepo;
protected $emailConfirmationService;
@ -27,6 +28,7 @@ class RegistrationService
/**
* Check whether or not registrations are allowed in the app settings.
*
* @throws UserRegistrationException
*/
public function ensureRegistrationAllowed()
@ -44,11 +46,13 @@ class RegistrationService
{
$authMethod = config('auth.method');
$authMethodsWithRegistration = ['standard'];
return in_array($authMethod, $authMethodsWithRegistration) && setting('registration-enabled');
}
/**
* The registrations flow for all users.
*
* @throws UserRegistrationException
*/
public function registerUser(array $userData, ?SocialAccount $socialAccount = null, bool $emailConfirmed = false): User
@ -84,6 +88,7 @@ class RegistrationService
session()->flash('sent-email-confirmation', true);
} catch (Exception $e) {
$message = trans('auth.email_confirm_send_error');
throw new UserRegistrationException($message, '/register/confirm');
}
}
@ -94,6 +99,7 @@ class RegistrationService
/**
* Ensure that the given email meets any active email domain registration restrictions.
* Throws if restrictions are active and the email does not match an allowed domain.
*
* @throws UserRegistrationException
*/
protected function ensureEmailDomainAllowed(string $userEmail): void
@ -105,9 +111,10 @@ class RegistrationService
}
$restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict));
$userEmailDomain = $domain = mb_substr(mb_strrchr($userEmail, "@"), 1);
$userEmailDomain = $domain = mb_substr(mb_strrchr($userEmail, '@'), 1);
if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
$redirect = $this->registrationAllowed() ? '/register' : '/login';
throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), $redirect);
}
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth\Access;
<?php
namespace BookStack\Auth\Access;
use BookStack\Actions\ActivityType;
use BookStack\Auth\User;
@ -37,12 +39,14 @@ class Saml2Service extends ExternalAuthService
/**
* Initiate a login flow.
*
* @throws Error
*/
public function login(): array
{
$toolKit = $this->getToolkit();
$returnRoute = url('/saml2/acs');
return [
'url' => $toolKit->login($returnRoute, [], false, false, true),
'id' => $toolKit->getLastRequestID(),
@ -51,6 +55,7 @@ class Saml2Service extends ExternalAuthService
/**
* Initiate a logout flow.
*
* @throws Error
*/
public function logout(): array
@ -78,6 +83,7 @@ class Saml2Service extends ExternalAuthService
* Process the ACS response from the idp and return the
* matching, or new if registration active, user matched to the idp.
* Returns null if not authenticated.
*
* @throws Error
* @throws SamlException
* @throws ValidationError
@ -108,6 +114,7 @@ class Saml2Service extends ExternalAuthService
/**
* Process a response for the single logout service.
*
* @throws Error
*/
public function processSlsResponse(?string $requestId): ?string
@ -124,6 +131,7 @@ class Saml2Service extends ExternalAuthService
}
$this->actionLogout();
return $redirect;
}
@ -138,6 +146,7 @@ class Saml2Service extends ExternalAuthService
/**
* Get the metadata for this service provider.
*
* @throws Error
*/
public function metadata(): string
@ -159,6 +168,7 @@ class Saml2Service extends ExternalAuthService
/**
* Load the underlying Onelogin SAML2 toolkit.
*
* @throws Error
* @throws Exception
*/
@ -178,6 +188,7 @@ class Saml2Service extends ExternalAuthService
$spSettings = $this->loadOneloginServiceProviderDetails();
$settings = array_replace_recursive($settings, $spSettings, $metaDataSettings, $overrides);
return new Auth($settings);
}
@ -192,13 +203,13 @@ class Saml2Service extends ExternalAuthService
'url' => url('/saml2/acs'),
],
'singleLogoutService' => [
'url' => url('/saml2/sls')
'url' => url('/saml2/sls'),
],
];
return [
'baseurl' => url('/saml2'),
'sp' => $spDetails
'sp' => $spDetails,
];
}
@ -211,7 +222,7 @@ class Saml2Service extends ExternalAuthService
}
/**
* Calculate the display name
* Calculate the display name.
*/
protected function getUserDisplayName(array $samlAttributes, string $defaultValue): string
{
@ -297,6 +308,7 @@ class Saml2Service extends ExternalAuthService
$data = $data[0];
break;
}
return $data;
}
@ -315,6 +327,7 @@ class Saml2Service extends ExternalAuthService
/**
* Get the user from the database for the specified details.
*
* @throws UserRegistrationException
*/
protected function getOrRegisterUser(array $userDetails): ?User
@ -340,6 +353,7 @@ class Saml2Service extends ExternalAuthService
/**
* Process the SAML response for a user. Login the user when
* they exist, optionally registering them automatically.
*
* @throws SamlException
* @throws JsonDebugException
* @throws UserRegistrationException
@ -378,6 +392,7 @@ class Saml2Service extends ExternalAuthService
auth()->login($user);
Activity::add(ActivityType::AUTH_LOGIN, "saml2; {$user->logDescriptor()}");
Theme::dispatch(ThemeEvents::AUTH_LOGIN, 'saml2', $user);
return $user;
}
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth\Access;
<?php
namespace BookStack\Auth\Access;
use BookStack\Actions\ActivityType;
use BookStack\Auth\SocialAccount;
@ -21,12 +23,14 @@ class SocialAuthService
{
/**
* The core socialite library used.
*
* @var Socialite
*/
protected $socialite;
/**
* The default built-in social drivers we support.
*
* @var string[]
*/
protected $validSocialDrivers = [
@ -39,7 +43,7 @@ class SocialAuthService
'okta',
'gitlab',
'twitch',
'discord'
'discord',
];
/**
@ -47,6 +51,7 @@ class SocialAuthService
* for an initial redirect action.
* Array is keyed by social driver name.
* Callbacks are passed an instance of the driver.
*
* @var array<string, callable>
*/
protected $configureForRedirectCallbacks = [];
@ -61,26 +66,31 @@ class SocialAuthService
/**
* Start the social login path.
*
* @throws SocialDriverNotConfigured
*/
public function startLogIn(string $socialDriver): RedirectResponse
{
$driver = $this->validateDriver($socialDriver);
return $this->getDriverForRedirect($driver)->redirect();
}
/**
* Start the social registration process
* Start the social registration process.
*
* @throws SocialDriverNotConfigured
*/
public function startRegister(string $socialDriver): RedirectResponse
{
$driver = $this->validateDriver($socialDriver);
return $this->getDriverForRedirect($driver)->redirect();
}
/**
* Handle the social registration process on callback.
*
* @throws UserRegistrationException
*/
public function handleRegistrationCallback(string $socialDriver, SocialUser $socialUser): SocialUser
@ -92,6 +102,7 @@ class SocialAuthService
if (User::query()->where('email', '=', $socialUser->getEmail())->exists()) {
$email = $socialUser->getEmail();
throw new UserRegistrationException(trans('errors.error_user_exists_different_creds', ['email' => $email]), '/login');
}
@ -100,16 +111,19 @@ class SocialAuthService
/**
* Get the social user details via the social driver.
*
* @throws SocialDriverNotConfigured
*/
public function getSocialUser(string $socialDriver): SocialUser
{
$driver = $this->validateDriver($socialDriver);
return $this->socialite->driver($driver)->user();
}
/**
* Handle the login process on a oAuth callback.
*
* @throws SocialSignInAccountNotUsed
*/
public function handleLoginCallback(string $socialDriver, SocialUser $socialUser)
@ -128,6 +142,7 @@ class SocialAuthService
auth()->login($socialAccount->user);
Activity::add(ActivityType::AUTH_LOGIN, $socialAccount);
Theme::dispatch(ThemeEvents::AUTH_LOGIN, $socialDriver, $socialAccount->user);
return redirect()->intended('/');
}
@ -137,18 +152,21 @@ class SocialAuthService
$account = $this->newSocialAccount($socialDriver, $socialUser);
$currentUser->socialAccounts()->save($account);
session()->flash('success', trans('settings.users_social_connected', ['socialAccount' => $titleCaseDriver]));
return redirect($currentUser->getEditUrl());
}
// 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) {
session()->flash('error', trans('errors.social_account_existing', ['socialAccount' => $titleCaseDriver]));
return redirect($currentUser->getEditUrl());
}
// 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) {
session()->flash('error', trans('errors.social_account_already_used_existing', ['socialAccount' => $titleCaseDriver]));
return redirect($currentUser->getEditUrl());
}
@ -163,6 +181,7 @@ class SocialAuthService
/**
* Ensure the social driver is correct and supported.
*
* @throws SocialDriverNotConfigured
*/
protected function validateDriver(string $socialDriver): string
@ -188,6 +207,7 @@ class SocialAuthService
$lowerName = strtolower($driver);
$configPrefix = 'services.' . $lowerName . '.';
$config = [config($configPrefix . 'client_id'), config($configPrefix . 'client_secret'), config('services.callback_url')];
return !in_array(false, $config) && !in_array(null, $config);
}
@ -239,7 +259,7 @@ class SocialAuthService
return new SocialAccount([
'driver' => $socialDriver,
'driver_id' => $socialUser->getId(),
'avatar' => $socialUser->getAvatar()
'avatar' => $socialUser->getAvatar(),
]);
}
@ -252,7 +272,7 @@ class SocialAuthService
}
/**
* Provide redirect options per service for the Laravel Socialite driver
* Provide redirect options per service for the Laravel Socialite driver.
*/
protected function getDriverForRedirect(string $driverName): Provider
{

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth\Access;
<?php
namespace BookStack\Auth\Access;
use BookStack\Auth\User;
use BookStack\Notifications\UserInvite;
@ -11,6 +13,7 @@ class UserInviteService extends UserTokenService
/**
* Send an invitation to a user to sign into BookStack
* Removes existing invitation tokens.
*
* @param User $user
*/
public function sendInvitation(User $user)

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth\Access;
<?php
namespace BookStack\Auth\Access;
use BookStack\Auth\User;
use BookStack\Exceptions\UserTokenExpiredException;
@ -10,15 +12,16 @@ use stdClass;
class UserTokenService
{
/**
* Name of table where user tokens are stored.
*
* @var string
*/
protected $tokenTable = 'user_tokens';
/**
* Token expiry time in hours.
*
* @var int
*/
protected $expiryTime = 24;
@ -27,6 +30,7 @@ class UserTokenService
/**
* UserTokenService constructor.
*
* @param Database $db
*/
public function __construct(Database $db)
@ -36,7 +40,9 @@ class UserTokenService
/**
* Delete all email confirmations that belong to a user.
*
* @param User $user
*
* @return mixed
*/
public function deleteByUser(User $user)
@ -48,10 +54,13 @@ class UserTokenService
/**
* Get the user id from a token, while check the token exists and has not expired.
*
* @param string $token
* @return int
*
* @throws UserTokenNotFoundException
* @throws UserTokenExpiredException
*
* @return int
*/
public function checkTokenAndGetUserId(string $token): int
{
@ -70,6 +79,7 @@ class UserTokenService
/**
* Creates a unique token within the email confirmation database.
*
* @return string
*/
protected function generateToken(): string
@ -78,12 +88,15 @@ class UserTokenService
while ($this->tokenExists($token)) {
$token = Str::random(25);
}
return $token;
}
/**
* Generate and store a token for the given user.
*
* @param User $user
*
* @return string
*/
protected function createTokenForUser(User $user): string
@ -93,14 +106,17 @@ class UserTokenService
'user_id' => $user->id,
'token' => $token,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
'updated_at' => Carbon::now(),
]);
return $token;
}
/**
* Check if the given token exists.
*
* @param string $token
*
* @return bool
*/
protected function tokenExists(string $token): bool
@ -111,7 +127,9 @@ class UserTokenService
/**
* Get a token entry for the given token.
*
* @param string $token
*
* @return object|null
*/
protected function getEntryByToken(string $token)
@ -123,7 +141,9 @@ class UserTokenService
/**
* Check if the given token entry has expired.
*
* @param stdClass $tokenEntry
*
* @return bool
*/
protected function entryExpired(stdClass $tokenEntry): bool

View File

@ -1,15 +1,17 @@
<?php namespace BookStack\Auth\Permissions;
<?php
namespace BookStack\Auth\Permissions;
use BookStack\Model;
class EntityPermission extends Model
{
protected $fillable = ['role_id', 'action'];
public $timestamps = false;
/**
* Get all this restriction's attached entity.
*
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function restrictable()

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth\Permissions;
<?php
namespace BookStack\Auth\Permissions;
use BookStack\Auth\Role;
use BookStack\Entities\Models\Entity;

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth\Permissions;
<?php
namespace BookStack\Auth\Permissions;
use BookStack\Auth\Role;
use BookStack\Auth\User;
@ -48,7 +50,7 @@ class PermissionService
}
/**
* Set the database connection
* Set the database connection.
*/
public function setConnection(Connection $connection)
{
@ -56,7 +58,8 @@ class PermissionService
}
/**
* Prepare the local entity cache and ensure it's empty
* Prepare the local entity cache and ensure it's empty.
*
* @param Entity[] $entities
*/
protected function readyEntityCache(array $entities = [])
@ -73,7 +76,7 @@ class PermissionService
}
/**
* Get a book via ID, Checks local cache
* Get a book via ID, Checks local cache.
*/
protected function getBook(int $bookId): ?Book
{
@ -85,7 +88,7 @@ class PermissionService
}
/**
* Get a chapter via ID, Checks local cache
* Get a chapter via ID, Checks local cache.
*/
protected function getChapter(int $chapterId): ?Chapter
{
@ -151,12 +154,13 @@ class PermissionService
},
'pages' => function ($query) {
$query->withTrashed()->select(['id', 'restricted', 'owned_by', 'book_id', 'chapter_id']);
}
},
]);
}
/**
* Build joint permissions for the given shelf and role combinations.
*
* @throws Throwable
*/
protected function buildJointPermissionsForShelves(EloquentCollection $shelves, array $roles, bool $deleteOld = false)
@ -169,6 +173,7 @@ class PermissionService
/**
* Build joint permissions for the given book and role combinations.
*
* @throws Throwable
*/
protected function buildJointPermissionsForBooks(EloquentCollection $books, array $roles, bool $deleteOld = false)
@ -193,6 +198,7 @@ class PermissionService
/**
* Rebuild the entity jointPermissions for a particular entity.
*
* @throws Throwable
*/
public function buildJointPermissionsForEntity(Entity $entity)
@ -201,6 +207,7 @@ class PermissionService
if ($entity instanceof Book) {
$books = $this->bookFetchQuery()->where('id', '=', $entity->id)->get();
$this->buildJointPermissionsForBooks($books, Role::query()->get()->all(), true);
return;
}
@ -224,6 +231,7 @@ class PermissionService
/**
* Rebuild the entity jointPermissions for a collection of entities.
*
* @throws Throwable
*/
public function buildJointPermissionsForEntities(array $entities)
@ -263,6 +271,7 @@ class PermissionService
/**
* Delete all of the entity jointPermissions for a list of entities.
*
* @param Role[] $roles
*/
protected function deleteManyJointPermissionsForRoles($roles)
@ -275,7 +284,9 @@ class PermissionService
/**
* Delete the entity jointPermissions for a particular entity.
*
* @param Entity $entity
*
* @throws Throwable
*/
public function deleteJointPermissionsForEntity(Entity $entity)
@ -285,7 +296,9 @@ class PermissionService
/**
* Delete all of the entity jointPermissions for a list of entities.
*
* @param Entity[] $entities
*
* @throws Throwable
*/
protected function deleteManyJointPermissionsForEntities(array $entities)
@ -295,7 +308,6 @@ class PermissionService
}
$this->db->transaction(function () use ($entities) {
foreach (array_chunk($entities, 1000) as $entityChunk) {
$query = $this->db->table('joint_permissions');
foreach ($entityChunk as $entity) {
@ -311,8 +323,10 @@ class PermissionService
/**
* Create & Save entity jointPermissions for many entities and roles.
*
* @param Entity[] $entities
* @param Role[] $roles
*
* @throws Throwable
*/
protected function createManyJointPermissions(array $entities, array $roles)
@ -363,7 +377,6 @@ class PermissionService
});
}
/**
* Get the actions related to an entity.
*/
@ -376,6 +389,7 @@ class PermissionService
if ($entity instanceof Book) {
$baseActions[] = 'chapter-create';
}
return $baseActions;
}
@ -397,6 +411,7 @@ class PermissionService
if ($entity->restricted) {
$hasAccess = $this->mapHasActiveRestriction($permissionMap, $entity, $role, $restrictionAction);
return $this->createJointPermissionDataArray($entity, $role, $action, $hasAccess, $hasAccess);
}
@ -433,6 +448,7 @@ class PermissionService
protected function mapHasActiveRestriction(array $entityMap, Entity $entity, Role $role, string $action): bool
{
$key = $entity->getMorphClass() . ':' . $entity->getRawAttribute('id') . ':' . $role->getRawAttribute('id') . ':' . $action;
return $entityMap[$key] ?? false;
}
@ -455,6 +471,7 @@ class PermissionService
/**
* Checks if an entity has a restriction set upon it.
*
* @param HasCreatorAndUpdater|HasOwner $ownable
*/
public function checkOwnableUserAccess(Model $ownable, string $permission): bool
@ -473,7 +490,8 @@ class PermissionService
$ownPermission = $user && $user->can($permission . '-own');
$ownerField = ($ownable instanceof Entity) ? 'owned_by' : 'created_by';
$isOwner = $user && $user->id === $ownable->$ownerField;
return ($allPermission || ($isOwner && $ownPermission));
return $allPermission || ($isOwner && $ownPermission);
}
// Handle abnormal create jointPermissions
@ -483,6 +501,7 @@ class PermissionService
$hasAccess = $this->entityRestrictionQuery($baseQuery, $action)->count() > 0;
$this->clean();
return $hasAccess;
}
@ -509,6 +528,7 @@ class PermissionService
$hasPermission = $permissionQuery->count() > 0;
$this->clean();
return $hasPermission;
}
@ -529,6 +549,7 @@ class PermissionService
});
$this->clean();
return $q;
}
@ -539,6 +560,7 @@ class PermissionService
public function restrictEntityQuery(Builder $query, string $ability = 'view'): Builder
{
$this->clean();
return $query->where(function (Builder $parentQuery) use ($ability) {
$parentQuery->whereHas('jointPermissions', function (Builder $permissionQuery) use ($ability) {
$permissionQuery->whereIn('role_id', $this->getCurrentUserRoles())
@ -580,6 +602,7 @@ class PermissionService
/**
* Filter items that have entities set as a polymorphic relation.
*
* @param Builder|\Illuminate\Database\Query\Builder $query
*/
public function filterRestrictedEntityRelations($query, string $tableName, string $entityIdColumn, string $entityTypeColumn, string $action = 'view')
@ -600,6 +623,7 @@ class PermissionService
});
$this->clean();
return $q;
}
@ -628,12 +652,14 @@ class PermissionService
});
$this->clean();
return $q;
}
/**
* Add the query for checking the given user id has permission
* within the join_permissions table.
*
* @param QueryBuilder|Builder $query
*/
protected function addJointHasPermissionCheck($query, int $userIdToCheck)
@ -645,7 +671,7 @@ class PermissionService
}
/**
* Get the current user
* Get the current user.
*/
private function currentUser(): User
{

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth\Permissions;
<?php
namespace BookStack\Auth\Permissions;
use BookStack\Actions\ActivityType;
use BookStack\Auth\Role;
@ -9,7 +11,6 @@ use Illuminate\Database\Eloquent\Collection;
class PermissionsRepo
{
protected $permission;
protected $role;
protected $permissionService;
@ -62,6 +63,7 @@ class PermissionsRepo
$this->assignRolePermissions($role, $permissions);
$this->permissionService->buildJointPermissionForRole($role);
Activity::add(ActivityType::ROLE_CREATE, $role);
return $role;
}
@ -116,6 +118,7 @@ class PermissionsRepo
* Check it's not an admin role or set as default before deleting.
* If an migration Role ID is specified the users assign to the current role
* will be added to the role of the specified id.
*
* @throws PermissionsException
* @throws Exception
*/

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth\Permissions;
<?php
namespace BookStack\Auth\Permissions;
use BookStack\Auth\Role;
use BookStack\Model;
@ -18,7 +20,9 @@ class RolePermission extends Model
/**
* Get the permission object by name.
*
* @param $name
*
* @return mixed
*/
public static function getByName($name)

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth;
<?php
namespace BookStack\Auth;
use BookStack\Auth\Permissions\JointPermission;
use BookStack\Auth\Permissions\RolePermission;
@ -9,7 +11,8 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* Class Role
* Class Role.
*
* @property int $id
* @property string $display_name
* @property string $description
@ -18,7 +21,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
*/
class Role extends Model implements Loggable
{
protected $fillable = ['display_name', 'description', 'external_auth_id'];
/**
@ -56,6 +58,7 @@ class Role extends Model implements Loggable
return true;
}
}
return false;
}

View File

@ -1,16 +1,18 @@
<?php namespace BookStack\Auth;
<?php
namespace BookStack\Auth;
use BookStack\Interfaces\Loggable;
use BookStack\Model;
/**
* Class SocialAccount
* Class SocialAccount.
*
* @property string $driver
* @property User $user
*/
class SocialAccount extends Model implements Loggable
{
protected $fillable = ['user_id', 'driver', 'driver_id', 'timestamps'];
public function user()

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth;
<?php
namespace BookStack\Auth;
use BookStack\Actions\Favourite;
use BookStack\Api\ApiToken;
@ -22,7 +24,8 @@ use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Collection;
/**
* Class User
* Class User.
*
* @property string $id
* @property string $name
* @property string $slug
@ -38,16 +41,20 @@ use Illuminate\Support\Collection;
*/
class User extends Model implements AuthenticatableContract, CanResetPasswordContract, Loggable, Sluggable
{
use Authenticatable, CanResetPassword, Notifiable;
use Authenticatable;
use CanResetPassword;
use Notifiable;
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name', 'email'];
@ -56,6 +63,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = [
@ -65,12 +73,14 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
/**
* This holds the user's permissions when loaded.
*
* @var ?Collection
*/
protected $permissions;
/**
* This holds the default user when loaded.
*
* @var null|User
*/
protected static $defaultUser = null;
@ -85,6 +95,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
}
static::$defaultUser = static::query()->where('system_name', '=', 'public')->first();
return static::$defaultUser;
}
@ -98,6 +109,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
/**
* The roles that belong to the user.
*
* @return BelongsToMany
*/
public function roles()
@ -105,6 +117,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
if ($this->id === 0) {
return;
}
return $this->belongsToMany(Role::class);
}
@ -194,7 +207,9 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
/**
* Check if the user has a social account,
* If a driver is passed it checks for that single account type.
*
* @param bool|string $socialDriver
*
* @return bool
*/
public function hasSocialAccount($socialDriver = false)
@ -207,7 +222,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
}
/**
* Returns a URL to the user's avatar
* Returns a URL to the user's avatar.
*/
public function getAvatar(int $size = 50): string
{
@ -222,6 +237,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
} catch (Exception $err) {
$avatar = $default;
}
return $avatar;
}
@ -268,6 +284,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
public function getEditUrl(string $path = ''): string
{
$uri = '/settings/users/' . $this->id . '/' . trim($path, '/');
return url(rtrim($uri, '/'));
}
@ -298,7 +315,9 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
/**
* Send the password reset notification.
*
* @param string $token
*
* @return void
*/
public function sendPasswordResetNotification($token)
@ -320,6 +339,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
public function refreshSlug(): string
{
$this->slug = app(SlugGenerator::class)->generate($this);
return $this->slug;
}
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Auth;
<?php
namespace BookStack\Auth;
use Activity;
use BookStack\Entities\EntityProvider;
@ -96,6 +98,7 @@ class UserRepo
/**
* Assign a user to a system-level role.
*
* @throws NotFoundException
*/
public function attachSystemRole(User $user, string $systemRoleName)
@ -126,6 +129,7 @@ class UserRepo
/**
* Set the assigned user roles via an array of role IDs.
*
* @throws UserUpdateException
*/
public function setUserRoles(User $user, array $roles)
@ -176,6 +180,7 @@ class UserRepo
/**
* Remove the given user from storage, Delete all related content.
*
* @throws Exception
*/
public function destroy(User $user, ?int $newOwnerId = null)
@ -201,7 +206,7 @@ class UserRepo
*/
protected function migrateOwnership(User $fromUser, User $toUser)
{
$entities = (new EntityProvider)->all();
$entities = (new EntityProvider())->all();
foreach ($entities as $instance) {
$instance->newQuery()->where('owned_by', '=', $fromUser->id)
->update(['owned_by' => $toUser->id]);
@ -242,6 +247,7 @@ class UserRepo
public function getAssetCounts(User $user): array
{
$createdBy = ['created_by' => $user->id];
return [
'pages' => Page::visible()->where($createdBy)->count(),
'chapters' => Chapter::visible()->where($createdBy)->count(),

View File

@ -18,6 +18,6 @@ return [
'max_item_count' => env('API_MAX_ITEM_COUNT', 500),
// The number of API requests that can be made per minute by a single user.
'requests_per_minute' => env('API_REQUESTS_PER_MIN', 180)
'requests_per_minute' => env('API_REQUESTS_PER_MIN', 180),
];

View File

@ -56,7 +56,7 @@ return [
'locale' => env('APP_LANG', 'en'),
// Locales available
'locales' => ['en', 'ar', 'bg', 'bs', 'ca', 'cs', 'da', 'de', 'de_informal', 'es', 'es_AR', 'fa', 'fr', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'lv', 'nl', 'nb', 'pt', 'pt_BR', 'sk', 'sl', 'sv', 'pl', 'ru', 'th', 'tr', 'uk', 'vi', 'zh_CN', 'zh_TW',],
'locales' => ['en', 'ar', 'bg', 'bs', 'ca', 'cs', 'da', 'de', 'de_informal', 'es', 'es_AR', 'fa', 'fr', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'lv', 'nl', 'nb', 'pt', 'pt_BR', 'sk', 'sl', 'sv', 'pl', 'ru', 'th', 'tr', 'uk', 'vi', 'zh_CN', 'zh_TW'],
// Application Fallback Locale
'fallback_locale' => 'en',

View File

@ -46,7 +46,6 @@ return [
'driver' => 'null',
],
],
];

View File

@ -1,7 +1,7 @@
<?php
/**
* Debugbar Configuration Options
* Debugbar 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.
@ -16,10 +16,9 @@ return [
// You can provide an array of URI's that must be ignored (eg. 'api/*')
'enabled' => env('DEBUGBAR_ENABLED', false),
'except' => [
'telescope*'
'telescope*',
],
// DebugBar stores data for session/ajax requests.
// You can disable this, so the debugbar stores data in headers/session,
// but this can cause problems with large data collectors.
@ -30,7 +29,7 @@ return [
'driver' => 'file', // redis, file, pdo, custom
'path' => storage_path('debugbar'), // For file driver
'connection' => null, // Leave null for default connection (Redis/PDO)
'provider' => '' // Instance of StorageInterface for custom driver
'provider' => '', // Instance of StorageInterface for custom driver
],
// Vendor files are included by default, but can be set to false.
@ -98,19 +97,19 @@ return [
'hints' => true, // Show hints for common mistakes
],
'mail' => [
'full_log' => false
'full_log' => false,
],
'views' => [
'data' => false, //Note: Can slow down the application, because the data can be quite large..
],
'route' => [
'label' => true // show complete route on bar
'label' => true, // show complete route on bar
],
'logs' => [
'file' => null
'file' => null,
],
'cache' => [
'values' => true // collect cache values
'values' => true, // collect cache values
],
],

View File

@ -10,12 +10,11 @@
return [
'show_warnings' => false, // Throw an Exception on warnings from dompdf
'orientation' => 'portrait',
'defines' => [
/**
* The location of the DOMPDF font directory
* The location of the DOMPDF font directory.
*
* The location of the directory where DOMPDF will store fonts and font metrics
* Note: This directory must exist and be writable by the webserver process.
@ -38,17 +37,17 @@ return [
* Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic,
* Symbol, ZapfDingbats.
*/
"DOMPDF_FONT_DIR" => storage_path('fonts/'), // advised by dompdf (https://github.com/dompdf/dompdf/pull/782)
'DOMPDF_FONT_DIR' => storage_path('fonts/'), // advised by dompdf (https://github.com/dompdf/dompdf/pull/782)
/**
* The location of the DOMPDF font cache directory
* The location of the DOMPDF font cache directory.
*
* This directory contains the cached font metrics for the fonts used by DOMPDF.
* This directory can be the same as DOMPDF_FONT_DIR
*
* Note: This directory must exist and be writable by the webserver process.
*/
"DOMPDF_FONT_CACHE" => storage_path('fonts/'),
'DOMPDF_FONT_CACHE' => storage_path('fonts/'),
/**
* The location of a temporary directory.
@ -57,10 +56,10 @@ return [
* The temporary directory is required to download remote images and when
* using the PFDLib back end.
*/
"DOMPDF_TEMP_DIR" => sys_get_temp_dir(),
'DOMPDF_TEMP_DIR' => sys_get_temp_dir(),
/**
* ==== IMPORTANT ====
* ==== IMPORTANT ====.
*
* dompdf's "chroot": Prevents dompdf from accessing system files or other
* files on the webserver. All local files opened by dompdf must be in a
@ -71,7 +70,7 @@ return [
* direct class use like:
* $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output();
*/
"DOMPDF_CHROOT" => realpath(base_path()),
'DOMPDF_CHROOT' => realpath(base_path()),
/**
* Whether to use Unicode fonts or not.
@ -82,20 +81,19 @@ return [
* When enabled, dompdf can support all Unicode glyphs. Any glyphs used in a
* document must be present in your fonts, however.
*/
"DOMPDF_UNICODE_ENABLED" => true,
'DOMPDF_UNICODE_ENABLED' => true,
/**
* Whether to enable font subsetting or not.
*/
"DOMPDF_ENABLE_FONTSUBSETTING" => false,
'DOMPDF_ENABLE_FONTSUBSETTING' => false,
/**
* The PDF rendering backend to use
* The PDF rendering backend to use.
*
* Valid settings are 'PDFLib', 'CPDF' (the bundled R&OS PDF class), 'GD' and
* 'auto'. 'auto' will look for PDFLib and use it if found, or if not it will
* fall back on CPDF. 'GD' renders PDFs to graphic files. {@link
* Canvas_Factory} ultimately determines which rendering class to instantiate
* fall back on CPDF. 'GD' renders PDFs to graphic files. {@link * Canvas_Factory} ultimately determines which rendering class to instantiate
* based on this setting.
*
* Both PDFLib & CPDF rendering backends provide sufficient rendering
@ -117,10 +115,10 @@ return [
* @link http://www.ros.co.nz/pdf
* @link http://www.php.net/image
*/
"DOMPDF_PDF_BACKEND" => "CPDF",
'DOMPDF_PDF_BACKEND' => 'CPDF',
/**
* PDFlib license key
* PDFlib license key.
*
* If you are using a licensed, commercial version of PDFlib, specify
* your license key here. If you are using PDFlib-Lite or are evaluating
@ -143,7 +141,7 @@ return [
* the desired content might be different (e.g. screen or projection view of html file).
* Therefore allow specification of content here.
*/
"DOMPDF_DEFAULT_MEDIA_TYPE" => "print",
'DOMPDF_DEFAULT_MEDIA_TYPE' => 'print',
/**
* The default paper size.
@ -152,18 +150,19 @@ return [
*
* @see CPDF_Adapter::PAPER_SIZES for valid sizes ('letter', 'legal', 'A4', etc.)
*/
"DOMPDF_DEFAULT_PAPER_SIZE" => "a4",
'DOMPDF_DEFAULT_PAPER_SIZE' => 'a4',
/**
* The default font family
* The default font family.
*
* Used if no suitable fonts can be found. This must exist in the font folder.
*
* @var string
*/
"DOMPDF_DEFAULT_FONT" => "dejavu sans",
'DOMPDF_DEFAULT_FONT' => 'dejavu sans',
/**
* Image DPI setting
* Image DPI setting.
*
* This setting determines the default DPI setting for images and fonts. The
* DPI may be overridden for inline images by explictly setting the
@ -195,10 +194,10 @@ return [
*
* @var int
*/
"DOMPDF_DPI" => 96,
'DOMPDF_DPI' => 96,
/**
* Enable inline PHP
* Enable inline PHP.
*
* If this setting is set to true then DOMPDF will automatically evaluate
* inline PHP contained within <script type="text/php"> ... </script> tags.
@ -209,20 +208,20 @@ return [
*
* @var bool
*/
"DOMPDF_ENABLE_PHP" => false,
'DOMPDF_ENABLE_PHP' => false,
/**
* Enable inline Javascript
* Enable inline Javascript.
*
* If this setting is set to true then DOMPDF will automatically insert
* JavaScript code contained within <script type="text/javascript"> ... </script> tags.
*
* @var bool
*/
"DOMPDF_ENABLE_JAVASCRIPT" => false,
'DOMPDF_ENABLE_JAVASCRIPT' => false,
/**
* Enable remote file access
* Enable remote file access.
*
* If this setting is set to true, DOMPDF will access remote sites for
* images and CSS files as required.
@ -238,29 +237,27 @@ return [
*
* @var bool
*/
"DOMPDF_ENABLE_REMOTE" => true,
'DOMPDF_ENABLE_REMOTE' => true,
/**
* A ratio applied to the fonts height to be more like browsers' line height
* A ratio applied to the fonts height to be more like browsers' line height.
*/
"DOMPDF_FONT_HEIGHT_RATIO" => 1.1,
'DOMPDF_FONT_HEIGHT_RATIO' => 1.1,
/**
* Enable CSS float
* Enable CSS float.
*
* Allows people to disabled CSS float support
*
* @var bool
*/
"DOMPDF_ENABLE_CSS_FLOAT" => true,
'DOMPDF_ENABLE_CSS_FLOAT' => true,
/**
* Use the more-than-experimental HTML5 Lib parser
* Use the more-than-experimental HTML5 Lib parser.
*/
"DOMPDF_ENABLE_HTML5PARSER" => true,
'DOMPDF_ENABLE_HTML5PARSER' => true,
],
];

View File

@ -84,7 +84,7 @@ return [
'handler_with' => [4],
'formatter' => LineFormatter::class,
'formatter_with' => [
'format' => "%message%",
'format' => '%message%',
],
],
@ -101,7 +101,6 @@ return [
],
],
// Failed Login Message
// Allows a configurable message to be logged when a login request fails.
'failed_login' => [

View File

@ -23,7 +23,7 @@ return [
// Global "From" address & name
'from' => [
'address' => env('MAIL_FROM', 'mail@bookstackapp.com'),
'name' => env('MAIL_FROM_NAME', 'BookStack')
'name' => env('MAIL_FROM_NAME', 'BookStack'),
],
// Email encryption protocol

View File

@ -17,7 +17,6 @@ return [
// Queue connection configuration
'connections' => [
'sync' => [
'driver' => 'sync',
],

View File

@ -31,7 +31,6 @@ return [
// Overrides, in JSON format, to the configuration passed to underlying onelogin library.
'onelogin_overrides' => env('SAML2_ONELOGIN_OVERRIDES', null),
'onelogin' => [
// If 'strict' is True, then the PHP Toolkit will reject unsigned
// or unencrypted messages if it expects them signed or encrypted

View File

@ -1,6 +1,6 @@
<?php
use \Illuminate\Support\Str;
use Illuminate\Support\Str;
/**
* Session configuration options.

View File

@ -14,7 +14,7 @@ return [
'binary' => file_exists(base_path('wkhtmltopdf')) ? base_path('wkhtmltopdf') : env('WKHTMLTOPDF', false),
'timeout' => false,
'options' => [
'outline' => true
'outline' => true,
],
'env' => [],
],

View File

@ -25,11 +25,11 @@ class CleanupImages extends Command
*/
protected $description = 'Cleanup images and drawings';
protected $imageService;
/**
* Create a new command instance.
*
* @param \BookStack\Uploads\ImageService $imageService
*/
public function __construct(ImageService $imageService)
@ -63,6 +63,7 @@ class CleanupImages extends Command
$this->comment($deleteCount . ' images found that would have been deleted');
$this->showDeletedImages($deleted);
$this->comment('Run with -f or --force to perform deletions');
return;
}

View File

@ -23,7 +23,6 @@ class ClearViews extends Command
/**
* Create a new command instance.
*
*/
public function __construct()
{

View File

@ -54,6 +54,7 @@ class CopyShelfPermissions extends Command
if (!$cascadeAll && !$shelfSlug) {
$this->error('Either a --slug or --all option must be provided.');
return;
}

View File

@ -38,8 +38,9 @@ class CreateAdmin extends Command
/**
* Execute the console command.
*
* @return mixed
* @throws \BookStack\Exceptions\NotFoundException
*
* @return mixed
*/
public function handle()
{
@ -71,7 +72,6 @@ class CreateAdmin extends Command
return $this->error('Invalid password provided, Must be at least 5 characters');
}
$user = $this->userRepo->create(['email' => $email, 'name' => $name, 'password' => $password]);
$this->userRepo->attachSystemRole($user, 'admin');
$this->userRepo->downloadAndAssignUserAvatar($user);

View File

@ -8,7 +8,6 @@ use Illuminate\Console\Command;
class DeleteUsers extends Command
{
/**
* The name and signature of the console command.
*
@ -47,7 +46,7 @@ class DeleteUsers extends Command
continue;
}
$this->userRepo->destroy($user);
++$numDeleted;
$numDeleted++;
}
$this->info("Deleted $numDeleted of $totalUsers total users.");
} else {

View File

@ -4,7 +4,6 @@ namespace BookStack\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Database\Connection;
use Illuminate\Support\Facades\DB;
class UpdateUrl extends Command
{
@ -49,7 +48,8 @@ class UpdateUrl extends Command
$urlPattern = '/https?:\/\/(.+)/';
if (!preg_match($urlPattern, $oldUrl) || !preg_match($urlPattern, $newUrl)) {
$this->error("The given urls are expected to be full urls starting with http:// or https://");
$this->error('The given urls are expected to be full urls starting with http:// or https://');
return 1;
}
@ -58,11 +58,11 @@ class UpdateUrl extends Command
}
$columnsToUpdateByTable = [
"attachments" => ["path"],
"pages" => ["html", "text", "markdown"],
"images" => ["url"],
"settings" => ["value"],
"comments" => ["html", "text"],
'attachments' => ['path'],
'pages' => ['html', 'text', 'markdown'],
'images' => ['url'],
'settings' => ['value'],
'comments' => ['html', 'text'],
];
foreach ($columnsToUpdateByTable as $table => $columns) {
@ -73,7 +73,7 @@ class UpdateUrl extends Command
}
$jsonColumnsToUpdateByTable = [
"settings" => ["value"],
'settings' => ['value'],
];
foreach ($jsonColumnsToUpdateByTable as $table => $columns) {
@ -85,10 +85,11 @@ class UpdateUrl extends Command
}
}
$this->info("URL update procedure complete.");
$this->info('URL update procedure complete.');
$this->info('============================================================================');
$this->info('Be sure to run "php artisan cache:clear" to clear any old URLs in the cache.');
$this->info('============================================================================');
return 0;
}
@ -100,8 +101,9 @@ class UpdateUrl extends Command
{
$oldQuoted = $this->db->getPdo()->quote($oldUrl);
$newQuoted = $this->db->getPdo()->quote($newUrl);
return $this->db->table($table)->update([
$column => $this->db->raw("REPLACE({$column}, {$oldQuoted}, {$newQuoted})")
$column => $this->db->raw("REPLACE({$column}, {$oldQuoted}, {$newQuoted})"),
]);
}
@ -112,8 +114,8 @@ class UpdateUrl extends Command
protected function checkUserOkayToProceed(string $oldUrl, string $newUrl): bool
{
$dangerWarning = "This will search for \"{$oldUrl}\" in your database and replace it with \"{$newUrl}\".\n";
$dangerWarning .= "Are you sure you want to proceed?";
$backupConfirmation = "This operation could cause issues if used incorrectly. Have you made a backup of your existing database?";
$dangerWarning .= 'Are you sure you want to proceed?';
$backupConfirmation = 'This operation could cause issues if used incorrectly. Have you made a backup of your existing database?';
return $this->confirm($dangerWarning) && $this->confirm($backupConfirmation);
}

View File

@ -23,7 +23,6 @@ class UpgradeDatabaseEncoding extends Command
/**
* Create a new command instance.
*
*/
public function __construct()
{

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Console;
<?php
namespace BookStack\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -18,6 +20,7 @@ class Kernel extends ConsoleKernel
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
*
* @return void
*/
protected function schedule(Schedule $schedule)

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities;
<?php
namespace BookStack\Entities;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Tools\ShelfContext;
@ -6,11 +8,11 @@ use Illuminate\View\View;
class BreadcrumbsViewComposer
{
protected $entityContextManager;
/**
* BreadcrumbsViewComposer constructor.
*
* @param ShelfContext $entityContextManager
*/
public function __construct(ShelfContext $entityContextManager)
@ -20,6 +22,7 @@ class BreadcrumbsViewComposer
/**
* Modify data when the view is composed.
*
* @param View $view
*/
public function compose(View $view)

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities;
<?php
namespace BookStack\Entities;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
@ -8,7 +10,7 @@ use BookStack\Entities\Models\Page;
use BookStack\Entities\Models\PageRevision;
/**
* Class EntityProvider
* Class EntityProvider.
*
* Provides access to the core entity models.
* Wrapped up in this provider since they are often used together
@ -16,7 +18,6 @@ use BookStack\Entities\Models\PageRevision;
*/
class EntityProvider
{
/**
* @var Bookshelf
*/
@ -42,7 +43,6 @@ class EntityProvider
*/
public $pageRevision;
public function __construct()
{
$this->bookshelf = new Bookshelf();
@ -55,6 +55,7 @@ class EntityProvider
/**
* Fetch all core entity types as an associated array
* with their basic names as the keys.
*
* @return array<Entity>
*/
public function all(): array
@ -73,6 +74,7 @@ class EntityProvider
public function get(string $type): Entity
{
$type = strtolower($type);
return $this->all()[$type];
}
@ -86,6 +88,7 @@ class EntityProvider
$model = $this->get($type);
$morphClasses[] = $model->getMorphClass();
}
return $morphClasses;
}
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Models;
<?php
namespace BookStack\Entities\Models;
use BookStack\Uploads\Image;
use Exception;
@ -8,7 +10,8 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection;
/**
* Class Book
* Class Book.
*
* @property string $description
* @property int $image_id
* @property Image|null $cover
@ -30,8 +33,10 @@ class Book extends Entity implements HasCoverImage
/**
* Returns book cover image, if book cover not exists return default cover image.
*
* @param int $width - Width of the image
* @param int $height - Height of the image
*
* @return string
*/
public function getBookCover($width = 440, $height = 250)
@ -46,11 +51,12 @@ class Book extends Entity implements HasCoverImage
} catch (Exception $err) {
$cover = $default;
}
return $cover;
}
/**
* Get the cover image of the book
* Get the cover image of the book.
*/
public function cover(): BelongsTo
{
@ -67,6 +73,7 @@ class Book extends Entity implements HasCoverImage
/**
* Get all pages within this book.
*
* @return HasMany
*/
public function pages()
@ -76,6 +83,7 @@ class Book extends Entity implements HasCoverImage
/**
* Get the direct child pages of this book.
*
* @return HasMany
*/
public function directPages()
@ -85,6 +93,7 @@ class Book extends Entity implements HasCoverImage
/**
* Get all chapters within this book.
*
* @return HasMany
*/
public function chapters()
@ -94,6 +103,7 @@ class Book extends Entity implements HasCoverImage
/**
* Get the shelves this book is contained within.
*
* @return BelongsToMany
*/
public function shelves()
@ -103,12 +113,14 @@ class Book extends Entity implements HasCoverImage
/**
* Get the direct child items within this book.
*
* @return Collection
*/
public function getDirectChildren(): Collection
{
$pages = $this->directPages()->visible()->get();
$chapters = $this->chapters()->visible()->get();
return $pages->concat($chapters)->sortBy('priority')->sortByDesc('draft');
}
}

View File

@ -1,18 +1,21 @@
<?php namespace BookStack\Entities\Models;
<?php
namespace BookStack\Entities\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* Class BookChild
* Class BookChild.
*
* @property int $book_id
* @property int $priority
* @property Book $book
*
* @method Builder whereSlugs(string $bookSlug, string $childSlug)
*/
abstract class BookChild extends Entity
{
/**
* Scope a query to find items where the the child has the given childSlug
* where its parent has the bookSlug.

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Models;
<?php
namespace BookStack\Entities\Models;
use BookStack\Uploads\Image;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -17,6 +19,7 @@ class Bookshelf extends Entity implements HasCoverImage
/**
* Get the books in this shelf.
* Should not be used directly since does not take into account permissions.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function books()
@ -44,8 +47,10 @@ class Bookshelf extends Entity implements HasCoverImage
/**
* Returns BookShelf cover image, if cover does not exists return default cover image.
*
* @param int $width - Width of the image
* @param int $height - Height of the image
*
* @return string
*/
public function getBookCover($width = 440, $height = 250)
@ -61,11 +66,12 @@ class Bookshelf extends Entity implements HasCoverImage
} catch (\Exception $err) {
$cover = $default;
}
return $cover;
}
/**
* Get the cover image of the shelf
* Get the cover image of the shelf.
*/
public function cover(): BelongsTo
{
@ -82,7 +88,9 @@ class Bookshelf extends Entity implements HasCoverImage
/**
* Check if this shelf contains the given book.
*
* @param Book $book
*
* @return bool
*/
public function contains(Book $book): bool
@ -92,6 +100,7 @@ class Bookshelf extends Entity implements HasCoverImage
/**
* Add a book to the end of this shelf.
*
* @param Book $book
*/
public function appendBook(Book $book)

View File

@ -1,9 +1,12 @@
<?php namespace BookStack\Entities\Models;
<?php
namespace BookStack\Entities\Models;
use Illuminate\Support\Collection;
/**
* Class Chapter
* Class Chapter.
*
* @property Collection<Page> $pages
* @property mixed description
*/
@ -16,7 +19,9 @@ class Chapter extends BookChild
/**
* Get the pages that this chapter contains.
*
* @param string $dir
*
* @return mixed
*/
public function pages($dir = 'ASC')

View File

@ -1,7 +1,8 @@
<?php namespace BookStack\Entities\Models;
<?php
namespace BookStack\Entities\Models;
use BookStack\Auth\User;
use BookStack\Entities\Models\Entity;
use BookStack\Interfaces\Loggable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -12,7 +13,6 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
*/
class Deletion extends Model implements Loggable
{
/**
* Get the related deletable record.
*/
@ -40,12 +40,14 @@ class Deletion extends Model implements Loggable
'deletable_id' => $entity->id,
]);
$record->save();
return $record;
}
public function logDescriptor(): string
{
$deletable = $this->deletable()->first();
return "Deletion ({$this->id}) for {$deletable->getType()} ({$deletable->id}) {$deletable->name}";
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Models;
<?php
namespace BookStack\Entities\Models;
use BookStack\Actions\Activity;
use BookStack\Actions\Comment;
@ -34,8 +36,9 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property Carbon $updated_at
* @property int $created_by
* @property int $updated_by
* @property boolean $restricted
* @property bool $restricted
* @property Collection $tags
*
* @method static Entity|Builder visible()
* @method static Entity|Builder hasPermission(string $permission)
* @method static Builder withLastView()
@ -154,11 +157,12 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
}
/**
* Get the comments for an entity
* Get the comments for an entity.
*/
public function comments(bool $orderByCreated = true): MorphMany
{
$query = $this->morphMany(Comment::class, 'entity');
return $orderByCreated ? $query->orderBy('created_at', 'asc') : $query;
}
@ -205,7 +209,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
/**
* Check if this instance or class is a certain type of entity.
* Examples of $type are 'page', 'book', 'chapter'
* Examples of $type are 'page', 'book', 'chapter'.
*/
public static function isA(string $type): bool
{
@ -218,6 +222,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
public static function getType(): string
{
$className = array_slice(explode('\\', static::class), -1, 1)[0];
return strtolower($className);
}
@ -229,6 +234,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
if (mb_strlen($this->name) <= $length) {
return $this->name;
}
return mb_substr($this->name, 0, $length - 3) . '...';
}
@ -255,7 +261,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
}
/**
* Get the url of this entity
* Get the url of this entity.
*/
abstract public function getUrl(string $path = '/'): string;
@ -272,6 +278,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
if ($this instanceof Chapter) {
return $this->book()->withTrashed()->first();
}
return null;
}
@ -285,7 +292,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
}
/**
* Index the current entity for search
* Index the current entity for search.
*/
public function indexForSearch()
{
@ -298,6 +305,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
public function refreshSlug(): string
{
$this->slug = app(SlugGenerator::class)->generate($this);
return $this->slug;
}

View File

@ -1,13 +1,11 @@
<?php
namespace BookStack\Entities\Models;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
interface HasCoverImage
{
/**
* Get the cover image for this item.
*/

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Models;
<?php
namespace BookStack\Entities\Models;
use BookStack\Entities\Tools\PageContent;
use BookStack\Uploads\Attachment;
@ -9,7 +11,8 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
use Permissions;
/**
* Class Page
* Class Page.
*
* @property int $chapter_id
* @property string $html
* @property string $markdown
@ -41,22 +44,26 @@ class Page extends BookChild
public function scopeVisible(Builder $query): Builder
{
$query = Permissions::enforceDraftVisibilityOnQuery($query);
return parent::scopeVisible($query);
}
/**
* Converts this page into a simplified array.
*
* @return mixed
*/
public function toSimpleArray()
{
$array = array_intersect_key($this->toArray(), array_flip($this->simpleAttributes));
$array['url'] = $this->getUrl();
return $array;
}
/**
* Get the chapter that this page is in, If applicable.
*
* @return BelongsTo
*/
public function chapter()
@ -66,6 +73,7 @@ class Page extends BookChild
/**
* Check if this page has a chapter.
*
* @return bool
*/
public function hasChapter()
@ -96,6 +104,7 @@ class Page extends BookChild
/**
* Get the attachments assigned to this page.
*
* @return HasMany
*/
public function attachments()
@ -120,7 +129,8 @@ class Page extends BookChild
}
/**
* Get the current revision for the page if existing
* Get the current revision for the page if existing.
*
* @return PageRevision|null
*/
public function getCurrentRevision()
@ -136,6 +146,7 @@ class Page extends BookChild
$refreshed = $this->refresh()->unsetRelations()->load(['tags', 'createdBy', 'updatedBy', 'ownedBy']);
$refreshed->setHidden(array_diff($refreshed->getHidden(), ['html', 'markdown']));
$refreshed->html = (new PageContent($refreshed))->render();
return $refreshed;
}
}

View File

@ -1,12 +1,14 @@
<?php namespace BookStack\Entities\Models;
<?php
namespace BookStack\Entities\Models;
use BookStack\Auth\User;
use BookStack\Entities\Models\Page;
use BookStack\Model;
use Carbon\Carbon;
/**
* Class PageRevision
* Class PageRevision.
*
* @property int $page_id
* @property string $slug
* @property string $book_slug
@ -23,7 +25,8 @@ class PageRevision extends Model
protected $fillable = ['name', 'html', 'text', 'markdown', 'summary'];
/**
* Get the user that created the page revision
* Get the user that created the page revision.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function createdBy()
@ -33,6 +36,7 @@ class PageRevision extends Model
/**
* Get the page this revision originates from.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function page()
@ -42,7 +46,9 @@ class PageRevision extends Model
/**
* Get the url for this revision.
*
* @param null|string $path
*
* @return string
*/
public function getUrl($path = null)
@ -51,11 +57,13 @@ class PageRevision extends Model
if ($path) {
return $url . '/' . trim($path, '/');
}
return $url;
}
/**
* Get the previous revision for the same page if existing
* Get the previous revision for the same page if existing.
*
* @return \BookStack\Entities\PageRevision|null
*/
public function getPrevious()
@ -74,8 +82,10 @@ class PageRevision extends Model
/**
* Allows checking of the exact class, Used to check entity type.
* Included here to align with entities in similar use cases.
* (Yup, Bit of an awkward hack)
* (Yup, Bit of an awkward hack).
*
* @param $type
*
* @return bool
*/
public static function isA($type)

View File

@ -1,15 +1,17 @@
<?php namespace BookStack\Entities\Models;
<?php
namespace BookStack\Entities\Models;
use BookStack\Model;
class SearchTerm extends Model
{
protected $fillable = ['term', 'entity_id', 'entity_type', 'score'];
public $timestamps = false;
/**
* Get the entity that this term belongs to
* Get the entity that this term belongs to.
*
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function entity()

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Queries;
<?php
namespace BookStack\Entities\Queries;
use BookStack\Auth\Permissions\PermissionService;
use BookStack\Entities\EntityProvider;

View File

@ -1,5 +1,6 @@
<?php namespace BookStack\Entities\Queries;
<?php
namespace BookStack\Entities\Queries;
use BookStack\Actions\View;
use Illuminate\Support\Facades\DB;
@ -25,5 +26,4 @@ class Popular extends EntityQuery
->pluck('viewable')
->filter();
}
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Queries;
<?php
namespace BookStack\Entities\Queries;
use BookStack\Actions\View;
use Illuminate\Support\Collection;

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Queries;
<?php
namespace BookStack\Entities\Queries;
use BookStack\Actions\Favourite;
use Illuminate\Database\Query\JoinClause;

View File

@ -2,24 +2,18 @@
namespace BookStack\Entities\Repos;
use BookStack\Actions\ActivityType;
use BookStack\Actions\TagRepo;
use BookStack\Auth\User;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Models\HasCoverImage;
use BookStack\Exceptions\ImageUploadException;
use BookStack\Facades\Activity;
use BookStack\Uploads\ImageRepo;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Collection;
class BaseRepo
{
protected $tagRepo;
protected $imageRepo;
public function __construct(TagRepo $tagRepo, ImageRepo $imageRepo)
{
$this->tagRepo = $tagRepo;
@ -27,7 +21,7 @@ class BaseRepo
}
/**
* Create a new entity in the system
* Create a new entity in the system.
*/
public function create(Entity $entity, array $input)
{
@ -72,6 +66,7 @@ class BaseRepo
/**
* Update the given items' cover image, or clear it.
*
* @throws ImageUploadException
* @throws \Exception
*/

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Repos;
<?php
namespace BookStack\Entities\Repos;
use BookStack\Actions\ActivityType;
use BookStack\Actions\TagRepo;
@ -15,7 +17,6 @@ use Illuminate\Support\Collection;
class BookRepo
{
protected $baseRepo;
protected $tagRepo;
protected $imageRepo;
@ -84,13 +85,14 @@ class BookRepo
}
/**
* Create a new book in the system
* Create a new book in the system.
*/
public function create(array $input): Book
{
$book = new Book();
$this->baseRepo->create($book, $input);
Activity::addForEntity($book, ActivityType::BOOK_CREATE);
return $book;
}
@ -101,11 +103,13 @@ class BookRepo
{
$this->baseRepo->update($book, $input);
Activity::addForEntity($book, ActivityType::BOOK_UPDATE);
return $book;
}
/**
* Update the given book's cover image, or clear it.
*
* @throws ImageUploadException
* @throws Exception
*/
@ -116,6 +120,7 @@ class BookRepo
/**
* Remove a book from the system.
*
* @throws Exception
*/
public function destroy(Book $book)

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Repos;
<?php
namespace BookStack\Entities\Repos;
use BookStack\Actions\ActivityType;
use BookStack\Entities\Models\Book;
@ -89,6 +91,7 @@ class BookshelfRepo
$this->baseRepo->create($shelf, $input);
$this->updateBooks($shelf, $bookIds);
Activity::addForEntity($shelf, ActivityType::BOOKSHELF_CREATE);
return $shelf;
}
@ -104,6 +107,7 @@ class BookshelfRepo
}
Activity::addForEntity($shelf, ActivityType::BOOKSHELF_UPDATE);
return $shelf;
}
@ -129,6 +133,7 @@ class BookshelfRepo
/**
* Update the given shelf cover image, or clear it.
*
* @throws ImageUploadException
* @throws Exception
*/
@ -164,6 +169,7 @@ class BookshelfRepo
/**
* Remove a bookshelf from the system.
*
* @throws Exception
*/
public function destroy(Bookshelf $shelf)

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Repos;
<?php
namespace BookStack\Entities\Repos;
use BookStack\Actions\ActivityType;
use BookStack\Entities\Models\Book;
@ -9,11 +11,9 @@ use BookStack\Exceptions\MoveOperationException;
use BookStack\Exceptions\NotFoundException;
use BookStack\Facades\Activity;
use Exception;
use Illuminate\Support\Collection;
class ChapterRepo
{
protected $baseRepo;
/**
@ -26,6 +26,7 @@ class ChapterRepo
/**
* Get a chapter via the slug.
*
* @throws NotFoundException
*/
public function getBySlug(string $bookSlug, string $chapterSlug): Chapter
@ -49,6 +50,7 @@ class ChapterRepo
$chapter->priority = (new BookContents($parentBook))->getLastPriority() + 1;
$this->baseRepo->create($chapter, $input);
Activity::addForEntity($chapter, ActivityType::CHAPTER_CREATE);
return $chapter;
}
@ -59,11 +61,13 @@ class ChapterRepo
{
$this->baseRepo->update($chapter, $input);
Activity::addForEntity($chapter, ActivityType::CHAPTER_UPDATE);
return $chapter;
}
/**
* Remove a chapter from the system.
*
* @throws Exception
*/
public function destroy(Chapter $chapter)
@ -77,7 +81,8 @@ class ChapterRepo
/**
* Move the given chapter into a new parent book.
* The $parentIdentifier must be a string of the following format:
* 'book:<id>' (book:5)
* 'book:<id>' (book:5).
*
* @throws MoveOperationException
*/
public function move(Chapter $chapter, string $parentIdentifier): Book

View File

@ -1,14 +1,16 @@
<?php namespace BookStack\Entities\Repos;
<?php
namespace BookStack\Entities\Repos;
use BookStack\Actions\ActivityType;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Models\PageRevision;
use BookStack\Entities\Tools\BookContents;
use BookStack\Entities\Tools\PageContent;
use BookStack\Entities\Tools\TrashCan;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Models\PageRevision;
use BookStack\Exceptions\MoveOperationException;
use BookStack\Exceptions\NotFoundException;
use BookStack\Exceptions\PermissionsException;
@ -16,11 +18,9 @@ use BookStack\Facades\Activity;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
class PageRepo
{
protected $baseRepo;
/**
@ -33,6 +33,7 @@ class PageRepo
/**
* Get a page by ID.
*
* @throws NotFoundException
*/
public function getById(int $id, array $relations = ['book']): Page
@ -48,6 +49,7 @@ class PageRepo
/**
* Get a page its book and own slug.
*
* @throws NotFoundException
*/
public function getBySlug(string $bookSlug, string $pageSlug): Page
@ -77,6 +79,7 @@ class PageRepo
->orderBy('created_at', 'desc')
->with('page')
->first();
return $revision ? $revision->page : null;
}
@ -119,6 +122,7 @@ class PageRepo
public function getUserDraft(Page $page): ?PageRevision
{
$revision = $this->getUserDraftQuery($page)->first();
return $revision;
}
@ -144,6 +148,7 @@ class PageRepo
$page->save();
$page->refresh()->rebuildPermissions();
return $page;
}
@ -166,6 +171,7 @@ class PageRepo
$draft->refresh();
Activity::addForEntity($draft, ActivityType::PAGE_CREATE);
return $draft;
}
@ -190,7 +196,7 @@ class PageRepo
$this->getUserDraftQuery($page)->delete();
// Save a revision after updating
$summary = trim($input['summary'] ?? "");
$summary = trim($input['summary'] ?? '');
$htmlChanged = isset($input['html']) && $input['html'] !== $oldHtml;
$nameChanged = isset($input['name']) && $input['name'] !== $oldName;
$markdownChanged = isset($input['markdown']) && $input['markdown'] !== $oldMarkdown;
@ -199,6 +205,7 @@ class PageRepo
}
Activity::addForEntity($page, ActivityType::PAGE_UPDATE);
return $page;
}
@ -234,6 +241,7 @@ class PageRepo
$revision->save();
$this->deleteOldRevisions($page);
return $revision;
}
@ -249,6 +257,7 @@ class PageRepo
}
$page->fill($input);
$page->save();
return $page;
}
@ -260,11 +269,13 @@ class PageRepo
}
$draft->save();
return $draft;
}
/**
* Destroy a page from the system.
*
* @throws Exception
*/
public function destroy(Page $page)
@ -301,13 +312,15 @@ class PageRepo
$this->savePageRevision($page, $summary);
Activity::addForEntity($page, ActivityType::PAGE_RESTORE);
return $page;
}
/**
* Move the given page into a new parent book or chapter.
* The $parentIdentifier must be a string of the following format:
* 'book:<id>' (book:5)
* 'book:<id>' (book:5).
*
* @throws MoveOperationException
* @throws PermissionsException
*/
@ -327,12 +340,14 @@ class PageRepo
$page->rebuildPermissions();
Activity::addForEntity($page, ActivityType::PAGE_MOVE);
return $parent;
}
/**
* Copy an existing page in the system.
* Optionally providing a new parent via string identifier and a new name.
*
* @throws MoveOperationException
* @throws PermissionsException
*/
@ -369,7 +384,8 @@ class PageRepo
/**
* Find a page parent entity via a identifier string in the format:
* {type}:{id}
* Example: (book:5)
* Example: (book:5).
*
* @throws MoveOperationException
*/
protected function findParentByIdentifier(string $identifier): ?Entity
@ -383,6 +399,7 @@ class PageRepo
}
$parentClass = $entityType === 'book' ? Book::class : Chapter::class;
return $parentClass::visible()->where('id', '=', $entityId)->first();
}
@ -420,6 +437,7 @@ class PageRepo
$draft->book_slug = $page->book->slug;
$draft->created_by = user()->id;
$draft->type = 'update_draft';
return $draft;
}
@ -445,13 +463,14 @@ class PageRepo
}
/**
* Get a new priority for a page
* Get a new priority for a page.
*/
protected function getNewPriority(Page $page): int
{
$parent = $page->getParent();
if ($parent instanceof Chapter) {
$lastPage = $parent->pages('desc')->first();
return $lastPage ? $lastPage->priority + 1 : 0;
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\BookChild;
@ -10,7 +12,6 @@ use Illuminate\Support\Collection;
class BookContents
{
/**
* @var Book
*/
@ -35,6 +36,7 @@ class BookContents
->where('chapter_id', '=', 0)->max('priority');
$maxChapter = Chapter::visible()->where('book_id', '=', $this->book->id)
->max('priority');
return max($maxChapter, $maxPage, 1);
}
@ -83,6 +85,7 @@ class BookContents
if (isset($entity['draft']) && $entity['draft']) {
return -100;
}
return $entity['priority'] ?? 0;
};
}
@ -110,9 +113,10 @@ class BookContents
* +"parentChapter": false (ID of parent chapter, as string, or false)
* +"type": "page" (Entity type of item)
* +"book": "1" (Id of book to place item in)
* }
* }.
*
* Returns a list of books that were involved in the operation.
*
* @throws SortOperationException
*/
public function sortUsingMap(Collection $sortMap): Collection
@ -190,6 +194,7 @@ class BookContents
/**
* Get the books involved in a sort.
* The given sort map should have its models loaded first.
*
* @throws SortOperationException
*/
protected function getBooksInvolvedInSort(Collection $sortMap): Collection
@ -202,7 +207,7 @@ class BookContents
$books = Book::hasPermission('update')->whereIn('id', $bookIdsInvolved)->get();
if (count($books) !== count($bookIdsInvolved)) {
throw new SortOperationException("Could not find all books requested in sort operation");
throw new SortOperationException('Could not find all books requested in sort operation');
}
return $books;

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Chapter;
@ -12,7 +14,6 @@ use Throwable;
class ExportFormatter
{
protected $imageService;
/**
@ -26,6 +27,7 @@ class ExportFormatter
/**
* Convert a page to a self-contained HTML file.
* Includes required CSS & image content. Images are base64 encoded into the HTML.
*
* @throws Throwable
*/
public function pageToContainedHtml(Page $page)
@ -35,11 +37,13 @@ class ExportFormatter
'page' => $page,
'format' => 'html',
])->render();
return $this->containHtml($pageHtml);
}
/**
* Convert a chapter to a self-contained HTML file.
*
* @throws Throwable
*/
public function chapterToContainedHtml(Chapter $chapter)
@ -53,11 +57,13 @@ class ExportFormatter
'pages' => $pages,
'format' => 'html',
])->render();
return $this->containHtml($html);
}
/**
* Convert a book to a self-contained HTML file.
*
* @throws Throwable
*/
public function bookToContainedHtml(Book $book)
@ -68,11 +74,13 @@ class ExportFormatter
'bookChildren' => $bookTree,
'format' => 'html',
])->render();
return $this->containHtml($html);
}
/**
* Convert a page to a PDF file.
*
* @throws Throwable
*/
public function pageToPdf(Page $page)
@ -82,11 +90,13 @@ class ExportFormatter
'page' => $page,
'format' => 'pdf',
])->render();
return $this->htmlToPdf($html);
}
/**
* Convert a chapter to a PDF file.
*
* @throws Throwable
*/
public function chapterToPdf(Chapter $chapter)
@ -107,6 +117,7 @@ class ExportFormatter
/**
* Convert a book to a PDF file.
*
* @throws Throwable
*/
public function bookToPdf(Book $book)
@ -117,11 +128,13 @@ class ExportFormatter
'bookChildren' => $bookTree,
'format' => 'pdf',
])->render();
return $this->htmlToPdf($html);
}
/**
* Convert normal web-page HTML to a PDF.
*
* @throws Exception
*/
protected function htmlToPdf(string $html): string
@ -134,11 +147,13 @@ class ExportFormatter
} else {
$pdf = DomPDF::loadHTML($containedHtml);
}
return $pdf->output();
}
/**
* Bundle of the contents of a html file to be self-contained.
*
* @throws Exception
*/
protected function containHtml(string $htmlContent): string
@ -195,6 +210,7 @@ class ExportFormatter
$text = html_entity_decode($text);
// Add title
$text = $page->name . "\n\n" . $text;
return $text;
}
@ -208,6 +224,7 @@ class ExportFormatter
foreach ($chapter->getVisiblePages() as $page) {
$text .= $this->pageToPlainText($page);
}
return $text;
}
@ -225,6 +242,7 @@ class ExportFormatter
$text .= $this->pageToPlainText($bookChild);
}
}
return $text;
}
@ -234,10 +252,10 @@ class ExportFormatter
public function pageToMarkdown(Page $page): string
{
if ($page->markdown) {
return "# " . $page->name . "\n\n" . $page->markdown;
return '# ' . $page->name . "\n\n" . $page->markdown;
}
return "# " . $page->name . "\n\n" . (new HtmlToMarkdown($page->html))->convert();
return '# ' . $page->name . "\n\n" . (new HtmlToMarkdown($page->html))->convert();
}
/**
@ -245,11 +263,12 @@ class ExportFormatter
*/
public function chapterToMarkdown(Chapter $chapter): string
{
$text = "# " . $chapter->name . "\n\n";
$text = '# ' . $chapter->name . "\n\n";
$text .= $chapter->description . "\n\n";
foreach ($chapter->pages as $page) {
$text .= $this->pageToMarkdown($page) . "\n\n";
}
return $text;
}
@ -259,7 +278,7 @@ class ExportFormatter
public function bookToMarkdown(Book $book): string
{
$bookTree = (new BookContents($book))->getTree(false, true);
$text = "# " . $book->name . "\n\n";
$text = '# ' . $book->name . "\n\n";
foreach ($bookTree as $bookChild) {
if ($bookChild instanceof Chapter) {
$text .= $this->chapterToMarkdown($bookChild);
@ -267,6 +286,7 @@ class ExportFormatter
$text .= $this->pageToMarkdown($bookChild);
}
}
return $text;
}
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools\Markdown;
<?php
namespace BookStack\Entities\Tools\Markdown;
use League\HTMLToMarkdown\Converter\ParagraphConverter;
use League\HTMLToMarkdown\ElementInterface;

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools\Markdown;
<?php
namespace BookStack\Entities\Tools\Markdown;
use League\CommonMark\ConfigurableEnvironmentInterface;
use League\CommonMark\Extension\ExtensionInterface;
@ -7,7 +9,6 @@ use League\CommonMark\Extension\Strikethrough\StrikethroughDelimiterProcessor;
class CustomStrikeThroughExtension implements ExtensionInterface
{
public function register(ConfigurableEnvironmentInterface $environment)
{
$environment->addDelimiterProcessor(new StrikethroughDelimiterProcessor());

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools\Markdown;
<?php
namespace BookStack\Entities\Tools\Markdown;
use League\CommonMark\ElementRendererInterface;
use League\CommonMark\Extension\Strikethrough\Strikethrough;

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools\Markdown;
<?php
namespace BookStack\Entities\Tools\Markdown;
use League\HTMLToMarkdown\Converter\BlockquoteConverter;
use League\HTMLToMarkdown\Converter\CodeConverter;
@ -27,12 +29,13 @@ class HtmlToMarkdown
}
/**
* Run the conversion
* Run the conversion.
*/
public function convert(): string
{
$converter = new HtmlConverter($this->getConverterEnvironment());
$html = $this->prepareHtml($this->html);
return $converter->convert($html);
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use BookStack\Entities\Models\BookChild;
use BookStack\Entities\Models\Entity;
@ -48,6 +50,7 @@ class NextPreviousContentLocator
return get_class($entity) === get_class($this->relativeBookItem)
&& $entity->id === $this->relativeBookItem->id;
});
return $index === false ? null : $index;
}
@ -64,6 +67,7 @@ class NextPreviousContentLocator
$childPages = $item->visible_pages ?? [];
$flatOrdered = $flatOrdered->concat($childPages);
}
return $flatOrdered;
}
}

View File

@ -1,12 +1,14 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Tools\Markdown\CustomStrikeThroughExtension;
use BookStack\Exceptions\ImageUploadException;
use BookStack\Facades\Theme;
use BookStack\Theming\ThemeEvents;
use BookStack\Util\HtmlContentFilter;
use BookStack\Uploads\ImageRepo;
use BookStack\Util\HtmlContentFilter;
use DOMDocument;
use DOMNodeList;
use DOMXPath;
@ -18,7 +20,6 @@ use League\CommonMark\Extension\TaskList\TaskListExtension;
class PageContent
{
protected $page;
/**
@ -62,11 +63,12 @@ class PageContent
$environment->addExtension(new CustomStrikeThroughExtension());
$environment = Theme::dispatch(ThemeEvents::COMMONMARK_ENVIRONMENT_CONFIGURE, $environment) ?? $environment;
$converter = new CommonMarkConverter([], $environment);
return $converter->convertToHtml($markdown);
}
/**
* Convert all base64 image data to saved images
* Convert all base64 image data to saved images.
*/
public function extractBase64Images(Page $page, string $htmlText): string
{
@ -97,6 +99,7 @@ class PageContent
// Save image from data with a random name
$imageName = 'embedded-image-' . Str::random(8) . '.' . $extension;
try {
$image = $imageRepo->saveNewFromData($imageName, base64_decode($base64ImageData), 'gallery', $page->id);
$imageNode->setAttribute('src', $image->url);
@ -171,7 +174,7 @@ class PageContent
/**
* Set a unique id on the given DOMElement.
* A map for existing ID's should be passed in to check for current existence.
* Returns a pair of strings in the format [old_id, new_id]
* Returns a pair of strings in the format [old_id, new_id].
*/
protected function setUniqueId(\DOMNode $element, array &$idMap): array
{
@ -183,6 +186,7 @@ class PageContent
$existingId = $element->getAttribute('id');
if (strpos($existingId, 'bkmrk') === 0 && !isset($idMap[$existingId])) {
$idMap[$existingId] = true;
return [$existingId, $existingId];
}
@ -200,6 +204,7 @@ class PageContent
$element->setAttribute('id', $newId);
$idMap[$newId] = true;
return [$existingId, $newId];
}
@ -209,11 +214,12 @@ class PageContent
protected function toPlainText(): string
{
$html = $this->render(true);
return html_entity_decode(strip_tags($html));
}
/**
* Render the page for viewing
* Render the page for viewing.
*/
public function render(bool $blankIncludes = false): string
{
@ -233,7 +239,7 @@ class PageContent
}
/**
* Parse the headers on the page to get a navigation menu
* Parse the headers on the page to get a navigation menu.
*/
public function getNavigation(string $htmlContent): array
{
@ -243,7 +249,7 @@ class PageContent
$doc = $this->loadDocumentFromHtml($htmlContent);
$xPath = new DOMXPath($doc);
$headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6");
$headers = $xPath->query('//h1|//h2|//h3|//h4|//h5|//h6');
return $headers ? $this->headerNodesToLevelList($headers) : [];
}
@ -272,6 +278,7 @@ class PageContent
$levelChange = ($tree->pluck('level')->min() - 1);
$tree = $tree->map(function ($header) use ($levelChange) {
$header['level'] -= ($levelChange);
return $header;
});
@ -325,7 +332,6 @@ class PageContent
return $html;
}
/**
* Fetch the content from a specific section of the given page.
*/
@ -365,6 +371,7 @@ class PageContent
$doc = new DOMDocument();
$html = '<body>' . $html . '</body>';
$doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
return $doc;
}
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Models\PageRevision;
@ -7,7 +9,6 @@ use Illuminate\Database\Eloquent\Builder;
class PageEditActivity
{
protected $page;
/**
@ -20,6 +21,7 @@ class PageEditActivity
/**
* Check if there's active editing being performed on this page.
*
* @return bool
*/
public function hasActiveEditing(): bool
@ -37,12 +39,15 @@ class PageEditActivity
$userMessage = $count > 1 ? trans('entities.pages_draft_edit_active.start_a', ['count' => $count]) : trans('entities.pages_draft_edit_active.start_b', ['userName' => $pageDraftEdits->first()->createdBy->name]);
$timeMessage = trans('entities.pages_draft_edit_active.time_b', ['minCount'=> 60]);
return trans('entities.pages_draft_edit_active.message', ['start' => $userMessage, 'time' => $timeMessage]);
}
/**
* Get the message to show when the user will be editing one of their drafts.
*
* @param PageRevision $draft
*
* @return string
*/
public function getEditingActiveDraftMessage(PageRevision $draft): string
@ -51,6 +56,7 @@ class PageEditActivity
if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) {
return $message;
}
return $message . "\n" . trans('entities.pages_draft_edited_notification');
}

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use BookStack\Actions\ActivityType;
use BookStack\Auth\User;
@ -9,7 +11,6 @@ use Illuminate\Support\Collection;
class PermissionsUpdater
{
/**
* Update an entities permissions from a permission form submit request.
*/

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use BookStack\Entities\EntityProvider;
use BookStack\Entities\Models\Entity;
@ -17,14 +19,12 @@ class SearchIndex
*/
protected $entityProvider;
public function __construct(SearchTerm $searchTerm, EntityProvider $entityProvider)
{
$this->searchTerm = $searchTerm;
$this->entityProvider = $entityProvider;
}
/**
* Index the given entity.
*/
@ -42,7 +42,8 @@ class SearchIndex
}
/**
* Index multiple Entities at once
* Index multiple Entities at once.
*
* @param Entity[] $entities
*/
protected function indexEntities(array $entities)
@ -111,7 +112,7 @@ class SearchIndex
foreach ($tokenMap as $token => $count) {
$terms[] = [
'term' => $token,
'score' => $count * $scoreAdjustment
'score' => $count * $scoreAdjustment,
];
}

View File

@ -1,10 +1,11 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use Illuminate\Http\Request;
class SearchOptions
{
/**
* @var array
*/
@ -35,6 +36,7 @@ class SearchOptions
foreach ($decoded as $type => $value) {
$instance->$type = $value;
}
return $instance;
}
@ -67,6 +69,7 @@ class SearchOptions
if (isset($inputs['types']) && count($inputs['types']) < 4) {
$instance->filters['type'] = implode('|', $inputs['types']);
}
return $instance;
}
@ -79,13 +82,13 @@ class SearchOptions
'searches' => [],
'exacts' => [],
'tags' => [],
'filters' => []
'filters' => [],
];
$patterns = [
'exacts' => '/"(.*?)"/',
'tags' => '/\[(.*?)\]/',
'filters' => '/\{(.*?)\}/'
'filters' => '/\{(.*?)\}/',
];
// Parse special terms

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use BookStack\Auth\Permissions\PermissionService;
use BookStack\Auth\User;
@ -13,7 +15,6 @@ use Illuminate\Support\Str;
class SearchRunner
{
/**
* @var EntityProvider
*/
@ -29,14 +30,13 @@ class SearchRunner
*/
protected $permissionService;
/**
* Acceptable operators to be used in a query
* Acceptable operators to be used in a query.
*
* @var array
*/
protected $queryOperators = ['<=', '>=', '=', '<', '>', 'like', '!='];
public function __construct(EntityProvider $entityProvider, Connection $db, PermissionService $permissionService)
{
$this->entityProvider = $entityProvider;
@ -85,9 +85,8 @@ class SearchRunner
];
}
/**
* Search a book for entities
* Search a book for entities.
*/
public function searchBook(int $bookId, string $searchString): Collection
{
@ -108,12 +107,13 @@ class SearchRunner
}
/**
* Search a chapter for entities
* Search a chapter for entities.
*/
public function searchChapter(int $chapterId, string $searchString): Collection
{
$opts = SearchOptions::fromString($searchString);
$pages = $this->buildEntitySearchQuery($opts, 'page')->where('chapter_id', '=', $chapterId)->take(20)->get();
return $pages->sortByDesc('score');
}
@ -121,6 +121,7 @@ class SearchRunner
* Search across a particular entity type.
* Setting getCount = true will return the total
* matching instead of the items themselves.
*
* @return \Illuminate\Database\Eloquent\Collection|int|static[]
*/
protected function searchEntityTable(SearchOptions $searchOpts, string $entityType = 'page', int $page = 1, int $count = 20, string $action = 'view', bool $getCount = false)
@ -131,11 +132,12 @@ class SearchRunner
}
$query = $query->skip(($page - 1) * $count)->take($count);
return $query->get();
}
/**
* Create a search query for an entity
* Create a search query for an entity.
*/
protected function buildEntitySearchQuery(SearchOptions $searchOpts, string $entityType = 'page', string $action = 'view'): EloquentBuilder
{
@ -191,6 +193,7 @@ class SearchRunner
foreach ($this->queryOperators as $operator) {
$escapedOperators[] = preg_quote($operator);
}
return join('|', $escapedOperators);
}
@ -199,7 +202,7 @@ class SearchRunner
*/
protected function applyTagSearch(EloquentBuilder $query, string $tagTerm): EloquentBuilder
{
preg_match("/^(.*?)((".$this->getRegexEscapedOperators().")(.*?))?$/", $tagTerm, $tagSplit);
preg_match('/^(.*?)((' . $this->getRegexEscapedOperators() . ')(.*?))?$/', $tagTerm, $tagSplit);
$query->whereHas('tags', function (EloquentBuilder $query) use ($tagSplit) {
$tagName = $tagSplit[1];
$tagOperator = count($tagSplit) > 2 ? $tagSplit[3] : '';
@ -222,13 +225,13 @@ class SearchRunner
$query->where('name', '=', $tagName);
}
});
return $query;
}
/**
* Custom entity search filters
* Custom entity search filters.
*/
protected function filterUpdatedAfter(EloquentBuilder $query, Entity $model, $input)
{
try {
@ -338,11 +341,9 @@ class SearchRunner
}
}
/**
* Sorting filter options
* Sorting filter options.
*/
protected function sortByLastCommented(EloquentBuilder $query, Entity $model)
{
$commentsTable = $this->db->getTablePrefix() . 'comments';

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use BookStack\Entities\EntityProvider;
use BookStack\Entities\Models\Book;
@ -7,13 +9,12 @@ use Illuminate\Support\Collection;
class SiblingFetcher
{
/**
* Search among the siblings of the entity of given type and id.
*/
public function fetch(string $entityType, int $entityId): Collection
{
$entity = (new EntityProvider)->get($entityType)->visible()->findOrFail($entityId);
$entity = (new EntityProvider())->get($entityType)->visible()->findOrFail($entityId);
$entities = [];
// Page in chapter
@ -29,7 +30,7 @@ class SiblingFetcher
// Book
// Gets just the books in a shelf if shelf is in context
if ($entity->isA('book')) {
$contextShelf = (new ShelfContext)->getContextualShelfForBook($entity);
$contextShelf = (new ShelfContext())->getContextualShelfForBook($entity);
if ($contextShelf) {
$entities = $contextShelf->visibleBooks()->get();
} else {

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use BookStack\Entities\Models\BookChild;
use BookStack\Interfaces\Sluggable;
@ -6,7 +8,6 @@ use Illuminate\Support\Str;
class SlugGenerator
{
/**
* Generate a fresh slug for the given entity.
* The slug will generated so it does not conflict within the same parent item.
@ -17,6 +18,7 @@ class SlugGenerator
while ($this->slugInUse($slug, $model)) {
$slug .= '-' . Str::random(3);
}
return $slug;
}
@ -26,9 +28,10 @@ class SlugGenerator
protected function formatNameAsSlug(string $name): string
{
$slug = Str::slug($name);
if ($slug === "") {
if ($slug === '') {
$slug = substr(md5(rand(1, 500)), 0, 5);
}
return $slug;
}

View File

@ -1,11 +1,13 @@
<?php namespace BookStack\Entities\Tools;
<?php
namespace BookStack\Entities\Tools;
use BookStack\Entities\EntityProvider;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Deletion;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\EntityProvider;
use BookStack\Entities\Models\HasCoverImage;
use BookStack\Entities\Models\Page;
use BookStack\Exceptions\NotifyException;
@ -17,7 +19,6 @@ use Illuminate\Support\Carbon;
class TrashCan
{
/**
* Send a shelf to the recycle bin.
*/
@ -29,6 +30,7 @@ class TrashCan
/**
* Send a book to the recycle bin.
*
* @throws Exception
*/
public function softDestroyBook(Book $book)
@ -48,6 +50,7 @@ class TrashCan
/**
* Send a chapter to the recycle bin.
*
* @throws Exception
*/
public function softDestroyChapter(Chapter $chapter, bool $recordDelete = true)
@ -67,6 +70,7 @@ class TrashCan
/**
* Send a page to the recycle bin.
*
* @throws Exception
*/
public function softDestroyPage(Page $page, bool $recordDelete = true)
@ -89,18 +93,21 @@ class TrashCan
/**
* Remove a bookshelf from the system.
*
* @throws Exception
*/
protected function destroyShelf(Bookshelf $shelf): int
{
$this->destroyCommonRelations($shelf);
$shelf->forceDelete();
return 1;
}
/**
* Remove a book from the system.
* Destroys any child chapters and pages.
*
* @throws Exception
*/
protected function destroyBook(Book $book): int
@ -120,12 +127,14 @@ class TrashCan
$this->destroyCommonRelations($book);
$book->forceDelete();
return $count + 1;
}
/**
* Remove a chapter from the system.
* Destroys all pages within.
*
* @throws Exception
*/
protected function destroyChapter(Chapter $chapter): int
@ -141,11 +150,13 @@ class TrashCan
$this->destroyCommonRelations($chapter);
$chapter->forceDelete();
return $count + 1;
}
/**
* Remove a page from the system.
*
* @throws Exception
*/
protected function destroyPage(Page $page): int
@ -160,6 +171,7 @@ class TrashCan
}
$page->forceDelete();
return 1;
}
@ -172,7 +184,7 @@ class TrashCan
$counts = [];
/** @var Entity $instance */
foreach ((new EntityProvider)->all() as $key => $instance) {
foreach ((new EntityProvider())->all() as $key => $instance) {
$counts[$key] = $instance->newQuery()->onlyTrashed()->count();
}
@ -181,6 +193,7 @@ class TrashCan
/**
* Destroy all items that have pending deletions.
*
* @throws Exception
*/
public function empty(): int
@ -190,11 +203,13 @@ class TrashCan
foreach ($deletions as $deletion) {
$deleteCount += $this->destroyFromDeletion($deletion);
}
return $deleteCount;
}
/**
* Destroy an element from the given deletion model.
*
* @throws Exception
*/
public function destroyFromDeletion(Deletion $deletion): int
@ -207,11 +222,13 @@ class TrashCan
$count = $this->destroyEntity($deletion->deletable);
}
$deletion->delete();
return $count;
}
/**
* Restore the content within the given deletion.
*
* @throws Exception
*/
public function restoreFromDeletion(Deletion $deletion): int
@ -229,6 +246,7 @@ class TrashCan
}
$deletion->delete();
return $restoreCount;
}
@ -236,6 +254,7 @@ class TrashCan
* Automatically clear old content from the recycle bin
* depending on the configured lifetime.
* Returns the total number of deleted elements.
*
* @throws Exception
*/
public function autoClearOld(): int
@ -287,6 +306,7 @@ class TrashCan
/**
* Destroy the given entity.
*
* @throws Exception
*/
protected function destroyEntity(Entity $entity): int

View File

@ -4,5 +4,4 @@ namespace BookStack\Exceptions;
class ApiAuthException extends UnauthorizedException
{
}

View File

@ -1,6 +1,7 @@
<?php namespace BookStack\Exceptions;
<?php
namespace BookStack\Exceptions;
class ConfirmationEmailException extends NotifyException
{
}

View File

@ -1,6 +1,7 @@
<?php namespace BookStack\Exceptions;
<?php
namespace BookStack\Exceptions;
class FileUploadException extends PrettyException
{
}

View File

@ -35,9 +35,10 @@ class Handler extends ExceptionHandler
* Report or log an exception.
*
* @param Exception $exception
* @return void
*
* @throws Exception
*
* @return void
*/
public function report(Exception $exception)
{
@ -49,6 +50,7 @@ class Handler extends ExceptionHandler
*
* @param \Illuminate\Http\Request $request
* @param Exception $e
*
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
@ -83,7 +85,7 @@ class Handler extends ExceptionHandler
$responseData = [
'error' => [
'message' => $e->getMessage(),
]
],
];
if ($e instanceof ValidationException) {
@ -92,6 +94,7 @@ class Handler extends ExceptionHandler
}
$responseData['error']['code'] = $code;
return new JsonResponse($responseData, $code, $headers);
}
@ -100,6 +103,7 @@ class Handler extends ExceptionHandler
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception
*
* @return \Illuminate\Http\Response
*/
protected function unauthenticated($request, AuthenticationException $exception)
@ -116,6 +120,7 @@ class Handler extends ExceptionHandler
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Validation\ValidationException $exception
*
* @return \Illuminate\Http\JsonResponse
*/
protected function invalidJson($request, ValidationException $exception)

View File

@ -1,4 +1,6 @@
<?php namespace BookStack\Exceptions;
<?php
namespace BookStack\Exceptions;
use Exception;

View File

@ -1,6 +1,7 @@
<?php namespace BookStack\Exceptions;
<?php
namespace BookStack\Exceptions;
class ImageUploadException extends PrettyException
{
}

View File

@ -1,10 +1,11 @@
<?php namespace BookStack\Exceptions;
<?php
namespace BookStack\Exceptions;
use Exception;
class JsonDebugException extends Exception
{
protected $data;
/**

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