Merge branch 'master' into release
This commit is contained in:
		
						commit
						d7adcf6c69
					
				| 
						 | 
				
			
			@ -48,6 +48,7 @@ GITHUB_APP_ID=false
 | 
			
		|||
GITHUB_APP_SECRET=false
 | 
			
		||||
GOOGLE_APP_ID=false
 | 
			
		||||
GOOGLE_APP_SECRET=false
 | 
			
		||||
GOOGLE_SELECT_ACCOUNT=false
 | 
			
		||||
OKTA_BASE_URL=false
 | 
			
		||||
OKTA_APP_ID=false
 | 
			
		||||
OKTA_APP_SECRET=false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,9 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace BookStack;
 | 
			
		||||
namespace BookStack\Actions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\User;
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @property string  key
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Actions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Activity;
 | 
			
		||||
use BookStack\Entity;
 | 
			
		||||
use BookStack\Auth\Permissions\PermissionService;
 | 
			
		||||
use BookStack\Entities\Entity;
 | 
			
		||||
use Session;
 | 
			
		||||
 | 
			
		||||
class ActivityService
 | 
			
		||||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ class ActivityService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * ActivityService constructor.
 | 
			
		||||
     * @param Activity $activity
 | 
			
		||||
     * @param \BookStack\Actions\Activity $activity
 | 
			
		||||
     * @param PermissionService $permissionService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(Activity $activity, PermissionService $permissionService)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Actions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Ownable;
 | 
			
		||||
 | 
			
		||||
class Comment extends Ownable
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
<?php namespace BookStack\Repos;
 | 
			
		||||
<?php namespace BookStack\Actions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Comment;
 | 
			
		||||
use BookStack\Entity;
 | 
			
		||||
use BookStack\Entities\Entity;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CommentRepo
 | 
			
		||||
| 
						 | 
				
			
			@ -11,13 +10,13 @@ class CommentRepo
 | 
			
		|||
{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Comment $comment
 | 
			
		||||
     * @var \BookStack\Actions\Comment $comment
 | 
			
		||||
     */
 | 
			
		||||
    protected $comment;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * CommentRepo constructor.
 | 
			
		||||
     * @param Comment $comment
 | 
			
		||||
     * @param \BookStack\Actions\Comment $comment
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(Comment $comment)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +26,7 @@ class CommentRepo
 | 
			
		|||
    /**
 | 
			
		||||
     * Get a comment by ID.
 | 
			
		||||
     * @param $id
 | 
			
		||||
     * @return Comment|\Illuminate\Database\Eloquent\Model
 | 
			
		||||
     * @return \BookStack\Actions\Comment|\Illuminate\Database\Eloquent\Model
 | 
			
		||||
     */
 | 
			
		||||
    public function getById($id)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -36,9 +35,9 @@ class CommentRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new comment on an entity.
 | 
			
		||||
     * @param Entity $entity
 | 
			
		||||
     * @param \BookStack\Entities\Entity $entity
 | 
			
		||||
     * @param array $data
 | 
			
		||||
     * @return Comment
 | 
			
		||||
     * @return \BookStack\Actions\Comment
 | 
			
		||||
     */
 | 
			
		||||
    public function create(Entity $entity, $data = [])
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +52,7 @@ class CommentRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update an existing comment.
 | 
			
		||||
     * @param Comment $comment
 | 
			
		||||
     * @param \BookStack\Actions\Comment $comment
 | 
			
		||||
     * @param array $input
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +65,7 @@ class CommentRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete a comment from the system.
 | 
			
		||||
     * @param Comment $comment
 | 
			
		||||
     * @param \BookStack\Actions\Comment $comment
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function delete($comment)
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +75,7 @@ class CommentRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the next local ID relative to the linked entity.
 | 
			
		||||
     * @param Entity $entity
 | 
			
		||||
     * @param \BookStack\Entities\Entity $entity
 | 
			
		||||
     * @return int
 | 
			
		||||
     */
 | 
			
		||||
    protected function getNextLocalId(Entity $entity)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Actions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class Attribute
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +1,7 @@
 | 
			
		|||
<?php namespace BookStack\Repos;
 | 
			
		||||
<?php namespace BookStack\Actions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Tag;
 | 
			
		||||
use BookStack\Entity;
 | 
			
		||||
use BookStack\Services\PermissionService;
 | 
			
		||||
use BookStack\Auth\Permissions\PermissionService;
 | 
			
		||||
use BookStack\Entities\Entity;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class TagRepo
 | 
			
		||||
| 
						 | 
				
			
			@ -17,9 +16,9 @@ class TagRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * TagRepo constructor.
 | 
			
		||||
     * @param Tag $attr
 | 
			
		||||
     * @param Entity $ent
 | 
			
		||||
     * @param PermissionService $ps
 | 
			
		||||
     * @param \BookStack\Actions\Tag $attr
 | 
			
		||||
     * @param \BookStack\Entities\Entity $ent
 | 
			
		||||
     * @param \BookStack\Auth\Permissions\PermissionService $ps
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(Tag $attr, Entity $ent, PermissionService $ps)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +106,7 @@ class TagRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Save an array of tags to an entity
 | 
			
		||||
     * @param Entity $entity
 | 
			
		||||
     * @param \BookStack\Entities\Entity $entity
 | 
			
		||||
     * @param array $tags
 | 
			
		||||
     * @return array|\Illuminate\Database\Eloquent\Collection
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -128,7 +127,7 @@ class TagRepo
 | 
			
		|||
    /**
 | 
			
		||||
     * Create a new Tag instance from user input.
 | 
			
		||||
     * @param $input
 | 
			
		||||
     * @return Tag
 | 
			
		||||
     * @return \BookStack\Actions\Tag
 | 
			
		||||
     */
 | 
			
		||||
    protected function newInstanceFromInput($input)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Actions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
 | 
			
		||||
class View extends Model
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Actions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Entity;
 | 
			
		||||
use BookStack\View;
 | 
			
		||||
use BookStack\Auth\Permissions\PermissionService;
 | 
			
		||||
use BookStack\Entities\Entity;
 | 
			
		||||
 | 
			
		||||
class ViewService
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -10,8 +10,8 @@ class ViewService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * ViewService constructor.
 | 
			
		||||
     * @param View $view
 | 
			
		||||
     * @param PermissionService $permissionService
 | 
			
		||||
     * @param \BookStack\Actions\View $view
 | 
			
		||||
     * @param \BookStack\Auth\Permissions\PermissionService $permissionService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(View $view, PermissionService $permissionService)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -50,12 +50,13 @@ class ViewService
 | 
			
		|||
     * Get the entities with the most views.
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @param int $page
 | 
			
		||||
     * @param bool|false|array $filterModel
 | 
			
		||||
     * @param Entity|false|array $filterModel
 | 
			
		||||
     * @param string $action - used for permission checking
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    public function getPopular($count = 10, $page = 0, $filterModel = false, $action = 'view')
 | 
			
		||||
    {
 | 
			
		||||
        // TODO - Standardise input filter
 | 
			
		||||
        $skipCount = $count * $page;
 | 
			
		||||
        $query = $this->permissionService->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type', $action)
 | 
			
		||||
            ->select('*', 'viewable_id', 'viewable_type', \DB::raw('SUM(views) as view_count'))
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +66,7 @@ class ViewService
 | 
			
		|||
        if ($filterModel && is_array($filterModel)) {
 | 
			
		||||
            $query->whereIn('viewable_type', $filterModel);
 | 
			
		||||
        } else if ($filterModel) {
 | 
			
		||||
            $query->where('viewable_type', '=', get_class($filterModel));
 | 
			
		||||
            $query->where('viewable_type', '=', $filterModel->getMorphClass());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $query->with('viewable')->skip($skipCount)->take($count)->get()->pluck('viewable');
 | 
			
		||||
| 
						 | 
				
			
			@ -89,7 +90,7 @@ class ViewService
 | 
			
		|||
            ->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type');
 | 
			
		||||
 | 
			
		||||
        if ($filterModel) {
 | 
			
		||||
            $query = $query->where('viewable_type', '=', get_class($filterModel));
 | 
			
		||||
            $query = $query->where('viewable_type', '=', $filterModel->getMorphClass());
 | 
			
		||||
        }
 | 
			
		||||
        $query = $query->where('user_id', '=', $user->id);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,11 +1,11 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Auth\Access;
 | 
			
		||||
 | 
			
		||||
use BookStack\Notifications\ConfirmEmail;
 | 
			
		||||
use BookStack\Repos\UserRepo;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use BookStack\Auth\User;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use BookStack\Exceptions\ConfirmationEmailException;
 | 
			
		||||
use BookStack\Exceptions\UserRegistrationException;
 | 
			
		||||
use BookStack\User;
 | 
			
		||||
use BookStack\Notifications\ConfirmEmail;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use Illuminate\Database\Connection as Database;
 | 
			
		||||
 | 
			
		||||
class EmailConfirmationService
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ class EmailConfirmationService
 | 
			
		|||
    /**
 | 
			
		||||
     * EmailConfirmationService constructor.
 | 
			
		||||
     * @param Database $db
 | 
			
		||||
     * @param UserRepo $users
 | 
			
		||||
     * @param \BookStack\Auth\UserRepo $users
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(Database $db, UserRepo $users)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ class EmailConfirmationService
 | 
			
		|||
    /**
 | 
			
		||||
     * Create new confirmation for a user,
 | 
			
		||||
     * Also removes any existing old ones.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param \BookStack\Auth\User $user
 | 
			
		||||
     * @throws ConfirmationEmailException
 | 
			
		||||
     */
 | 
			
		||||
    public function sendConfirmation(User $user)
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +88,7 @@ class EmailConfirmationService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete all email confirmations that belong to a user.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param \BookStack\Auth\User $user
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function deleteConfirmationsByUser(User $user)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Auth\Access;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class Ldap
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +1,10 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Auth\Access;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\Access;
 | 
			
		||||
use BookStack\Auth\Role;
 | 
			
		||||
use BookStack\Auth\User;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use BookStack\Exceptions\LdapException;
 | 
			
		||||
use BookStack\Repos\UserRepo;
 | 
			
		||||
use BookStack\Role;
 | 
			
		||||
use BookStack\User;
 | 
			
		||||
use Illuminate\Contracts\Auth\Authenticatable;
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -24,9 +25,9 @@ class LdapService
 | 
			
		|||
    /**
 | 
			
		||||
     * LdapService constructor.
 | 
			
		||||
     * @param Ldap $ldap
 | 
			
		||||
     * @param UserRepo $userRepo
 | 
			
		||||
     * @param \BookStack\Auth\UserRepo $userRepo
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(Ldap $ldap, UserRepo $userRepo)
 | 
			
		||||
    public function __construct(Access\Ldap $ldap, UserRepo $userRepo)
 | 
			
		||||
    {
 | 
			
		||||
        $this->ldap = $ldap;
 | 
			
		||||
        $this->config = config('services.ldap');
 | 
			
		||||
| 
						 | 
				
			
			@ -298,7 +299,7 @@ class LdapService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sync the LDAP groups to the user roles for the current user
 | 
			
		||||
     * @param \BookStack\User $user
 | 
			
		||||
     * @param \BookStack\Auth\User $user
 | 
			
		||||
     * @param string $username
 | 
			
		||||
     * @throws LdapException
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -347,7 +348,7 @@ class LdapService
 | 
			
		|||
    /**
 | 
			
		||||
     * Check a role against an array of group names to see if it matches.
 | 
			
		||||
     * Checked against role 'external_auth_id' if set otherwise the name of the role.
 | 
			
		||||
     * @param Role $role
 | 
			
		||||
     * @param \BookStack\Auth\Role $role
 | 
			
		||||
     * @param array $groupNames
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,11 +1,11 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Auth\Access;
 | 
			
		||||
 | 
			
		||||
use BookStack\Exceptions\SocialSignInAccountNotUsed;
 | 
			
		||||
use Laravel\Socialite\Contracts\Factory as Socialite;
 | 
			
		||||
use BookStack\Auth\SocialAccount;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use BookStack\Exceptions\SocialDriverNotConfigured;
 | 
			
		||||
use BookStack\Exceptions\SocialSignInAccountNotUsed;
 | 
			
		||||
use BookStack\Exceptions\UserRegistrationException;
 | 
			
		||||
use BookStack\Repos\UserRepo;
 | 
			
		||||
use BookStack\SocialAccount;
 | 
			
		||||
use Laravel\Socialite\Contracts\Factory as Socialite;
 | 
			
		||||
use Laravel\Socialite\Contracts\User as SocialUser;
 | 
			
		||||
 | 
			
		||||
class SocialAuthService
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ class SocialAuthService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * SocialAuthService constructor.
 | 
			
		||||
     * @param UserRepo      $userRepo
 | 
			
		||||
     * @param \BookStack\Auth\UserRepo      $userRepo
 | 
			
		||||
     * @param Socialite     $socialite
 | 
			
		||||
     * @param SocialAccount $socialAccount
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -40,7 +40,7 @@ class SocialAuthService
 | 
			
		|||
    public function startLogIn($socialDriver)
 | 
			
		||||
    {
 | 
			
		||||
        $driver = $this->validateDriver($socialDriver);
 | 
			
		||||
        return $this->socialite->driver($driver)->redirect();
 | 
			
		||||
        return $this->getSocialDriver($driver)->redirect();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ class SocialAuthService
 | 
			
		|||
    public function startRegister($socialDriver)
 | 
			
		||||
    {
 | 
			
		||||
        $driver = $this->validateDriver($socialDriver);
 | 
			
		||||
        return $this->socialite->driver($driver)->redirect();
 | 
			
		||||
        return $this->getSocialDriver($driver)->redirect();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -247,4 +247,20 @@ class SocialAuthService
 | 
			
		|||
        session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => title_case($socialDriver)]));
 | 
			
		||||
        return redirect(user()->getEditUrl());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Provide redirect options per service for the Laravel Socialite driver
 | 
			
		||||
     * @param $driverName
 | 
			
		||||
     * @return \Laravel\Socialite\Contracts\Provider
 | 
			
		||||
     */
 | 
			
		||||
    public function getSocialDriver(string $driverName)
 | 
			
		||||
    {
 | 
			
		||||
        $driver = $this->socialite->driver($driverName);
 | 
			
		||||
 | 
			
		||||
        if ($driverName === 'google' && config('services.google.select_account')) {
 | 
			
		||||
            $driver->with(['prompt' => 'select_account']);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $driver;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Auth\Permissions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
 | 
			
		||||
class EntityPermission extends Model
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,8 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Auth\Permissions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\Role;
 | 
			
		||||
use BookStack\Entities\Entity;
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
 | 
			
		||||
class JointPermission extends Model
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1,15 +1,14 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Auth\Permissions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Book;
 | 
			
		||||
use BookStack\Bookshelf;
 | 
			
		||||
use BookStack\Chapter;
 | 
			
		||||
use BookStack\Entity;
 | 
			
		||||
use BookStack\EntityPermission;
 | 
			
		||||
use BookStack\JointPermission;
 | 
			
		||||
use BookStack\Auth\Permissions;
 | 
			
		||||
use BookStack\Auth\Role;
 | 
			
		||||
use BookStack\Entities\Book;
 | 
			
		||||
use BookStack\Entities\Bookshelf;
 | 
			
		||||
use BookStack\Entities\Chapter;
 | 
			
		||||
use BookStack\Entities\Entity;
 | 
			
		||||
use BookStack\Entities\EntityProvider;
 | 
			
		||||
use BookStack\Entities\Page;
 | 
			
		||||
use BookStack\Ownable;
 | 
			
		||||
use BookStack\Page;
 | 
			
		||||
use BookStack\Role;
 | 
			
		||||
use BookStack\User;
 | 
			
		||||
use Illuminate\Database\Connection;
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder;
 | 
			
		||||
use Illuminate\Database\Query\Builder as QueryBuilder;
 | 
			
		||||
| 
						 | 
				
			
			@ -23,17 +22,31 @@ class PermissionService
 | 
			
		|||
    protected $userRoles = false;
 | 
			
		||||
    protected $currentUserModel = false;
 | 
			
		||||
 | 
			
		||||
    public $book;
 | 
			
		||||
    public $chapter;
 | 
			
		||||
    public $page;
 | 
			
		||||
    public $bookshelf;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Connection
 | 
			
		||||
     */
 | 
			
		||||
    protected $db;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var JointPermission
 | 
			
		||||
     */
 | 
			
		||||
    protected $jointPermission;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Role
 | 
			
		||||
     */
 | 
			
		||||
    protected $role;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var EntityPermission
 | 
			
		||||
     */
 | 
			
		||||
    protected $entityPermission;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var EntityProvider
 | 
			
		||||
     */
 | 
			
		||||
    protected $entityProvider;
 | 
			
		||||
 | 
			
		||||
    protected $entityCache;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -42,29 +55,20 @@ class PermissionService
 | 
			
		|||
     * @param EntityPermission $entityPermission
 | 
			
		||||
     * @param Role $role
 | 
			
		||||
     * @param Connection $db
 | 
			
		||||
     * @param Bookshelf $bookshelf
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param Chapter $chapter
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param EntityProvider $entityProvider
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        JointPermission $jointPermission,
 | 
			
		||||
        EntityPermission $entityPermission,
 | 
			
		||||
        Permissions\EntityPermission $entityPermission,
 | 
			
		||||
        Role $role,
 | 
			
		||||
        Connection $db,
 | 
			
		||||
        Bookshelf $bookshelf,
 | 
			
		||||
        Book $book,
 | 
			
		||||
        Chapter $chapter,
 | 
			
		||||
        Page $page
 | 
			
		||||
        EntityProvider $entityProvider
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->db = $db;
 | 
			
		||||
        $this->jointPermission = $jointPermission;
 | 
			
		||||
        $this->entityPermission = $entityPermission;
 | 
			
		||||
        $this->role = $role;
 | 
			
		||||
        $this->bookshelf = $bookshelf;
 | 
			
		||||
        $this->book = $book;
 | 
			
		||||
        $this->chapter = $chapter;
 | 
			
		||||
        $this->page = $page;
 | 
			
		||||
        $this->entityProvider = $entityProvider;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +82,7 @@ class PermissionService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Prepare the local entity cache and ensure it's empty
 | 
			
		||||
     * @param Entity[] $entities
 | 
			
		||||
     * @param \BookStack\Entities\Entity[] $entities
 | 
			
		||||
     */
 | 
			
		||||
    protected function readyEntityCache($entities = [])
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +108,7 @@ class PermissionService
 | 
			
		|||
            return $this->entityCache['book']->get($bookId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $book = $this->book->find($bookId);
 | 
			
		||||
        $book = $this->entityProvider->book->find($bookId);
 | 
			
		||||
        if ($book === null) {
 | 
			
		||||
            $book = false;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +119,7 @@ class PermissionService
 | 
			
		|||
    /**
 | 
			
		||||
     * Get a chapter via ID, Checks local cache
 | 
			
		||||
     * @param $chapterId
 | 
			
		||||
     * @return Book
 | 
			
		||||
     * @return \BookStack\Entities\Book
 | 
			
		||||
     */
 | 
			
		||||
    protected function getChapter($chapterId)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +127,7 @@ class PermissionService
 | 
			
		|||
            return $this->entityCache['chapter']->get($chapterId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $chapter = $this->chapter->find($chapterId);
 | 
			
		||||
        $chapter = $this->entityProvider->chapter->find($chapterId);
 | 
			
		||||
        if ($chapter === null) {
 | 
			
		||||
            $chapter = false;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +176,7 @@ class PermissionService
 | 
			
		|||
        });
 | 
			
		||||
 | 
			
		||||
        // Chunk through all bookshelves
 | 
			
		||||
        $this->bookshelf->newQuery()->select(['id', 'restricted', 'created_by'])
 | 
			
		||||
        $this->entityProvider->bookshelf->newQuery()->select(['id', 'restricted', 'created_by'])
 | 
			
		||||
            ->chunk(50, function ($shelves) use ($roles) {
 | 
			
		||||
                $this->buildJointPermissionsForShelves($shelves, $roles);
 | 
			
		||||
            });
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +188,8 @@ class PermissionService
 | 
			
		|||
     */
 | 
			
		||||
    protected function bookFetchQuery()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->book->newQuery()->select(['id', 'restricted', 'created_by'])->with(['chapters' => function ($query) {
 | 
			
		||||
        return $this->entityProvider->book->newQuery()
 | 
			
		||||
            ->select(['id', 'restricted', 'created_by'])->with(['chapters' => function ($query) {
 | 
			
		||||
            $query->select(['id', 'restricted', 'created_by', 'book_id']);
 | 
			
		||||
        }, 'pages'  => function ($query) {
 | 
			
		||||
            $query->select(['id', 'restricted', 'created_by', 'book_id', 'chapter_id']);
 | 
			
		||||
| 
						 | 
				
			
			@ -234,7 +239,7 @@ class PermissionService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Rebuild the entity jointPermissions for a particular entity.
 | 
			
		||||
     * @param Entity $entity
 | 
			
		||||
     * @param \BookStack\Entities\Entity $entity
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    public function buildJointPermissionsForEntity(Entity $entity)
 | 
			
		||||
| 
						 | 
				
			
			@ -290,7 +295,7 @@ class PermissionService
 | 
			
		|||
        });
 | 
			
		||||
 | 
			
		||||
        // Chunk through all bookshelves
 | 
			
		||||
        $this->bookshelf->newQuery()->select(['id', 'restricted', 'created_by'])
 | 
			
		||||
        $this->entityProvider->bookshelf->newQuery()->select(['id', 'restricted', 'created_by'])
 | 
			
		||||
            ->chunk(50, function ($shelves) use ($roles) {
 | 
			
		||||
                $this->buildJointPermissionsForShelves($shelves, $roles);
 | 
			
		||||
            });
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +334,7 @@ class PermissionService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete all of the entity jointPermissions for a list of entities.
 | 
			
		||||
     * @param Entity[] $entities
 | 
			
		||||
     * @param \BookStack\Entities\Entity[] $entities
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    protected function deleteManyJointPermissionsForEntities($entities)
 | 
			
		||||
| 
						 | 
				
			
			@ -410,7 +415,7 @@ class PermissionService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the actions related to an entity.
 | 
			
		||||
     * @param Entity $entity
 | 
			
		||||
     * @param \BookStack\Entities\Entity $entity
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    protected function getActions(Entity $entity)
 | 
			
		||||
| 
						 | 
				
			
			@ -496,7 +501,7 @@ class PermissionService
 | 
			
		|||
    /**
 | 
			
		||||
     * Create an array of data with the information of an entity jointPermissions.
 | 
			
		||||
     * Used to build data for bulk insertion.
 | 
			
		||||
     * @param Entity $entity
 | 
			
		||||
     * @param \BookStack\Entities\Entity $entity
 | 
			
		||||
     * @param Role $role
 | 
			
		||||
     * @param $action
 | 
			
		||||
     * @param $permissionAll
 | 
			
		||||
| 
						 | 
				
			
			@ -554,7 +559,7 @@ class PermissionService
 | 
			
		|||
    /**
 | 
			
		||||
     * Check if an entity has restrictions set on itself or its
 | 
			
		||||
     * parent tree.
 | 
			
		||||
     * @param Entity $entity
 | 
			
		||||
     * @param \BookStack\Entities\Entity $entity
 | 
			
		||||
     * @param $action
 | 
			
		||||
     * @return bool|mixed
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -604,7 +609,9 @@ class PermissionService
 | 
			
		|||
     */
 | 
			
		||||
    public function bookChildrenQuery($book_id, $filterDrafts = false, $fetchPageContent = false)
 | 
			
		||||
    {
 | 
			
		||||
        $pageSelect = $this->db->table('pages')->selectRaw($this->page->entityRawQuery($fetchPageContent))->where('book_id', '=', $book_id)->where(function ($query) use ($filterDrafts) {
 | 
			
		||||
        $entities = $this->entityProvider;
 | 
			
		||||
        $pageSelect = $this->db->table('pages')->selectRaw($entities->page->entityRawQuery($fetchPageContent))
 | 
			
		||||
            ->where('book_id', '=', $book_id)->where(function ($query) use ($filterDrafts) {
 | 
			
		||||
            $query->where('draft', '=', 0);
 | 
			
		||||
            if (!$filterDrafts) {
 | 
			
		||||
                $query->orWhere(function ($query) {
 | 
			
		||||
| 
						 | 
				
			
			@ -612,7 +619,7 @@ class PermissionService
 | 
			
		|||
                });
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        $chapterSelect = $this->db->table('chapters')->selectRaw($this->chapter->entityRawQuery())->where('book_id', '=', $book_id);
 | 
			
		||||
        $chapterSelect = $this->db->table('chapters')->selectRaw($entities->chapter->entityRawQuery())->where('book_id', '=', $book_id);
 | 
			
		||||
        $query = $this->db->query()->select('*')->from($this->db->raw("({$pageSelect->toSql()} UNION {$chapterSelect->toSql()}) AS U"))
 | 
			
		||||
            ->mergeBindings($pageSelect)->mergeBindings($chapterSelect);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -635,7 +642,7 @@ class PermissionService
 | 
			
		|||
    /**
 | 
			
		||||
     * Add restrictions for a generic entity
 | 
			
		||||
     * @param string $entityType
 | 
			
		||||
     * @param Builder|Entity $query
 | 
			
		||||
     * @param Builder|\BookStack\Entities\Entity $query
 | 
			
		||||
     * @param string $action
 | 
			
		||||
     * @return Builder
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -703,12 +710,13 @@ class PermissionService
 | 
			
		|||
        $this->currentAction = 'view';
 | 
			
		||||
        $tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn];
 | 
			
		||||
 | 
			
		||||
        $q = $query->where(function ($query) use ($tableDetails) {
 | 
			
		||||
            $query->where(function ($query) use (&$tableDetails) {
 | 
			
		||||
                $query->whereExists(function ($permissionQuery) use (&$tableDetails) {
 | 
			
		||||
        $pageMorphClass = $this->entityProvider->page->getMorphClass();
 | 
			
		||||
        $q = $query->where(function ($query) use ($tableDetails, $pageMorphClass) {
 | 
			
		||||
            $query->where(function ($query) use (&$tableDetails, $pageMorphClass) {
 | 
			
		||||
                $query->whereExists(function ($permissionQuery) use (&$tableDetails, $pageMorphClass) {
 | 
			
		||||
                    $permissionQuery->select('id')->from('joint_permissions')
 | 
			
		||||
                        ->whereRaw('joint_permissions.entity_id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
 | 
			
		||||
                        ->where('entity_type', '=', 'Bookstack\\Page')
 | 
			
		||||
                        ->where('entity_type', '=', $pageMorphClass)
 | 
			
		||||
                        ->where('action', '=', $this->currentAction)
 | 
			
		||||
                        ->whereIn('role_id', $this->getRoles())
 | 
			
		||||
                        ->where(function ($query) {
 | 
			
		||||
| 
						 | 
				
			
			@ -726,7 +734,7 @@ class PermissionService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the current user
 | 
			
		||||
     * @return User
 | 
			
		||||
     * @return \BookStack\Auth\User
 | 
			
		||||
     */
 | 
			
		||||
    private function currentUser()
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -1,10 +1,8 @@
 | 
			
		|||
<?php namespace BookStack\Repos;
 | 
			
		||||
<?php namespace BookStack\Auth\Permissions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\Permissions;
 | 
			
		||||
use BookStack\Auth\Role;
 | 
			
		||||
use BookStack\Exceptions\PermissionsException;
 | 
			
		||||
use BookStack\RolePermission;
 | 
			
		||||
use BookStack\Role;
 | 
			
		||||
use BookStack\Services\PermissionService;
 | 
			
		||||
use Setting;
 | 
			
		||||
 | 
			
		||||
class PermissionsRepo
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -19,9 +17,9 @@ class PermissionsRepo
 | 
			
		|||
     * PermissionsRepo constructor.
 | 
			
		||||
     * @param RolePermission $permission
 | 
			
		||||
     * @param Role $role
 | 
			
		||||
     * @param PermissionService $permissionService
 | 
			
		||||
     * @param \BookStack\Auth\Permissions\PermissionService $permissionService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(RolePermission $permission, Role $role, PermissionService $permissionService)
 | 
			
		||||
    public function __construct(RolePermission $permission, Role $role, Permissions\PermissionService $permissionService)
 | 
			
		||||
    {
 | 
			
		||||
        $this->permission = $permission;
 | 
			
		||||
        $this->role = $role;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,7 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Auth\Permissions;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\Role;
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
 | 
			
		||||
class RolePermission extends Model
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,7 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Auth;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\Permissions\JointPermission;
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
 | 
			
		||||
class Role extends Model
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +30,7 @@ class Role extends Model
 | 
			
		|||
     */
 | 
			
		||||
    public function permissions()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->belongsToMany(RolePermission::class, 'permission_role', 'role_id', 'permission_id');
 | 
			
		||||
        return $this->belongsToMany(Permissions\RolePermission::class, 'permission_role', 'role_id', 'permission_id');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -48,18 +51,18 @@ class Role extends Model
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add a permission to this role.
 | 
			
		||||
     * @param RolePermission $permission
 | 
			
		||||
     * @param \BookStack\Auth\Permissions\RolePermission $permission
 | 
			
		||||
     */
 | 
			
		||||
    public function attachPermission(RolePermission $permission)
 | 
			
		||||
    public function attachPermission(Permissions\RolePermission $permission)
 | 
			
		||||
    {
 | 
			
		||||
        $this->permissions()->attach($permission->id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Detach a single permission from this role.
 | 
			
		||||
     * @param RolePermission $permission
 | 
			
		||||
     * @param \BookStack\Auth\Permissions\RolePermission $permission
 | 
			
		||||
     */
 | 
			
		||||
    public function detachPermission(RolePermission $permission)
 | 
			
		||||
    public function detachPermission(Permissions\RolePermission $permission)
 | 
			
		||||
    {
 | 
			
		||||
        $this->permissions()->detach($permission->id);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Auth;
 | 
			
		||||
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
 | 
			
		||||
class SocialAccount extends Model
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Auth;
 | 
			
		||||
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
use BookStack\Notifications\ResetPassword;
 | 
			
		||||
use BookStack\Uploads\Image;
 | 
			
		||||
use Illuminate\Auth\Authenticatable;
 | 
			
		||||
use Illuminate\Auth\Passwords\CanResetPassword;
 | 
			
		||||
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,10 +1,9 @@
 | 
			
		|||
<?php namespace BookStack\Repos;
 | 
			
		||||
<?php namespace BookStack\Auth;
 | 
			
		||||
 | 
			
		||||
use Activity;
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Exceptions\NotFoundException;
 | 
			
		||||
use BookStack\Image;
 | 
			
		||||
use BookStack\Role;
 | 
			
		||||
use BookStack\User;
 | 
			
		||||
use BookStack\Uploads\Image;
 | 
			
		||||
use Exception;
 | 
			
		||||
use Images;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +79,7 @@ class UserRepo
 | 
			
		|||
     * Creates a new user and attaches a role to them.
 | 
			
		||||
     * @param array $data
 | 
			
		||||
     * @param boolean $verifyEmail
 | 
			
		||||
     * @return User
 | 
			
		||||
     * @return \BookStack\Auth\User
 | 
			
		||||
     */
 | 
			
		||||
    public function registerNew(array $data, $verifyEmail = false)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +121,7 @@ class UserRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the give user is the only admin.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param \BookStack\Auth\User $user
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    public function isOnlyAdmin(User $user)
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +141,7 @@ class UserRepo
 | 
			
		|||
     * Create a new basic instance of user.
 | 
			
		||||
     * @param array $data
 | 
			
		||||
     * @param boolean $verifyEmail
 | 
			
		||||
     * @return User
 | 
			
		||||
     * @return \BookStack\Auth\User
 | 
			
		||||
     */
 | 
			
		||||
    public function create(array $data, $verifyEmail = false)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -157,7 +156,7 @@ class UserRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Remove the given user from storage, Delete all related content.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param \BookStack\Auth\User $user
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
    public function destroy(User $user)
 | 
			
		||||
| 
						 | 
				
			
			@ -174,7 +173,7 @@ class UserRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the latest activity for a user.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param \BookStack\Auth\User $user
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @param int $page
 | 
			
		||||
     * @return array
 | 
			
		||||
| 
						 | 
				
			
			@ -186,7 +185,7 @@ class UserRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the recently created content for this given user.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param \BookStack\Auth\User $user
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -207,15 +206,15 @@ class UserRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get asset created counts for the give user.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param \BookStack\Auth\User $user
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function getAssetCounts(User $user)
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'pages'    => $this->entityRepo->page->where('created_by', '=', $user->id)->count(),
 | 
			
		||||
            'chapters' => $this->entityRepo->chapter->where('created_by', '=', $user->id)->count(),
 | 
			
		||||
            'books'    => $this->entityRepo->book->where('created_by', '=', $user->id)->count(),
 | 
			
		||||
            'pages'    => $this->entityRepo->getUserTotalCreated('page', $user),
 | 
			
		||||
            'chapters' => $this->entityRepo->getUserTotalCreated('chapter', $user),
 | 
			
		||||
            'books'    => $this->entityRepo->getUserTotalCreated('book', $user),
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Console\Commands;
 | 
			
		||||
 | 
			
		||||
use BookStack\Services\ImageService;
 | 
			
		||||
use BookStack\Uploads\ImageService;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Symfony\Component\Console\Output\OutputInterface;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ class CleanupImages extends Command
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new command instance.
 | 
			
		||||
     * @param ImageService $imageService
 | 
			
		||||
     * @param \BookStack\Uploads\ImageService $imageService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(ImageService $imageService)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Console\Commands;
 | 
			
		||||
 | 
			
		||||
use BookStack\Activity;
 | 
			
		||||
use BookStack\Actions\Activity;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
class ClearActivity extends Command
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Console\Commands;
 | 
			
		||||
 | 
			
		||||
use BookStack\PageRevision;
 | 
			
		||||
use BookStack\Entities\PageRevision;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
class ClearRevisions extends Command
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Console\Commands;
 | 
			
		||||
 | 
			
		||||
use BookStack\Repos\UserRepo;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
class CreateAdmin extends Command
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Console\Commands;
 | 
			
		||||
 | 
			
		||||
use BookStack\User;
 | 
			
		||||
use BookStack\Repos\UserRepo;
 | 
			
		||||
use BookStack\Auth\User;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
class DeleteUsers extends Command
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Console\Commands;
 | 
			
		||||
 | 
			
		||||
use BookStack\Services\PermissionService;
 | 
			
		||||
use BookStack\Auth\Permissions\PermissionService;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
class RegeneratePermissions extends Command
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +31,7 @@ class RegeneratePermissions extends Command
 | 
			
		|||
    /**
 | 
			
		||||
     * Create a new command instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param PermissionService $permissionService
 | 
			
		||||
     * @param \BookStack\Auth\\BookStack\Auth\Permissions\PermissionService $permissionService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(PermissionService $permissionService)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Console\Commands;
 | 
			
		||||
 | 
			
		||||
use BookStack\Services\SearchService;
 | 
			
		||||
use BookStack\Entities\SearchService;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
class RegenerateSearch extends Command
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ class RegenerateSearch extends Command
 | 
			
		|||
    /**
 | 
			
		||||
     * Create a new command instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param SearchService $searchService
 | 
			
		||||
     * @param \BookStack\Entities\SearchService $searchService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(SearchService $searchService)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Entities;
 | 
			
		||||
 | 
			
		||||
use BookStack\Uploads\Image;
 | 
			
		||||
 | 
			
		||||
class Book extends Entity
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -6,6 +8,15 @@ class Book extends Entity
 | 
			
		|||
 | 
			
		||||
    protected $fillable = ['name', 'description', 'image_id'];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the morph class for this model.
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getMorphClass()
 | 
			
		||||
    {
 | 
			
		||||
        return 'BookStack\\Book';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the url for this book.
 | 
			
		||||
     * @param string|bool $path
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Entities;
 | 
			
		||||
 | 
			
		||||
use BookStack\Uploads\Image;
 | 
			
		||||
 | 
			
		||||
class Bookshelf extends Entity
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +10,15 @@ class Bookshelf extends Entity
 | 
			
		|||
 | 
			
		||||
    protected $fillable = ['name', 'description', 'image_id'];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the morph class for this model.
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getMorphClass()
 | 
			
		||||
    {
 | 
			
		||||
        return 'BookStack\\Bookshelf';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the books in this shelf.
 | 
			
		||||
     * Should not be used directly since does not take into account permissions.
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Entities;
 | 
			
		||||
 | 
			
		||||
class Chapter extends Entity
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -6,6 +6,15 @@ class Chapter extends Entity
 | 
			
		|||
 | 
			
		||||
    protected $fillable = ['name', 'description', 'priority', 'book_id'];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the morph class for this model.
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getMorphClass()
 | 
			
		||||
    {
 | 
			
		||||
        return 'BookStack\\Chapter';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the book this chapter is within.
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,31 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Entities;
 | 
			
		||||
 | 
			
		||||
use BookStack\Actions\Activity;
 | 
			
		||||
use BookStack\Actions\Comment;
 | 
			
		||||
use BookStack\Actions\Tag;
 | 
			
		||||
use BookStack\Actions\View;
 | 
			
		||||
use BookStack\Auth\Permissions\EntityPermission;
 | 
			
		||||
use BookStack\Auth\Permissions\JointPermission;
 | 
			
		||||
use BookStack\Ownable;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class Entity
 | 
			
		||||
 * The base class for book-like items such as pages, chapters & books.
 | 
			
		||||
 * This is not a database model in itself but extended.
 | 
			
		||||
 *
 | 
			
		||||
 * @property integer $id
 | 
			
		||||
 * @property string $name
 | 
			
		||||
 * @property string $slug
 | 
			
		||||
 * @property Carbon $created_at
 | 
			
		||||
 * @property Carbon $updated_at
 | 
			
		||||
 * @property int $created_by
 | 
			
		||||
 * @property int $updated_by
 | 
			
		||||
 * @property boolean $restricted
 | 
			
		||||
 *
 | 
			
		||||
 * @package BookStack\Entities
 | 
			
		||||
 */
 | 
			
		||||
class Entity extends Ownable
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -15,6 +39,17 @@ class Entity extends Ownable
 | 
			
		|||
     */
 | 
			
		||||
    public $searchFactor = 1.0;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the morph class for this model.
 | 
			
		||||
     * Set here since, due to folder changes, the namespace used
 | 
			
		||||
     * in the database no longer matches the class namespace.
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getMorphClass()
 | 
			
		||||
    {
 | 
			
		||||
        return 'BookStack\\Entity';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Compares this entity to another given entity.
 | 
			
		||||
     * Matches by comparing class and id.
 | 
			
		||||
| 
						 | 
				
			
			@ -158,7 +193,7 @@ class Entity extends Ownable
 | 
			
		|||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return app('BookStack\\' . $className);
 | 
			
		||||
        return app('BookStack\\Entities\\' . $className);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,89 @@
 | 
			
		|||
<?php namespace BookStack\Entities;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class EntityProvider
 | 
			
		||||
 *
 | 
			
		||||
 * Provides access to the core entity models.
 | 
			
		||||
 * Wrapped up in this provider since they are often used together
 | 
			
		||||
 * so this is a neater alternative to injecting all in individually.
 | 
			
		||||
 *
 | 
			
		||||
 * @package BookStack\Entities
 | 
			
		||||
 */
 | 
			
		||||
class EntityProvider
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Bookshelf
 | 
			
		||||
     */
 | 
			
		||||
    public $bookshelf;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Book
 | 
			
		||||
     */
 | 
			
		||||
    public $book;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Chapter
 | 
			
		||||
     */
 | 
			
		||||
    public $chapter;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Page
 | 
			
		||||
     */
 | 
			
		||||
    public $page;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var PageRevision
 | 
			
		||||
     */
 | 
			
		||||
    public $pageRevision;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * EntityProvider constructor.
 | 
			
		||||
     * @param Bookshelf $bookshelf
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param Chapter $chapter
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param PageRevision $pageRevision
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        Bookshelf $bookshelf,
 | 
			
		||||
        Book $book,
 | 
			
		||||
        Chapter $chapter,
 | 
			
		||||
        Page $page,
 | 
			
		||||
        PageRevision $pageRevision
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->bookshelf = $bookshelf;
 | 
			
		||||
        $this->book = $book;
 | 
			
		||||
        $this->chapter = $chapter;
 | 
			
		||||
        $this->page = $page;
 | 
			
		||||
        $this->pageRevision = $pageRevision;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch all core entity types as an associated array
 | 
			
		||||
     * with their basic names as the keys.
 | 
			
		||||
     * @return Entity[]
 | 
			
		||||
     */
 | 
			
		||||
    public function all()
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'bookshelf' => $this->bookshelf,
 | 
			
		||||
            'book' => $this->book,
 | 
			
		||||
            'chapter' => $this->chapter,
 | 
			
		||||
            'page' => $this->page,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get an entity instance by it's basic name.
 | 
			
		||||
     * @param string $type
 | 
			
		||||
     * @return Entity
 | 
			
		||||
     */
 | 
			
		||||
    public function get(string $type)
 | 
			
		||||
    {
 | 
			
		||||
        $type = strtolower($type);
 | 
			
		||||
        return $this->all()[$type];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +1,7 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Entities;
 | 
			
		||||
 | 
			
		||||
use BookStack\Book;
 | 
			
		||||
use BookStack\Chapter;
 | 
			
		||||
use BookStack\Page;
 | 
			
		||||
use BookStack\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Uploads\ImageService;
 | 
			
		||||
 | 
			
		||||
class ExportService
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -13,7 +11,8 @@ class ExportService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * ExportService constructor.
 | 
			
		||||
     * @param $entityRepo
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     * @param ImageService $imageService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(EntityRepo $entityRepo, ImageService $imageService)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +23,7 @@ class ExportService
 | 
			
		|||
    /**
 | 
			
		||||
     * Convert a page to a self-contained HTML file.
 | 
			
		||||
     * Includes required CSS & image content. Images are base64 encoded into the HTML.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param \BookStack\Entities\Page $page
 | 
			
		||||
     * @return mixed|string
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +38,7 @@ class ExportService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a chapter to a self-contained HTML file.
 | 
			
		||||
     * @param Chapter $chapter
 | 
			
		||||
     * @param \BookStack\Entities\Chapter $chapter
 | 
			
		||||
     * @return mixed|string
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -89,7 +88,7 @@ class ExportService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a chapter to a PDF file.
 | 
			
		||||
     * @param Chapter $chapter
 | 
			
		||||
     * @param \BookStack\Entities\Chapter $chapter
 | 
			
		||||
     * @return mixed|string
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +107,7 @@ class ExportService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a book to a PDF file
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param \BookStack\Entities\Book $book
 | 
			
		||||
     * @return string
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -208,7 +207,7 @@ class ExportService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a chapter into a plain text string.
 | 
			
		||||
     * @param Chapter $chapter
 | 
			
		||||
     * @param \BookStack\Entities\Chapter $chapter
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function chapterToPlainText(Chapter $chapter)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Entities;
 | 
			
		||||
 | 
			
		||||
use BookStack\Uploads\Attachment;
 | 
			
		||||
 | 
			
		||||
class Page extends Entity
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +10,15 @@ class Page extends Entity
 | 
			
		|||
 | 
			
		||||
    public $textField = 'text';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the morph class for this model.
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getMorphClass()
 | 
			
		||||
    {
 | 
			
		||||
        return 'BookStack\\Page';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Converts this page into a simplified array.
 | 
			
		||||
     * @return mixed
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +126,7 @@ class Page extends Entity
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the current revision for the page if existing
 | 
			
		||||
     * @return \BookStack\PageRevision|null
 | 
			
		||||
     * @return \BookStack\Entities\PageRevision|null
 | 
			
		||||
     */
 | 
			
		||||
    public function getCurrentRevision()
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,7 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Entities;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\User;
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
 | 
			
		||||
class PageRevision extends Model
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1,54 +1,30 @@
 | 
			
		|||
<?php namespace BookStack\Repos;
 | 
			
		||||
<?php namespace BookStack\Entities\Repos;
 | 
			
		||||
 | 
			
		||||
use BookStack\Book;
 | 
			
		||||
use BookStack\Bookshelf;
 | 
			
		||||
use BookStack\Chapter;
 | 
			
		||||
use BookStack\Entity;
 | 
			
		||||
use BookStack\Actions\TagRepo;
 | 
			
		||||
use BookStack\Actions\ViewService;
 | 
			
		||||
use BookStack\Auth\Permissions\PermissionService;
 | 
			
		||||
use BookStack\Auth\User;
 | 
			
		||||
use BookStack\Entities\Book;
 | 
			
		||||
use BookStack\Entities\Bookshelf;
 | 
			
		||||
use BookStack\Entities\Chapter;
 | 
			
		||||
use BookStack\Entities\Entity;
 | 
			
		||||
use BookStack\Entities\EntityProvider;
 | 
			
		||||
use BookStack\Entities\Page;
 | 
			
		||||
use BookStack\Entities\SearchService;
 | 
			
		||||
use BookStack\Exceptions\NotFoundException;
 | 
			
		||||
use BookStack\Exceptions\NotifyException;
 | 
			
		||||
use BookStack\Page;
 | 
			
		||||
use BookStack\PageRevision;
 | 
			
		||||
use BookStack\Services\AttachmentService;
 | 
			
		||||
use BookStack\Services\PermissionService;
 | 
			
		||||
use BookStack\Services\SearchService;
 | 
			
		||||
use BookStack\Services\ViewService;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use BookStack\Uploads\AttachmentService;
 | 
			
		||||
use DOMDocument;
 | 
			
		||||
use DOMXPath;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
 | 
			
		||||
class EntityRepo
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Bookshelf
 | 
			
		||||
     */
 | 
			
		||||
    public $bookshelf;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Book $book
 | 
			
		||||
     * @var EntityProvider
 | 
			
		||||
     */
 | 
			
		||||
    public $book;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Chapter
 | 
			
		||||
     */
 | 
			
		||||
    public $chapter;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Page
 | 
			
		||||
     */
 | 
			
		||||
    public $page;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var PageRevision
 | 
			
		||||
     */
 | 
			
		||||
    protected $pageRevision;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Base entity instances keyed by type
 | 
			
		||||
     * @var []Entity
 | 
			
		||||
     */
 | 
			
		||||
    protected $entities;
 | 
			
		||||
    protected $entityProvider;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var PermissionService
 | 
			
		||||
| 
						 | 
				
			
			@ -72,63 +48,36 @@ class EntityRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * EntityRepo constructor.
 | 
			
		||||
     * @param Bookshelf $bookshelf
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param Chapter $chapter
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param PageRevision $pageRevision
 | 
			
		||||
     * @param EntityProvider $entityProvider
 | 
			
		||||
     * @param ViewService $viewService
 | 
			
		||||
     * @param PermissionService $permissionService
 | 
			
		||||
     * @param TagRepo $tagRepo
 | 
			
		||||
     * @param SearchService $searchService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        Bookshelf $bookshelf,
 | 
			
		||||
        Book $book,
 | 
			
		||||
        Chapter $chapter,
 | 
			
		||||
        Page $page,
 | 
			
		||||
        PageRevision $pageRevision,
 | 
			
		||||
        EntityProvider $entityProvider,
 | 
			
		||||
        ViewService $viewService,
 | 
			
		||||
        PermissionService $permissionService,
 | 
			
		||||
        TagRepo $tagRepo,
 | 
			
		||||
        SearchService $searchService
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->bookshelf = $bookshelf;
 | 
			
		||||
        $this->book = $book;
 | 
			
		||||
        $this->chapter = $chapter;
 | 
			
		||||
        $this->page = $page;
 | 
			
		||||
        $this->pageRevision = $pageRevision;
 | 
			
		||||
        $this->entities = [
 | 
			
		||||
            'bookshelf' => $this->bookshelf,
 | 
			
		||||
            'page' => $this->page,
 | 
			
		||||
            'chapter' => $this->chapter,
 | 
			
		||||
            'book' => $this->book
 | 
			
		||||
        ];
 | 
			
		||||
        $this->entityProvider = $entityProvider;
 | 
			
		||||
        $this->viewService = $viewService;
 | 
			
		||||
        $this->permissionService = $permissionService;
 | 
			
		||||
        $this->tagRepo = $tagRepo;
 | 
			
		||||
        $this->searchService = $searchService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get an entity instance via type.
 | 
			
		||||
     * @param $type
 | 
			
		||||
     * @return Entity
 | 
			
		||||
     */
 | 
			
		||||
    protected function getEntity($type)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->entities[strtolower($type)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Base query for searching entities via permission system
 | 
			
		||||
     * @param string $type
 | 
			
		||||
     * @param bool $allowDrafts
 | 
			
		||||
     * @param string $permission
 | 
			
		||||
     * @return \Illuminate\Database\Query\Builder
 | 
			
		||||
     */
 | 
			
		||||
    protected function entityQuery($type, $allowDrafts = false, $permission = 'view')
 | 
			
		||||
    {
 | 
			
		||||
        $q = $this->permissionService->enforceEntityRestrictions($type, $this->getEntity($type), $permission);
 | 
			
		||||
        $q = $this->permissionService->enforceEntityRestrictions($type, $this->entityProvider->get($type), $permission);
 | 
			
		||||
        if (strtolower($type) === 'page' && !$allowDrafts) {
 | 
			
		||||
            $q = $q->where('draft', '=', false);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -152,15 +101,35 @@ class EntityRepo
 | 
			
		|||
     * @param integer $id
 | 
			
		||||
     * @param bool $allowDrafts
 | 
			
		||||
     * @param bool $ignorePermissions
 | 
			
		||||
     * @return Entity
 | 
			
		||||
     * @return \BookStack\Entities\Entity
 | 
			
		||||
     */
 | 
			
		||||
    public function getById($type, $id, $allowDrafts = false, $ignorePermissions = false)
 | 
			
		||||
    {
 | 
			
		||||
        $query = $this->entityQuery($type, $allowDrafts);
 | 
			
		||||
 | 
			
		||||
        if ($ignorePermissions) {
 | 
			
		||||
            $entity = $this->getEntity($type);
 | 
			
		||||
            return $entity->newQuery()->find($id);
 | 
			
		||||
            $query = $this->entityProvider->get($type)->newQuery();
 | 
			
		||||
        }
 | 
			
		||||
        return $this->entityQuery($type, $allowDrafts)->find($id);
 | 
			
		||||
 | 
			
		||||
        return $query->find($id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param string $type
 | 
			
		||||
     * @param []int $ids
 | 
			
		||||
     * @param bool $allowDrafts
 | 
			
		||||
     * @param bool $ignorePermissions
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|Collection
 | 
			
		||||
     */
 | 
			
		||||
    public function getManyById($type, $ids, $allowDrafts = false, $ignorePermissions = false)
 | 
			
		||||
    {
 | 
			
		||||
        $query = $this->entityQuery($type, $allowDrafts);
 | 
			
		||||
 | 
			
		||||
        if ($ignorePermissions) {
 | 
			
		||||
            $query = $this->entityProvider->get($type)->newQuery();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $query->whereIn('id', $ids)->get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -168,7 +137,7 @@ class EntityRepo
 | 
			
		|||
     * @param string $type
 | 
			
		||||
     * @param string $slug
 | 
			
		||||
     * @param string|bool $bookSlug
 | 
			
		||||
     * @return Entity
 | 
			
		||||
     * @return \BookStack\Entities\Entity
 | 
			
		||||
     * @throws NotFoundException
 | 
			
		||||
     */
 | 
			
		||||
    public function getBySlug($type, $slug, $bookSlug = false)
 | 
			
		||||
| 
						 | 
				
			
			@ -178,7 +147,7 @@ class EntityRepo
 | 
			
		|||
        if (strtolower($type) === 'chapter' || strtolower($type) === 'page') {
 | 
			
		||||
            $q = $q->where('book_id', '=', function ($query) use ($bookSlug) {
 | 
			
		||||
                $query->select('id')
 | 
			
		||||
                    ->from($this->book->getTable())
 | 
			
		||||
                    ->from($this->entityProvider->book->getTable())
 | 
			
		||||
                    ->where('slug', '=', $bookSlug)->limit(1);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -190,26 +159,6 @@ class EntityRepo
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Search through page revisions and retrieve the last page in the
 | 
			
		||||
     * current book that has a slug equal to the one given.
 | 
			
		||||
     * @param string $pageSlug
 | 
			
		||||
     * @param string $bookSlug
 | 
			
		||||
     * @return null|Page
 | 
			
		||||
     */
 | 
			
		||||
    public function getPageByOldSlug($pageSlug, $bookSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $revision = $this->pageRevision->where('slug', '=', $pageSlug)
 | 
			
		||||
            ->whereHas('page', function ($query) {
 | 
			
		||||
                $this->permissionService->enforceEntityRestrictions('page', $query);
 | 
			
		||||
            })
 | 
			
		||||
            ->where('type', '=', 'version')
 | 
			
		||||
            ->where('book_slug', '=', $bookSlug)
 | 
			
		||||
            ->orderBy('created_at', 'desc')
 | 
			
		||||
            ->with('page')->first();
 | 
			
		||||
        return $revision !== null ? $revision->page : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get all entities of a type with the given permission, limited by count unless count is false.
 | 
			
		||||
     * @param string $type
 | 
			
		||||
| 
						 | 
				
			
			@ -247,7 +196,7 @@ class EntityRepo
 | 
			
		|||
     */
 | 
			
		||||
    public function getRecentlyCreated($type, $count = 20, $page = 0, $additionalQuery = false)
 | 
			
		||||
    {
 | 
			
		||||
        $query = $this->permissionService->enforceEntityRestrictions($type, $this->getEntity($type))
 | 
			
		||||
        $query = $this->permissionService->enforceEntityRestrictions($type, $this->entityProvider->get($type))
 | 
			
		||||
            ->orderBy('created_at', 'desc');
 | 
			
		||||
        if (strtolower($type) === 'page') {
 | 
			
		||||
            $query = $query->where('draft', '=', false);
 | 
			
		||||
| 
						 | 
				
			
			@ -268,7 +217,7 @@ class EntityRepo
 | 
			
		|||
     */
 | 
			
		||||
    public function getRecentlyUpdated($type, $count = 20, $page = 0, $additionalQuery = false)
 | 
			
		||||
    {
 | 
			
		||||
        $query = $this->permissionService->enforceEntityRestrictions($type, $this->getEntity($type))
 | 
			
		||||
        $query = $this->permissionService->enforceEntityRestrictions($type, $this->entityProvider->get($type))
 | 
			
		||||
            ->orderBy('updated_at', 'desc');
 | 
			
		||||
        if (strtolower($type) === 'page') {
 | 
			
		||||
            $query = $query->where('draft', '=', false);
 | 
			
		||||
| 
						 | 
				
			
			@ -288,7 +237,7 @@ class EntityRepo
 | 
			
		|||
     */
 | 
			
		||||
    public function getRecentlyViewed($type, $count = 10, $page = 0)
 | 
			
		||||
    {
 | 
			
		||||
        $filter = is_bool($type) ? false : $this->getEntity($type);
 | 
			
		||||
        $filter = is_bool($type) ? false : $this->entityProvider->get($type);
 | 
			
		||||
        return $this->viewService->getUserRecentlyViewed($count, $page, $filter);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -323,7 +272,7 @@ class EntityRepo
 | 
			
		|||
     */
 | 
			
		||||
    public function getPopular($type, $count = 10, $page = 0)
 | 
			
		||||
    {
 | 
			
		||||
        $filter = is_bool($type) ? false : $this->getEntity($type);
 | 
			
		||||
        $filter = is_bool($type) ? false : $this->entityProvider->get($type);
 | 
			
		||||
        return $this->viewService->getPopular($count, $page, $filter);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -331,19 +280,32 @@ class EntityRepo
 | 
			
		|||
     * Get draft pages owned by the current user.
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @param int $page
 | 
			
		||||
     * @return Collection
 | 
			
		||||
     */
 | 
			
		||||
    public function getUserDraftPages($count = 20, $page = 0)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->page->where('draft', '=', true)
 | 
			
		||||
        return $this->entityProvider->page->where('draft', '=', true)
 | 
			
		||||
            ->where('created_by', '=', user()->id)
 | 
			
		||||
            ->orderBy('updated_at', 'desc')
 | 
			
		||||
            ->skip($count * $page)->take($count)->get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the number of entities the given user has created.
 | 
			
		||||
     * @param string $type
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @return int
 | 
			
		||||
     */
 | 
			
		||||
    public function getUserTotalCreated(string $type, User $user)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->entityProvider->get($type)
 | 
			
		||||
            ->where('created_by', '=', $user->id)->count();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the child items for a chapter sorted by priority but
 | 
			
		||||
     * with draft items floated to the top.
 | 
			
		||||
     * @param Bookshelf $bookshelf
 | 
			
		||||
     * @param \BookStack\Entities\Bookshelf $bookshelf
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Collection|static[]
 | 
			
		||||
     */
 | 
			
		||||
    public function getBookshelfChildren(Bookshelf $bookshelf)
 | 
			
		||||
| 
						 | 
				
			
			@ -355,7 +317,7 @@ class EntityRepo
 | 
			
		|||
     * Get all child objects of a book.
 | 
			
		||||
     * Returns a sorted collection of Pages and Chapters.
 | 
			
		||||
     * Loads the book slug onto child elements to prevent access database access for getting the slug.
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param \BookStack\Entities\Book $book
 | 
			
		||||
     * @param bool $filterDrafts
 | 
			
		||||
     * @param bool $renderPages
 | 
			
		||||
     * @return mixed
 | 
			
		||||
| 
						 | 
				
			
			@ -368,14 +330,14 @@ class EntityRepo
 | 
			
		|||
        $tree = [];
 | 
			
		||||
 | 
			
		||||
        foreach ($q as $index => $rawEntity) {
 | 
			
		||||
            if ($rawEntity->entity_type === 'BookStack\\Page') {
 | 
			
		||||
                $entities[$index] = $this->page->newFromBuilder($rawEntity);
 | 
			
		||||
            if ($rawEntity->entity_type ===  $this->entityProvider->page->getMorphClass()) {
 | 
			
		||||
                $entities[$index] = $this->entityProvider->page->newFromBuilder($rawEntity);
 | 
			
		||||
                if ($renderPages) {
 | 
			
		||||
                    $entities[$index]->html = $rawEntity->html;
 | 
			
		||||
                    $entities[$index]->html = $this->renderPage($entities[$index]);
 | 
			
		||||
                };
 | 
			
		||||
            } else if ($rawEntity->entity_type === 'BookStack\\Chapter') {
 | 
			
		||||
                $entities[$index] = $this->chapter->newFromBuilder($rawEntity);
 | 
			
		||||
            } else if ($rawEntity->entity_type === $this->entityProvider->chapter->getMorphClass()) {
 | 
			
		||||
                $entities[$index] = $this->entityProvider->chapter->newFromBuilder($rawEntity);
 | 
			
		||||
                $key = $entities[$index]->entity_type . ':' . $entities[$index]->id;
 | 
			
		||||
                $parents[$key] = $entities[$index];
 | 
			
		||||
                $parents[$key]->setAttribute('pages', collect());
 | 
			
		||||
| 
						 | 
				
			
			@ -390,7 +352,7 @@ class EntityRepo
 | 
			
		|||
            if ($entity->chapter_id === 0 || $entity->chapter_id === '0') {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            $parentKey = 'BookStack\\Chapter:' . $entity->chapter_id;
 | 
			
		||||
            $parentKey = $this->entityProvider->chapter->getMorphClass() . ':' . $entity->chapter_id;
 | 
			
		||||
            if (!isset($parents[$parentKey])) {
 | 
			
		||||
                $tree[] = $entity;
 | 
			
		||||
                continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -405,7 +367,7 @@ class EntityRepo
 | 
			
		|||
    /**
 | 
			
		||||
     * Get the child items for a chapter sorted by priority but
 | 
			
		||||
     * with draft items floated to the top.
 | 
			
		||||
     * @param Chapter $chapter
 | 
			
		||||
     * @param \BookStack\Entities\Chapter $chapter
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Collection|static[]
 | 
			
		||||
     */
 | 
			
		||||
    public function getChapterChildren(Chapter $chapter)
 | 
			
		||||
| 
						 | 
				
			
			@ -417,7 +379,7 @@ class EntityRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the next sequential priority for a new child element in the given book.
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param \BookStack\Entities\Book $book
 | 
			
		||||
     * @return int
 | 
			
		||||
     */
 | 
			
		||||
    public function getNewBookPriority(Book $book)
 | 
			
		||||
| 
						 | 
				
			
			@ -428,7 +390,7 @@ class EntityRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a new priority for a new page to be added to the given chapter.
 | 
			
		||||
     * @param Chapter $chapter
 | 
			
		||||
     * @param \BookStack\Entities\Chapter $chapter
 | 
			
		||||
     * @return int
 | 
			
		||||
     */
 | 
			
		||||
    public function getNewChapterPriority(Chapter $chapter)
 | 
			
		||||
| 
						 | 
				
			
			@ -464,7 +426,7 @@ class EntityRepo
 | 
			
		|||
     */
 | 
			
		||||
    protected function slugExists($type, $slug, $currentId = false, $bookId = false)
 | 
			
		||||
    {
 | 
			
		||||
        $query = $this->getEntity($type)->where('slug', '=', $slug);
 | 
			
		||||
        $query = $this->entityProvider->get($type)->where('slug', '=', $slug);
 | 
			
		||||
        if (strtolower($type) === 'page' || strtolower($type) === 'chapter') {
 | 
			
		||||
            $query = $query->where('book_id', '=', $bookId);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -476,10 +438,11 @@ class EntityRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates entity restrictions from a request
 | 
			
		||||
     * @param $request
 | 
			
		||||
     * @param Entity $entity
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @param \BookStack\Entities\Entity $entity
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    public function updateEntityPermissionsFromRequest($request, Entity $entity)
 | 
			
		||||
    public function updateEntityPermissionsFromRequest(Request $request, Entity $entity)
 | 
			
		||||
    {
 | 
			
		||||
        $entity->restricted = $request->get('restricted', '') === 'true';
 | 
			
		||||
        $entity->permissions()->delete();
 | 
			
		||||
| 
						 | 
				
			
			@ -507,12 +470,12 @@ class EntityRepo
 | 
			
		|||
     * @param string $type
 | 
			
		||||
     * @param array $input
 | 
			
		||||
     * @param bool|Book $book
 | 
			
		||||
     * @return Entity
 | 
			
		||||
     * @return \BookStack\Entities\Entity
 | 
			
		||||
     */
 | 
			
		||||
    public function createFromInput($type, $input = [], $book = false)
 | 
			
		||||
    {
 | 
			
		||||
        $isChapter = strtolower($type) === 'chapter';
 | 
			
		||||
        $entityModel = $this->getEntity($type)->newInstance($input);
 | 
			
		||||
        $entityModel = $this->entityProvider->get($type)->newInstance($input);
 | 
			
		||||
        $entityModel->slug = $this->findSuitableSlug($type, $entityModel->name, false, $isChapter ? $book->id : false);
 | 
			
		||||
        $entityModel->created_by = user()->id;
 | 
			
		||||
        $entityModel->updated_by = user()->id;
 | 
			
		||||
| 
						 | 
				
			
			@ -531,9 +494,9 @@ class EntityRepo
 | 
			
		|||
     * Update entity details from request input.
 | 
			
		||||
     * Used for books and chapters
 | 
			
		||||
     * @param string $type
 | 
			
		||||
     * @param Entity $entityModel
 | 
			
		||||
     * @param \BookStack\Entities\Entity $entityModel
 | 
			
		||||
     * @param array $input
 | 
			
		||||
     * @return Entity
 | 
			
		||||
     * @return \BookStack\Entities\Entity
 | 
			
		||||
     */
 | 
			
		||||
    public function updateFromInput($type, Entity $entityModel, $input = [])
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -556,7 +519,7 @@ class EntityRepo
 | 
			
		|||
    /**
 | 
			
		||||
     * Sync the books assigned to a shelf from a comma-separated list
 | 
			
		||||
     * of book IDs.
 | 
			
		||||
     * @param Bookshelf $shelf
 | 
			
		||||
     * @param \BookStack\Entities\Bookshelf $shelf
 | 
			
		||||
     * @param string $books
 | 
			
		||||
     */
 | 
			
		||||
    public function updateShelfBooks(Bookshelf $shelf, string $books)
 | 
			
		||||
| 
						 | 
				
			
			@ -581,7 +544,7 @@ class EntityRepo
 | 
			
		|||
     * @param integer $newBookId
 | 
			
		||||
     * @param Entity $entity
 | 
			
		||||
     * @param bool $rebuildPermissions
 | 
			
		||||
     * @return Entity
 | 
			
		||||
     * @return \BookStack\Entities\Entity
 | 
			
		||||
     */
 | 
			
		||||
    public function changeBook($type, $newBookId, Entity $entity, $rebuildPermissions = false)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -635,191 +598,6 @@ class EntityRepo
 | 
			
		|||
        return $slug;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a new draft page instance.
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param Chapter|bool $chapter
 | 
			
		||||
     * @return Page
 | 
			
		||||
     */
 | 
			
		||||
    public function getDraftPage(Book $book, $chapter = false)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->page->newInstance();
 | 
			
		||||
        $page->name = trans('entities.pages_initial_name');
 | 
			
		||||
        $page->created_by = user()->id;
 | 
			
		||||
        $page->updated_by = user()->id;
 | 
			
		||||
        $page->draft = true;
 | 
			
		||||
 | 
			
		||||
        if ($chapter) {
 | 
			
		||||
            $page->chapter_id = $chapter->id;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $book->pages()->save($page);
 | 
			
		||||
        $page = $this->page->find($page->id);
 | 
			
		||||
        $this->permissionService->buildJointPermissionsForEntity($page);
 | 
			
		||||
        return $page;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Publish a draft page to make it a normal page.
 | 
			
		||||
     * Sets the slug and updates the content.
 | 
			
		||||
     * @param Page $draftPage
 | 
			
		||||
     * @param array $input
 | 
			
		||||
     * @return Page
 | 
			
		||||
     */
 | 
			
		||||
    public function publishPageDraft(Page $draftPage, array $input)
 | 
			
		||||
    {
 | 
			
		||||
        $draftPage->fill($input);
 | 
			
		||||
 | 
			
		||||
        // Save page tags if present
 | 
			
		||||
        if (isset($input['tags'])) {
 | 
			
		||||
            $this->tagRepo->saveTagsToEntity($draftPage, $input['tags']);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $draftPage->slug = $this->findSuitableSlug('page', $draftPage->name, false, $draftPage->book->id);
 | 
			
		||||
        $draftPage->html = $this->formatHtml($input['html']);
 | 
			
		||||
        $draftPage->text = $this->pageToPlainText($draftPage);
 | 
			
		||||
        $draftPage->draft = false;
 | 
			
		||||
        $draftPage->revision_count = 1;
 | 
			
		||||
 | 
			
		||||
        $draftPage->save();
 | 
			
		||||
        $this->savePageRevision($draftPage, trans('entities.pages_initial_revision'));
 | 
			
		||||
        $this->searchService->indexEntity($draftPage);
 | 
			
		||||
        return $draftPage;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a copy of a page in a new location with a new name.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param Entity $newParent
 | 
			
		||||
     * @param string $newName
 | 
			
		||||
     * @return Page
 | 
			
		||||
     */
 | 
			
		||||
    public function copyPage(Page $page, Entity $newParent, $newName = '')
 | 
			
		||||
    {
 | 
			
		||||
        $newBook = $newParent->isA('book') ? $newParent : $newParent->book;
 | 
			
		||||
        $newChapter = $newParent->isA('chapter') ? $newParent : null;
 | 
			
		||||
        $copyPage = $this->getDraftPage($newBook, $newChapter);
 | 
			
		||||
        $pageData = $page->getAttributes();
 | 
			
		||||
 | 
			
		||||
        // Update name
 | 
			
		||||
        if (!empty($newName)) {
 | 
			
		||||
            $pageData['name'] = $newName;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Copy tags from previous page if set
 | 
			
		||||
        if ($page->tags) {
 | 
			
		||||
            $pageData['tags'] = [];
 | 
			
		||||
            foreach ($page->tags as $tag) {
 | 
			
		||||
                $pageData['tags'][] = ['name' => $tag->name, 'value' => $tag->value];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set priority
 | 
			
		||||
        if ($newParent->isA('chapter')) {
 | 
			
		||||
            $pageData['priority'] = $this->getNewChapterPriority($newParent);
 | 
			
		||||
        } else {
 | 
			
		||||
            $pageData['priority'] = $this->getNewBookPriority($newParent);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->publishPageDraft($copyPage, $pageData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Saves a page revision into the system.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param null|string $summary
 | 
			
		||||
     * @return PageRevision
 | 
			
		||||
     */
 | 
			
		||||
    public function savePageRevision(Page $page, $summary = null)
 | 
			
		||||
    {
 | 
			
		||||
        $revision = $this->pageRevision->newInstance($page->toArray());
 | 
			
		||||
        if (setting('app-editor') !== 'markdown') {
 | 
			
		||||
            $revision->markdown = '';
 | 
			
		||||
        }
 | 
			
		||||
        $revision->page_id = $page->id;
 | 
			
		||||
        $revision->slug = $page->slug;
 | 
			
		||||
        $revision->book_slug = $page->book->slug;
 | 
			
		||||
        $revision->created_by = user()->id;
 | 
			
		||||
        $revision->created_at = $page->updated_at;
 | 
			
		||||
        $revision->type = 'version';
 | 
			
		||||
        $revision->summary = $summary;
 | 
			
		||||
        $revision->revision_number = $page->revision_count;
 | 
			
		||||
        $revision->save();
 | 
			
		||||
 | 
			
		||||
        $revisionLimit = config('app.revision_limit');
 | 
			
		||||
        if ($revisionLimit !== false) {
 | 
			
		||||
            $revisionsToDelete = $this->pageRevision->where('page_id', '=', $page->id)
 | 
			
		||||
                ->orderBy('created_at', 'desc')->skip(intval($revisionLimit))->take(10)->get(['id']);
 | 
			
		||||
            if ($revisionsToDelete->count() > 0) {
 | 
			
		||||
                $this->pageRevision->whereIn('id', $revisionsToDelete->pluck('id'))->delete();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $revision;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Formats a page's html to be tagged correctly
 | 
			
		||||
     * within the system.
 | 
			
		||||
     * @param string $htmlText
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    protected function formatHtml($htmlText)
 | 
			
		||||
    {
 | 
			
		||||
        if ($htmlText == '') {
 | 
			
		||||
            return $htmlText;
 | 
			
		||||
        }
 | 
			
		||||
        libxml_use_internal_errors(true);
 | 
			
		||||
        $doc = new DOMDocument();
 | 
			
		||||
        $doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8'));
 | 
			
		||||
 | 
			
		||||
        $container = $doc->documentElement;
 | 
			
		||||
        $body = $container->childNodes->item(0);
 | 
			
		||||
        $childNodes = $body->childNodes;
 | 
			
		||||
 | 
			
		||||
        // Ensure no duplicate ids are used
 | 
			
		||||
        $idArray = [];
 | 
			
		||||
 | 
			
		||||
        foreach ($childNodes as $index => $childNode) {
 | 
			
		||||
            /** @var \DOMElement $childNode */
 | 
			
		||||
            if (get_class($childNode) !== 'DOMElement') {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Overwrite id if not a BookStack custom id
 | 
			
		||||
            if ($childNode->hasAttribute('id')) {
 | 
			
		||||
                $id = $childNode->getAttribute('id');
 | 
			
		||||
                if (strpos($id, 'bkmrk') === 0 && array_search($id, $idArray) === false) {
 | 
			
		||||
                    $idArray[] = $id;
 | 
			
		||||
                    continue;
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Create an unique id for the element
 | 
			
		||||
            // Uses the content as a basis to ensure output is the same every time
 | 
			
		||||
            // the same content is passed through.
 | 
			
		||||
            $contentId = 'bkmrk-' . substr(strtolower(preg_replace('/\s+/', '-', trim($childNode->nodeValue))), 0, 20);
 | 
			
		||||
            $newId = urlencode($contentId);
 | 
			
		||||
            $loopIndex = 0;
 | 
			
		||||
            while (in_array($newId, $idArray)) {
 | 
			
		||||
                $newId = urlencode($contentId . '-' . $loopIndex);
 | 
			
		||||
                $loopIndex++;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $childNode->setAttribute('id', $newId);
 | 
			
		||||
            $idArray[] = $newId;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Generate inner html as a string
 | 
			
		||||
        $html = '';
 | 
			
		||||
        foreach ($childNodes as $childNode) {
 | 
			
		||||
            $html .= $doc->saveHTML($childNode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $html;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Render the page for viewing, Parsing and performing features such as page transclusion.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
| 
						 | 
				
			
			@ -900,17 +678,6 @@ class EntityRepo
 | 
			
		|||
        return $html;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the plain text version of a page's content.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function pageToPlainText(Page $page)
 | 
			
		||||
    {
 | 
			
		||||
        $html = $this->renderPage($page);
 | 
			
		||||
        return strip_tags($html);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Search for image usage within page content.
 | 
			
		||||
     * @param $imageString
 | 
			
		||||
| 
						 | 
				
			
			@ -927,281 +694,9 @@ class EntityRepo
 | 
			
		|||
        return count($pages) > 0 ? $pages : false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parse the headers on the page to get a navigation menu
 | 
			
		||||
     * @param String $pageContent
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function getPageNav($pageContent)
 | 
			
		||||
    {
 | 
			
		||||
        if ($pageContent == '') {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
        libxml_use_internal_errors(true);
 | 
			
		||||
        $doc = new DOMDocument();
 | 
			
		||||
        $doc->loadHTML(mb_convert_encoding($pageContent, 'HTML-ENTITIES', 'UTF-8'));
 | 
			
		||||
        $xPath = new DOMXPath($doc);
 | 
			
		||||
        $headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6");
 | 
			
		||||
 | 
			
		||||
        if (is_null($headers)) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $tree = collect([]);
 | 
			
		||||
        foreach ($headers as $header) {
 | 
			
		||||
            $text = $header->nodeValue;
 | 
			
		||||
            $tree->push([
 | 
			
		||||
                'nodeName' => strtolower($header->nodeName),
 | 
			
		||||
                'level' => intval(str_replace('h', '', $header->nodeName)),
 | 
			
		||||
                'link' => '#' . $header->getAttribute('id'),
 | 
			
		||||
                'text' => strlen($text) > 30 ? substr($text, 0, 27) . '...' : $text
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Normalise headers if only smaller headers have been used
 | 
			
		||||
        if (count($tree) > 0) {
 | 
			
		||||
            $minLevel = $tree->pluck('level')->min();
 | 
			
		||||
            $tree = $tree->map(function ($header) use ($minLevel) {
 | 
			
		||||
                $header['level'] -= ($minLevel - 2);
 | 
			
		||||
                return $header;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        return $tree->toArray();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates a page with any fillable data and saves it into the database.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param int $book_id
 | 
			
		||||
     * @param array $input
 | 
			
		||||
     * @return Page
 | 
			
		||||
     */
 | 
			
		||||
    public function updatePage(Page $page, $book_id, $input)
 | 
			
		||||
    {
 | 
			
		||||
        // Hold the old details to compare later
 | 
			
		||||
        $oldHtml = $page->html;
 | 
			
		||||
        $oldName = $page->name;
 | 
			
		||||
 | 
			
		||||
        // Prevent slug being updated if no name change
 | 
			
		||||
        if ($page->name !== $input['name']) {
 | 
			
		||||
            $page->slug = $this->findSuitableSlug('page', $input['name'], $page->id, $book_id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Save page tags if present
 | 
			
		||||
        if (isset($input['tags'])) {
 | 
			
		||||
            $this->tagRepo->saveTagsToEntity($page, $input['tags']);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Update with new details
 | 
			
		||||
        $userId = user()->id;
 | 
			
		||||
        $page->fill($input);
 | 
			
		||||
        $page->html = $this->formatHtml($input['html']);
 | 
			
		||||
        $page->text = $this->pageToPlainText($page);
 | 
			
		||||
        if (setting('app-editor') !== 'markdown') {
 | 
			
		||||
            $page->markdown = '';
 | 
			
		||||
        }
 | 
			
		||||
        $page->updated_by = $userId;
 | 
			
		||||
        $page->revision_count++;
 | 
			
		||||
        $page->save();
 | 
			
		||||
 | 
			
		||||
        // Remove all update drafts for this user & page.
 | 
			
		||||
        $this->userUpdatePageDraftsQuery($page, $userId)->delete();
 | 
			
		||||
 | 
			
		||||
        // Save a revision after updating
 | 
			
		||||
        if ($oldHtml !== $input['html'] || $oldName !== $input['name'] || $input['summary'] !== null) {
 | 
			
		||||
            $this->savePageRevision($page, $input['summary']);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->searchService->indexEntity($page);
 | 
			
		||||
 | 
			
		||||
        return $page;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The base query for getting user update drafts.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param $userId
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    protected function userUpdatePageDraftsQuery(Page $page, $userId)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->pageRevision->where('created_by', '=', $userId)
 | 
			
		||||
            ->where('type', 'update_draft')
 | 
			
		||||
            ->where('page_id', '=', $page->id)
 | 
			
		||||
            ->orderBy('created_at', 'desc');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether a user has a draft version of a particular page or not.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param $userId
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    public function hasUserGotPageDraft(Page $page, $userId)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->userUpdatePageDraftsQuery($page, $userId)->count() > 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the latest updated draft revision for a particular page and user.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param $userId
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function getUserPageDraft(Page $page, $userId)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->userUpdatePageDraftsQuery($page, $userId)->first();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the notification message that informs the user that they are editing a draft page.
 | 
			
		||||
     * @param PageRevision $draft
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getUserPageDraftMessage(PageRevision $draft)
 | 
			
		||||
    {
 | 
			
		||||
        $message = trans('entities.pages_editing_draft_notification', ['timeDiff' => $draft->updated_at->diffForHumans()]);
 | 
			
		||||
        if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) {
 | 
			
		||||
            return $message;
 | 
			
		||||
        }
 | 
			
		||||
        return $message . "\n" . trans('entities.pages_draft_edited_notification');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a page is being actively editing.
 | 
			
		||||
     * Checks for edits since last page updated.
 | 
			
		||||
     * Passing in a minuted range will check for edits
 | 
			
		||||
     * within the last x minutes.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param null $minRange
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    public function isPageEditingActive(Page $page, $minRange = null)
 | 
			
		||||
    {
 | 
			
		||||
        $draftSearch = $this->activePageEditingQuery($page, $minRange);
 | 
			
		||||
        return $draftSearch->count() > 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A query to check for active update drafts on a particular page.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param null $minRange
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    protected function activePageEditingQuery(Page $page, $minRange = null)
 | 
			
		||||
    {
 | 
			
		||||
        $query = $this->pageRevision->where('type', '=', 'update_draft')
 | 
			
		||||
            ->where('page_id', '=', $page->id)
 | 
			
		||||
            ->where('updated_at', '>', $page->updated_at)
 | 
			
		||||
            ->where('created_by', '!=', user()->id)
 | 
			
		||||
            ->with('createdBy');
 | 
			
		||||
 | 
			
		||||
        if ($minRange !== null) {
 | 
			
		||||
            $query = $query->where('updated_at', '>=', Carbon::now()->subMinutes($minRange));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $query;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Restores a revision's content back into a page.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param  int $revisionId
 | 
			
		||||
     * @return Page
 | 
			
		||||
     */
 | 
			
		||||
    public function restorePageRevision(Page $page, Book $book, $revisionId)
 | 
			
		||||
    {
 | 
			
		||||
        $page->revision_count++;
 | 
			
		||||
        $this->savePageRevision($page);
 | 
			
		||||
        $revision = $page->revisions()->where('id', '=', $revisionId)->first();
 | 
			
		||||
        $page->fill($revision->toArray());
 | 
			
		||||
        $page->slug = $this->findSuitableSlug('page', $page->name, $page->id, $book->id);
 | 
			
		||||
        $page->text = $this->pageToPlainText($page);
 | 
			
		||||
        $page->updated_by = user()->id;
 | 
			
		||||
        $page->save();
 | 
			
		||||
        $this->searchService->indexEntity($page);
 | 
			
		||||
        return $page;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Save a page update draft.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param array $data
 | 
			
		||||
     * @return PageRevision|Page
 | 
			
		||||
     */
 | 
			
		||||
    public function updatePageDraft(Page $page, $data = [])
 | 
			
		||||
    {
 | 
			
		||||
        // If the page itself is a draft simply update that
 | 
			
		||||
        if ($page->draft) {
 | 
			
		||||
            $page->fill($data);
 | 
			
		||||
            if (isset($data['html'])) {
 | 
			
		||||
                $page->text = $this->pageToPlainText($page);
 | 
			
		||||
            }
 | 
			
		||||
            $page->save();
 | 
			
		||||
            return $page;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Otherwise save the data to a revision
 | 
			
		||||
        $userId = user()->id;
 | 
			
		||||
        $drafts = $this->userUpdatePageDraftsQuery($page, $userId)->get();
 | 
			
		||||
 | 
			
		||||
        if ($drafts->count() > 0) {
 | 
			
		||||
            $draft = $drafts->first();
 | 
			
		||||
        } else {
 | 
			
		||||
            $draft = $this->pageRevision->newInstance();
 | 
			
		||||
            $draft->page_id = $page->id;
 | 
			
		||||
            $draft->slug = $page->slug;
 | 
			
		||||
            $draft->book_slug = $page->book->slug;
 | 
			
		||||
            $draft->created_by = $userId;
 | 
			
		||||
            $draft->type = 'update_draft';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $draft->fill($data);
 | 
			
		||||
        if (setting('app-editor') !== 'markdown') {
 | 
			
		||||
            $draft->markdown = '';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $draft->save();
 | 
			
		||||
        return $draft;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a notification message concerning the editing activity on a particular page.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param null $minRange
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getPageEditingActiveMessage(Page $page, $minRange = null)
 | 
			
		||||
    {
 | 
			
		||||
        $pageDraftEdits = $this->activePageEditingQuery($page, $minRange)->get();
 | 
			
		||||
 | 
			
		||||
        $userMessage = $pageDraftEdits->count() > 1 ? trans('entities.pages_draft_edit_active.start_a', ['count' => $pageDraftEdits->count()]): trans('entities.pages_draft_edit_active.start_b', ['userName' => $pageDraftEdits->first()->createdBy->name]);
 | 
			
		||||
        $timeMessage = $minRange === null ? trans('entities.pages_draft_edit_active.time_a') : trans('entities.pages_draft_edit_active.time_b', ['minCount'=>$minRange]);
 | 
			
		||||
        return trans('entities.pages_draft_edit_active.message', ['start' => $userMessage, 'time' => $timeMessage]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Change the page's parent to the given entity.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param Entity $parent
 | 
			
		||||
     */
 | 
			
		||||
    public function changePageParent(Page $page, Entity $parent)
 | 
			
		||||
    {
 | 
			
		||||
        $book = $parent->isA('book') ? $parent : $parent->book;
 | 
			
		||||
        $page->chapter_id = $parent->isA('chapter') ? $parent->id : 0;
 | 
			
		||||
        $page->save();
 | 
			
		||||
        if ($page->book->id !== $book->id) {
 | 
			
		||||
            $page = $this->changeBook('page', $book->id, $page);
 | 
			
		||||
        }
 | 
			
		||||
        $page->load('book');
 | 
			
		||||
        $this->permissionService->buildJointPermissionsForEntity($book);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Destroy a bookshelf instance
 | 
			
		||||
     * @param Bookshelf $shelf
 | 
			
		||||
     * @param \BookStack\Entities\Bookshelf $shelf
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    public function destroyBookshelf(Bookshelf $shelf)
 | 
			
		||||
| 
						 | 
				
			
			@ -1212,7 +707,7 @@ class EntityRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Destroy the provided book and all its child entities.
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param \BookStack\Entities\Book $book
 | 
			
		||||
     * @throws NotifyException
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -1230,7 +725,7 @@ class EntityRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Destroy a chapter and its relations.
 | 
			
		||||
     * @param Chapter $chapter
 | 
			
		||||
     * @param \BookStack\Entities\Chapter $chapter
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    public function destroyChapter(Chapter $chapter)
 | 
			
		||||
| 
						 | 
				
			
			@ -1272,7 +767,7 @@ class EntityRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Destroy or handle the common relations connected to an entity.
 | 
			
		||||
     * @param Entity $entity
 | 
			
		||||
     * @param \BookStack\Entities\Entity $entity
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    protected function destroyEntityCommonRelations(Entity $entity)
 | 
			
		||||
| 
						 | 
				
			
			@ -1289,7 +784,7 @@ class EntityRepo
 | 
			
		|||
    /**
 | 
			
		||||
     * Copy the permissions of a bookshelf to all child books.
 | 
			
		||||
     * Returns the number of books that had permissions updated.
 | 
			
		||||
     * @param Bookshelf $bookshelf
 | 
			
		||||
     * @param \BookStack\Entities\Bookshelf $bookshelf
 | 
			
		||||
     * @return int
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,508 @@
 | 
			
		|||
<?php namespace BookStack\Entities\Repos;
 | 
			
		||||
 | 
			
		||||
use BookStack\Entities\Book;
 | 
			
		||||
use BookStack\Entities\Chapter;
 | 
			
		||||
use BookStack\Entities\Entity;
 | 
			
		||||
use BookStack\Entities\Page;
 | 
			
		||||
use BookStack\Entities\PageRevision;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use DOMDocument;
 | 
			
		||||
use DOMXPath;
 | 
			
		||||
 | 
			
		||||
class PageRepo extends EntityRepo
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get page by slug.
 | 
			
		||||
     * @param string $pageSlug
 | 
			
		||||
     * @param string $bookSlug
 | 
			
		||||
     * @return Page
 | 
			
		||||
     * @throws \BookStack\Exceptions\NotFoundException
 | 
			
		||||
     */
 | 
			
		||||
    public function getPageBySlug(string $pageSlug, string $bookSlug)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Search through page revisions and retrieve the last page in the
 | 
			
		||||
     * current book that has a slug equal to the one given.
 | 
			
		||||
     * @param string $pageSlug
 | 
			
		||||
     * @param string $bookSlug
 | 
			
		||||
     * @return null|Page
 | 
			
		||||
     */
 | 
			
		||||
    public function getPageByOldSlug(string $pageSlug, string $bookSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $revision = $this->entityProvider->pageRevision->where('slug', '=', $pageSlug)
 | 
			
		||||
            ->whereHas('page', function ($query) {
 | 
			
		||||
                $this->permissionService->enforceEntityRestrictions('page', $query);
 | 
			
		||||
            })
 | 
			
		||||
            ->where('type', '=', 'version')
 | 
			
		||||
            ->where('book_slug', '=', $bookSlug)
 | 
			
		||||
            ->orderBy('created_at', 'desc')
 | 
			
		||||
            ->with('page')->first();
 | 
			
		||||
        return $revision !== null ? $revision->page : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates a page with any fillable data and saves it into the database.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param int $book_id
 | 
			
		||||
     * @param array $input
 | 
			
		||||
     * @return Page
 | 
			
		||||
     * @throws \Exception
 | 
			
		||||
     */
 | 
			
		||||
    public function updatePage(Page $page, int $book_id, array $input)
 | 
			
		||||
    {
 | 
			
		||||
        // Hold the old details to compare later
 | 
			
		||||
        $oldHtml = $page->html;
 | 
			
		||||
        $oldName = $page->name;
 | 
			
		||||
 | 
			
		||||
        // Prevent slug being updated if no name change
 | 
			
		||||
        if ($page->name !== $input['name']) {
 | 
			
		||||
            $page->slug = $this->findSuitableSlug('page', $input['name'], $page->id, $book_id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Save page tags if present
 | 
			
		||||
        if (isset($input['tags'])) {
 | 
			
		||||
            $this->tagRepo->saveTagsToEntity($page, $input['tags']);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Update with new details
 | 
			
		||||
        $userId = user()->id;
 | 
			
		||||
        $page->fill($input);
 | 
			
		||||
        $page->html = $this->formatHtml($input['html']);
 | 
			
		||||
        $page->text = $this->pageToPlainText($page);
 | 
			
		||||
        if (setting('app-editor') !== 'markdown') {
 | 
			
		||||
            $page->markdown = '';
 | 
			
		||||
        }
 | 
			
		||||
        $page->updated_by = $userId;
 | 
			
		||||
        $page->revision_count++;
 | 
			
		||||
        $page->save();
 | 
			
		||||
 | 
			
		||||
        // Remove all update drafts for this user & page.
 | 
			
		||||
        $this->userUpdatePageDraftsQuery($page, $userId)->delete();
 | 
			
		||||
 | 
			
		||||
        // Save a revision after updating
 | 
			
		||||
        if ($oldHtml !== $input['html'] || $oldName !== $input['name'] || $input['summary'] !== null) {
 | 
			
		||||
            $this->savePageRevision($page, $input['summary']);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->searchService->indexEntity($page);
 | 
			
		||||
 | 
			
		||||
        return $page;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Saves a page revision into the system.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param null|string $summary
 | 
			
		||||
     * @return PageRevision
 | 
			
		||||
     * @throws \Exception
 | 
			
		||||
     */
 | 
			
		||||
    public function savePageRevision(Page $page, string $summary = null)
 | 
			
		||||
    {
 | 
			
		||||
        $revision = $this->entityProvider->pageRevision->newInstance($page->toArray());
 | 
			
		||||
        if (setting('app-editor') !== 'markdown') {
 | 
			
		||||
            $revision->markdown = '';
 | 
			
		||||
        }
 | 
			
		||||
        $revision->page_id = $page->id;
 | 
			
		||||
        $revision->slug = $page->slug;
 | 
			
		||||
        $revision->book_slug = $page->book->slug;
 | 
			
		||||
        $revision->created_by = user()->id;
 | 
			
		||||
        $revision->created_at = $page->updated_at;
 | 
			
		||||
        $revision->type = 'version';
 | 
			
		||||
        $revision->summary = $summary;
 | 
			
		||||
        $revision->revision_number = $page->revision_count;
 | 
			
		||||
        $revision->save();
 | 
			
		||||
 | 
			
		||||
        $revisionLimit = config('app.revision_limit');
 | 
			
		||||
        if ($revisionLimit !== false) {
 | 
			
		||||
            $revisionsToDelete = $this->entityProvider->pageRevision->where('page_id', '=', $page->id)
 | 
			
		||||
                ->orderBy('created_at', 'desc')->skip(intval($revisionLimit))->take(10)->get(['id']);
 | 
			
		||||
            if ($revisionsToDelete->count() > 0) {
 | 
			
		||||
                $this->entityProvider->pageRevision->whereIn('id', $revisionsToDelete->pluck('id'))->delete();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $revision;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Formats a page's html to be tagged correctly
 | 
			
		||||
     * within the system.
 | 
			
		||||
     * @param string $htmlText
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    protected function formatHtml(string $htmlText)
 | 
			
		||||
    {
 | 
			
		||||
        if ($htmlText == '') {
 | 
			
		||||
            return $htmlText;
 | 
			
		||||
        }
 | 
			
		||||
        libxml_use_internal_errors(true);
 | 
			
		||||
        $doc = new DOMDocument();
 | 
			
		||||
        $doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8'));
 | 
			
		||||
 | 
			
		||||
        $container = $doc->documentElement;
 | 
			
		||||
        $body = $container->childNodes->item(0);
 | 
			
		||||
        $childNodes = $body->childNodes;
 | 
			
		||||
 | 
			
		||||
        // Ensure no duplicate ids are used
 | 
			
		||||
        $idArray = [];
 | 
			
		||||
 | 
			
		||||
        foreach ($childNodes as $index => $childNode) {
 | 
			
		||||
            /** @var \DOMElement $childNode */
 | 
			
		||||
            if (get_class($childNode) !== 'DOMElement') {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Overwrite id if not a BookStack custom id
 | 
			
		||||
            if ($childNode->hasAttribute('id')) {
 | 
			
		||||
                $id = $childNode->getAttribute('id');
 | 
			
		||||
                if (strpos($id, 'bkmrk') === 0 && array_search($id, $idArray) === false) {
 | 
			
		||||
                    $idArray[] = $id;
 | 
			
		||||
                    continue;
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Create an unique id for the element
 | 
			
		||||
            // Uses the content as a basis to ensure output is the same every time
 | 
			
		||||
            // the same content is passed through.
 | 
			
		||||
            $contentId = 'bkmrk-' . substr(strtolower(preg_replace('/\s+/', '-', trim($childNode->nodeValue))), 0, 20);
 | 
			
		||||
            $newId = urlencode($contentId);
 | 
			
		||||
            $loopIndex = 0;
 | 
			
		||||
            while (in_array($newId, $idArray)) {
 | 
			
		||||
                $newId = urlencode($contentId . '-' . $loopIndex);
 | 
			
		||||
                $loopIndex++;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $childNode->setAttribute('id', $newId);
 | 
			
		||||
            $idArray[] = $newId;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Generate inner html as a string
 | 
			
		||||
        $html = '';
 | 
			
		||||
        foreach ($childNodes as $childNode) {
 | 
			
		||||
            $html .= $doc->saveHTML($childNode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $html;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the plain text version of a page's content.
 | 
			
		||||
     * @param \BookStack\Entities\Page $page
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function pageToPlainText(Page $page)
 | 
			
		||||
    {
 | 
			
		||||
        $html = $this->renderPage($page);
 | 
			
		||||
        return strip_tags($html);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a new draft page instance.
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param Chapter|null $chapter
 | 
			
		||||
     * @return \BookStack\Entities\Page
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    public function getDraftPage(Book $book, Chapter $chapter = null)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityProvider->page->newInstance();
 | 
			
		||||
        $page->name = trans('entities.pages_initial_name');
 | 
			
		||||
        $page->created_by = user()->id;
 | 
			
		||||
        $page->updated_by = user()->id;
 | 
			
		||||
        $page->draft = true;
 | 
			
		||||
 | 
			
		||||
        if ($chapter) {
 | 
			
		||||
            $page->chapter_id = $chapter->id;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $book->pages()->save($page);
 | 
			
		||||
        $page = $this->entityProvider->page->find($page->id);
 | 
			
		||||
        $this->permissionService->buildJointPermissionsForEntity($page);
 | 
			
		||||
        return $page;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Save a page update draft.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param array $data
 | 
			
		||||
     * @return PageRevision|Page
 | 
			
		||||
     */
 | 
			
		||||
    public function updatePageDraft(Page $page, array $data = [])
 | 
			
		||||
    {
 | 
			
		||||
        // If the page itself is a draft simply update that
 | 
			
		||||
        if ($page->draft) {
 | 
			
		||||
            $page->fill($data);
 | 
			
		||||
            if (isset($data['html'])) {
 | 
			
		||||
                $page->text = $this->pageToPlainText($page);
 | 
			
		||||
            }
 | 
			
		||||
            $page->save();
 | 
			
		||||
            return $page;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Otherwise save the data to a revision
 | 
			
		||||
        $userId = user()->id;
 | 
			
		||||
        $drafts = $this->userUpdatePageDraftsQuery($page, $userId)->get();
 | 
			
		||||
 | 
			
		||||
        if ($drafts->count() > 0) {
 | 
			
		||||
            $draft = $drafts->first();
 | 
			
		||||
        } else {
 | 
			
		||||
            $draft = $this->entityProvider->pageRevision->newInstance();
 | 
			
		||||
            $draft->page_id = $page->id;
 | 
			
		||||
            $draft->slug = $page->slug;
 | 
			
		||||
            $draft->book_slug = $page->book->slug;
 | 
			
		||||
            $draft->created_by = $userId;
 | 
			
		||||
            $draft->type = 'update_draft';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $draft->fill($data);
 | 
			
		||||
        if (setting('app-editor') !== 'markdown') {
 | 
			
		||||
            $draft->markdown = '';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $draft->save();
 | 
			
		||||
        return $draft;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Publish a draft page to make it a normal page.
 | 
			
		||||
     * Sets the slug and updates the content.
 | 
			
		||||
     * @param Page $draftPage
 | 
			
		||||
     * @param array $input
 | 
			
		||||
     * @return Page
 | 
			
		||||
     * @throws \Exception
 | 
			
		||||
     */
 | 
			
		||||
    public function publishPageDraft(Page $draftPage, array $input)
 | 
			
		||||
    {
 | 
			
		||||
        $draftPage->fill($input);
 | 
			
		||||
 | 
			
		||||
        // Save page tags if present
 | 
			
		||||
        if (isset($input['tags'])) {
 | 
			
		||||
            $this->tagRepo->saveTagsToEntity($draftPage, $input['tags']);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $draftPage->slug = $this->findSuitableSlug('page', $draftPage->name, false, $draftPage->book->id);
 | 
			
		||||
        $draftPage->html = $this->formatHtml($input['html']);
 | 
			
		||||
        $draftPage->text = $this->pageToPlainText($draftPage);
 | 
			
		||||
        $draftPage->draft = false;
 | 
			
		||||
        $draftPage->revision_count = 1;
 | 
			
		||||
 | 
			
		||||
        $draftPage->save();
 | 
			
		||||
        $this->savePageRevision($draftPage, trans('entities.pages_initial_revision'));
 | 
			
		||||
        $this->searchService->indexEntity($draftPage);
 | 
			
		||||
        return $draftPage;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The base query for getting user update drafts.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param $userId
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    protected function userUpdatePageDraftsQuery(Page $page, int $userId)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->entityProvider->pageRevision->where('created_by', '=', $userId)
 | 
			
		||||
            ->where('type', 'update_draft')
 | 
			
		||||
            ->where('page_id', '=', $page->id)
 | 
			
		||||
            ->orderBy('created_at', 'desc');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the latest updated draft revision for a particular page and user.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param $userId
 | 
			
		||||
     * @return PageRevision|null
 | 
			
		||||
     */
 | 
			
		||||
    public function getUserPageDraft(Page $page, int $userId)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->userUpdatePageDraftsQuery($page, $userId)->first();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the notification message that informs the user that they are editing a draft page.
 | 
			
		||||
     * @param PageRevision $draft
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getUserPageDraftMessage(PageRevision $draft)
 | 
			
		||||
    {
 | 
			
		||||
        $message = trans('entities.pages_editing_draft_notification', ['timeDiff' => $draft->updated_at->diffForHumans()]);
 | 
			
		||||
        if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) {
 | 
			
		||||
            return $message;
 | 
			
		||||
        }
 | 
			
		||||
        return $message . "\n" . trans('entities.pages_draft_edited_notification');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A query to check for active update drafts on a particular page.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param int $minRange
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    protected function activePageEditingQuery(Page $page, int $minRange = null)
 | 
			
		||||
    {
 | 
			
		||||
        $query = $this->entityProvider->pageRevision->where('type', '=', 'update_draft')
 | 
			
		||||
            ->where('page_id', '=', $page->id)
 | 
			
		||||
            ->where('updated_at', '>', $page->updated_at)
 | 
			
		||||
            ->where('created_by', '!=', user()->id)
 | 
			
		||||
            ->with('createdBy');
 | 
			
		||||
 | 
			
		||||
        if ($minRange !== null) {
 | 
			
		||||
            $query = $query->where('updated_at', '>=', Carbon::now()->subMinutes($minRange));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $query;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a page is being actively editing.
 | 
			
		||||
     * Checks for edits since last page updated.
 | 
			
		||||
     * Passing in a minuted range will check for edits
 | 
			
		||||
     * within the last x minutes.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param int $minRange
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    public function isPageEditingActive(Page $page, int $minRange = null)
 | 
			
		||||
    {
 | 
			
		||||
        $draftSearch = $this->activePageEditingQuery($page, $minRange);
 | 
			
		||||
        return $draftSearch->count() > 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a notification message concerning the editing activity on a particular page.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param int $minRange
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getPageEditingActiveMessage(Page $page, int $minRange = null)
 | 
			
		||||
    {
 | 
			
		||||
        $pageDraftEdits = $this->activePageEditingQuery($page, $minRange)->get();
 | 
			
		||||
 | 
			
		||||
        $userMessage = $pageDraftEdits->count() > 1 ? trans('entities.pages_draft_edit_active.start_a', ['count' => $pageDraftEdits->count()]): trans('entities.pages_draft_edit_active.start_b', ['userName' => $pageDraftEdits->first()->createdBy->name]);
 | 
			
		||||
        $timeMessage = $minRange === null ? trans('entities.pages_draft_edit_active.time_a') : trans('entities.pages_draft_edit_active.time_b', ['minCount'=>$minRange]);
 | 
			
		||||
        return trans('entities.pages_draft_edit_active.message', ['start' => $userMessage, 'time' => $timeMessage]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parse the headers on the page to get a navigation menu
 | 
			
		||||
     * @param string $pageContent
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function getPageNav(string $pageContent)
 | 
			
		||||
    {
 | 
			
		||||
        if ($pageContent == '') {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
        libxml_use_internal_errors(true);
 | 
			
		||||
        $doc = new DOMDocument();
 | 
			
		||||
        $doc->loadHTML(mb_convert_encoding($pageContent, 'HTML-ENTITIES', 'UTF-8'));
 | 
			
		||||
        $xPath = new DOMXPath($doc);
 | 
			
		||||
        $headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6");
 | 
			
		||||
 | 
			
		||||
        if (is_null($headers)) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $tree = collect([]);
 | 
			
		||||
        foreach ($headers as $header) {
 | 
			
		||||
            $text = $header->nodeValue;
 | 
			
		||||
            $tree->push([
 | 
			
		||||
                'nodeName' => strtolower($header->nodeName),
 | 
			
		||||
                'level' => intval(str_replace('h', '', $header->nodeName)),
 | 
			
		||||
                'link' => '#' . $header->getAttribute('id'),
 | 
			
		||||
                'text' => strlen($text) > 30 ? substr($text, 0, 27) . '...' : $text
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Normalise headers if only smaller headers have been used
 | 
			
		||||
        if (count($tree) > 0) {
 | 
			
		||||
            $minLevel = $tree->pluck('level')->min();
 | 
			
		||||
            $tree = $tree->map(function ($header) use ($minLevel) {
 | 
			
		||||
                $header['level'] -= ($minLevel - 2);
 | 
			
		||||
                return $header;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        return $tree->toArray();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Restores a revision's content back into a page.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param  int $revisionId
 | 
			
		||||
     * @return Page
 | 
			
		||||
     * @throws \Exception
 | 
			
		||||
     */
 | 
			
		||||
    public function restorePageRevision(Page $page, Book $book, int $revisionId)
 | 
			
		||||
    {
 | 
			
		||||
        $page->revision_count++;
 | 
			
		||||
        $this->savePageRevision($page);
 | 
			
		||||
        $revision = $page->revisions()->where('id', '=', $revisionId)->first();
 | 
			
		||||
        $page->fill($revision->toArray());
 | 
			
		||||
        $page->slug = $this->findSuitableSlug('page', $page->name, $page->id, $book->id);
 | 
			
		||||
        $page->text = $this->pageToPlainText($page);
 | 
			
		||||
        $page->updated_by = user()->id;
 | 
			
		||||
        $page->save();
 | 
			
		||||
        $this->searchService->indexEntity($page);
 | 
			
		||||
        return $page;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Change the page's parent to the given entity.
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param Entity $parent
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    public function changePageParent(Page $page, Entity $parent)
 | 
			
		||||
    {
 | 
			
		||||
        $book = $parent->isA('book') ? $parent : $parent->book;
 | 
			
		||||
        $page->chapter_id = $parent->isA('chapter') ? $parent->id : 0;
 | 
			
		||||
        $page->save();
 | 
			
		||||
        if ($page->book->id !== $book->id) {
 | 
			
		||||
            $page = $this->changeBook('page', $book->id, $page);
 | 
			
		||||
        }
 | 
			
		||||
        $page->load('book');
 | 
			
		||||
        $this->permissionService->buildJointPermissionsForEntity($book);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a copy of a page in a new location with a new name.
 | 
			
		||||
     * @param \BookStack\Entities\Page $page
 | 
			
		||||
     * @param \BookStack\Entities\Entity $newParent
 | 
			
		||||
     * @param string $newName
 | 
			
		||||
     * @return \BookStack\Entities\Page
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     */
 | 
			
		||||
    public function copyPage(Page $page, Entity $newParent, string $newName = '')
 | 
			
		||||
    {
 | 
			
		||||
        $newBook = $newParent->isA('book') ? $newParent : $newParent->book;
 | 
			
		||||
        $newChapter = $newParent->isA('chapter') ? $newParent : null;
 | 
			
		||||
        $copyPage = $this->getDraftPage($newBook, $newChapter);
 | 
			
		||||
        $pageData = $page->getAttributes();
 | 
			
		||||
 | 
			
		||||
        // Update name
 | 
			
		||||
        if (!empty($newName)) {
 | 
			
		||||
            $pageData['name'] = $newName;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Copy tags from previous page if set
 | 
			
		||||
        if ($page->tags) {
 | 
			
		||||
            $pageData['tags'] = [];
 | 
			
		||||
            foreach ($page->tags as $tag) {
 | 
			
		||||
                $pageData['tags'][] = ['name' => $tag->name, 'value' => $tag->value];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set priority
 | 
			
		||||
        if ($newParent->isA('chapter')) {
 | 
			
		||||
            $pageData['priority'] = $this->getNewChapterPriority($newParent);
 | 
			
		||||
        } else {
 | 
			
		||||
            $pageData['priority'] = $this->getNewBookPriority($newParent);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->publishPageDraft($copyPage, $pageData);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,30 +1,34 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Entities;
 | 
			
		||||
 | 
			
		||||
use BookStack\Book;
 | 
			
		||||
use BookStack\Bookshelf;
 | 
			
		||||
use BookStack\Chapter;
 | 
			
		||||
use BookStack\Entity;
 | 
			
		||||
use BookStack\Page;
 | 
			
		||||
use BookStack\SearchTerm;
 | 
			
		||||
use BookStack\Auth\Permissions\PermissionService;
 | 
			
		||||
use Illuminate\Database\Connection;
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
 | 
			
		||||
use Illuminate\Database\Query\Builder;
 | 
			
		||||
use Illuminate\Database\Query\JoinClause;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
 | 
			
		||||
class SearchService
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @var SearchTerm
 | 
			
		||||
     */
 | 
			
		||||
    protected $searchTerm;
 | 
			
		||||
    protected $bookshelf;
 | 
			
		||||
    protected $book;
 | 
			
		||||
    protected $chapter;
 | 
			
		||||
    protected $page;
 | 
			
		||||
    protected $db;
 | 
			
		||||
    protected $permissionService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Entity[]
 | 
			
		||||
     * @var EntityProvider
 | 
			
		||||
     */
 | 
			
		||||
    protected $entities;
 | 
			
		||||
    protected $entityProvider;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Connection
 | 
			
		||||
     */
 | 
			
		||||
    protected $db;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var PermissionService
 | 
			
		||||
     */
 | 
			
		||||
    protected $permissionService;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Acceptable operators to be used in a query
 | 
			
		||||
| 
						 | 
				
			
			@ -35,27 +39,15 @@ class SearchService
 | 
			
		|||
    /**
 | 
			
		||||
     * SearchService constructor.
 | 
			
		||||
     * @param SearchTerm $searchTerm
 | 
			
		||||
     * @param Bookshelf $bookshelf
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param Chapter $chapter
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param EntityProvider $entityProvider
 | 
			
		||||
     * @param Connection $db
 | 
			
		||||
     * @param PermissionService $permissionService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(SearchTerm $searchTerm, Bookshelf $bookshelf, Book $book, Chapter $chapter, Page $page, Connection $db, PermissionService $permissionService)
 | 
			
		||||
    public function __construct(SearchTerm $searchTerm, EntityProvider $entityProvider, Connection $db, PermissionService $permissionService)
 | 
			
		||||
    {
 | 
			
		||||
        $this->searchTerm = $searchTerm;
 | 
			
		||||
        $this->bookshelf = $bookshelf;
 | 
			
		||||
        $this->book = $book;
 | 
			
		||||
        $this->chapter = $chapter;
 | 
			
		||||
        $this->page = $page;
 | 
			
		||||
        $this->entityProvider = $entityProvider;
 | 
			
		||||
        $this->db = $db;
 | 
			
		||||
        $this->entities = [
 | 
			
		||||
            'bookshelf' => $this->bookshelf,
 | 
			
		||||
            'page' => $this->page,
 | 
			
		||||
            'chapter' => $this->chapter,
 | 
			
		||||
            'book' => $this->book
 | 
			
		||||
        ];
 | 
			
		||||
        $this->permissionService = $permissionService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +72,7 @@ class SearchService
 | 
			
		|||
    public function searchEntities($searchString, $entityType = 'all', $page = 1, $count = 20, $action = 'view')
 | 
			
		||||
    {
 | 
			
		||||
        $terms = $this->parseSearchString($searchString);
 | 
			
		||||
        $entityTypes = array_keys($this->entities);
 | 
			
		||||
        $entityTypes = array_keys($this->entityProvider->all());
 | 
			
		||||
        $entityTypesToSearch = $entityTypes;
 | 
			
		||||
 | 
			
		||||
        if ($entityType !== 'all') {
 | 
			
		||||
| 
						 | 
				
			
			@ -177,17 +169,17 @@ class SearchService
 | 
			
		|||
     * @param array $terms
 | 
			
		||||
     * @param string $entityType
 | 
			
		||||
     * @param string $action
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Builder
 | 
			
		||||
     * @return EloquentBuilder
 | 
			
		||||
     */
 | 
			
		||||
    protected function buildEntitySearchQuery($terms, $entityType = 'page', $action = 'view')
 | 
			
		||||
    {
 | 
			
		||||
        $entity = $this->getEntity($entityType);
 | 
			
		||||
        $entity = $this->entityProvider->get($entityType);
 | 
			
		||||
        $entitySelect = $entity->newQuery();
 | 
			
		||||
 | 
			
		||||
        // Handle normal search terms
 | 
			
		||||
        if (count($terms['search']) > 0) {
 | 
			
		||||
            $subQuery = $this->db->table('search_terms')->select('entity_id', 'entity_type', \DB::raw('SUM(score) as score'));
 | 
			
		||||
            $subQuery->where('entity_type', '=', 'BookStack\\' . ucfirst($entityType));
 | 
			
		||||
            $subQuery->where('entity_type', '=', $entity->getMorphClass());
 | 
			
		||||
            $subQuery->where(function (Builder $query) use ($terms) {
 | 
			
		||||
                foreach ($terms['search'] as $inputTerm) {
 | 
			
		||||
                    $query->orWhere('term', 'like', $inputTerm .'%');
 | 
			
		||||
| 
						 | 
				
			
			@ -201,9 +193,9 @@ class SearchService
 | 
			
		|||
 | 
			
		||||
        // Handle exact term matching
 | 
			
		||||
        if (count($terms['exact']) > 0) {
 | 
			
		||||
            $entitySelect->where(function (\Illuminate\Database\Eloquent\Builder $query) use ($terms, $entity) {
 | 
			
		||||
            $entitySelect->where(function (EloquentBuilder $query) use ($terms, $entity) {
 | 
			
		||||
                foreach ($terms['exact'] as $inputTerm) {
 | 
			
		||||
                    $query->where(function (\Illuminate\Database\Eloquent\Builder $query) use ($inputTerm, $entity) {
 | 
			
		||||
                    $query->where(function (EloquentBuilder $query) use ($inputTerm, $entity) {
 | 
			
		||||
                        $query->where('name', 'like', '%'.$inputTerm .'%')
 | 
			
		||||
                            ->orWhere($entity->textField, 'like', '%'.$inputTerm .'%');
 | 
			
		||||
                    });
 | 
			
		||||
| 
						 | 
				
			
			@ -291,14 +283,14 @@ class SearchService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Apply a tag search term onto a entity query.
 | 
			
		||||
     * @param \Illuminate\Database\Eloquent\Builder $query
 | 
			
		||||
     * @param EloquentBuilder $query
 | 
			
		||||
     * @param string $tagTerm
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    protected function applyTagSearch(\Illuminate\Database\Eloquent\Builder $query, $tagTerm)
 | 
			
		||||
    protected function applyTagSearch(EloquentBuilder $query, $tagTerm)
 | 
			
		||||
    {
 | 
			
		||||
        preg_match("/^(.*?)((".$this->getRegexEscapedOperators().")(.*?))?$/", $tagTerm, $tagSplit);
 | 
			
		||||
        $query->whereHas('tags', function (\Illuminate\Database\Eloquent\Builder $query) use ($tagSplit) {
 | 
			
		||||
        $query->whereHas('tags', function (EloquentBuilder $query) use ($tagSplit) {
 | 
			
		||||
            $tagName = $tagSplit[1];
 | 
			
		||||
            $tagOperator = count($tagSplit) > 2 ? $tagSplit[3] : '';
 | 
			
		||||
            $tagValue = count($tagSplit) > 3 ? $tagSplit[4] : '';
 | 
			
		||||
| 
						 | 
				
			
			@ -323,16 +315,6 @@ class SearchService
 | 
			
		|||
        return $query;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get an entity instance via type.
 | 
			
		||||
     * @param $type
 | 
			
		||||
     * @return Entity
 | 
			
		||||
     */
 | 
			
		||||
    protected function getEntity($type)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->entities[strtolower($type)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Index the given entity.
 | 
			
		||||
     * @param Entity $entity
 | 
			
		||||
| 
						 | 
				
			
			@ -352,7 +334,7 @@ class SearchService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Index multiple Entities at once
 | 
			
		||||
     * @param Entity[] $entities
 | 
			
		||||
     * @param \BookStack\Entities\Entity[] $entities
 | 
			
		||||
     */
 | 
			
		||||
    protected function indexEntities($entities)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -380,7 +362,7 @@ class SearchService
 | 
			
		|||
    {
 | 
			
		||||
        $this->searchTerm->truncate();
 | 
			
		||||
 | 
			
		||||
        foreach ($this->entities as $entityModel) {
 | 
			
		||||
        foreach ($this->entityProvider->all() as $entityModel) {
 | 
			
		||||
            $selectFields = ['id', 'name', $entityModel->textField];
 | 
			
		||||
            $entityModel->newQuery()->select($selectFields)->chunk(1000, function ($entities) {
 | 
			
		||||
                $this->indexEntities($entities);
 | 
			
		||||
| 
						 | 
				
			
			@ -434,7 +416,7 @@ class SearchService
 | 
			
		|||
     * Custom entity search filters
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    protected function filterUpdatedAfter(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterUpdatedAfter(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $date = date_create($input);
 | 
			
		||||
| 
						 | 
				
			
			@ -444,7 +426,7 @@ class SearchService
 | 
			
		|||
        $query->where('updated_at', '>=', $date);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function filterUpdatedBefore(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterUpdatedBefore(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $date = date_create($input);
 | 
			
		||||
| 
						 | 
				
			
			@ -454,7 +436,7 @@ class SearchService
 | 
			
		|||
        $query->where('updated_at', '<', $date);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function filterCreatedAfter(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterCreatedAfter(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $date = date_create($input);
 | 
			
		||||
| 
						 | 
				
			
			@ -464,7 +446,7 @@ class SearchService
 | 
			
		|||
        $query->where('created_at', '>=', $date);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function filterCreatedBefore(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterCreatedBefore(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $date = date_create($input);
 | 
			
		||||
| 
						 | 
				
			
			@ -474,7 +456,7 @@ class SearchService
 | 
			
		|||
        $query->where('created_at', '<', $date);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function filterCreatedBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterCreatedBy(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        if (!is_numeric($input) && $input !== 'me') {
 | 
			
		||||
            return;
 | 
			
		||||
| 
						 | 
				
			
			@ -485,7 +467,7 @@ class SearchService
 | 
			
		|||
        $query->where('created_by', '=', $input);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function filterUpdatedBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterUpdatedBy(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        if (!is_numeric($input) && $input !== 'me') {
 | 
			
		||||
            return;
 | 
			
		||||
| 
						 | 
				
			
			@ -496,41 +478,41 @@ class SearchService
 | 
			
		|||
        $query->where('updated_by', '=', $input);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function filterInName(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterInName(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        $query->where('name', 'like', '%' .$input. '%');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function filterInTitle(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterInTitle(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        $this->filterInName($query, $model, $input);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function filterInBody(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterInBody(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        $query->where($model->textField, 'like', '%' .$input. '%');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function filterIsRestricted(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterIsRestricted(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        $query->where('restricted', '=', true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function filterViewedByMe(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterViewedByMe(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        $query->whereHas('views', function ($query) {
 | 
			
		||||
            $query->where('user_id', '=', user()->id);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function filterNotViewedByMe(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterNotViewedByMe(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        $query->whereDoesntHave('views', function ($query) {
 | 
			
		||||
            $query->where('user_id', '=', user()->id);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function filterSortBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
 | 
			
		||||
    protected function filterSortBy(EloquentBuilder $query, Entity $model, $input)
 | 
			
		||||
    {
 | 
			
		||||
        $functionName = camel_case('sort_by_' . $input);
 | 
			
		||||
        if (method_exists($this, $functionName)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -543,7 +525,7 @@ class SearchService
 | 
			
		|||
     * Sorting filter options
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    protected function sortByLastCommented(\Illuminate\Database\Eloquent\Builder $query, Entity $model)
 | 
			
		||||
    protected function sortByLastCommented(EloquentBuilder $query, Entity $model)
 | 
			
		||||
    {
 | 
			
		||||
        $commentsTable = $this->db->getTablePrefix() . 'comments';
 | 
			
		||||
        $morphClass = str_replace('\\', '\\\\', $model->getMorphClass());
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Entities;
 | 
			
		||||
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
 | 
			
		||||
class SearchTerm extends Model
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -3,12 +3,12 @@
 | 
			
		|||
namespace BookStack\Exceptions;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use Illuminate\Auth\AuthenticationException;
 | 
			
		||||
use Illuminate\Validation\ValidationException;
 | 
			
		||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
 | 
			
		||||
use Symfony\Component\HttpKernel\Exception\HttpException;
 | 
			
		||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
 | 
			
		||||
use Illuminate\Auth\Access\AuthorizationException;
 | 
			
		||||
use Illuminate\Auth\AuthenticationException;
 | 
			
		||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
 | 
			
		||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
 | 
			
		||||
use Illuminate\Validation\ValidationException;
 | 
			
		||||
use Symfony\Component\HttpKernel\Exception\HttpException;
 | 
			
		||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 | 
			
		||||
 | 
			
		||||
class Handler extends ExceptionHandler
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
<?php namespace BookStack\Services\Facades;
 | 
			
		||||
<?php namespace BookStack\Facades;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Support\Facades\Facade;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
<?php namespace BookStack\Services\Facades;
 | 
			
		||||
<?php namespace BookStack\Facades;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Support\Facades\Facade;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
<?php namespace BookStack\Services\Facades;
 | 
			
		||||
<?php namespace BookStack\Facades;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Support\Facades\Facade;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
<?php namespace BookStack\Services\Facades;
 | 
			
		||||
<?php namespace BookStack\Facades;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Support\Facades\Facade;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,10 +1,10 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Exceptions\FileUploadException;
 | 
			
		||||
use BookStack\Attachment;
 | 
			
		||||
use BookStack\Exceptions\NotFoundException;
 | 
			
		||||
use BookStack\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Services\AttachmentService;
 | 
			
		||||
use BookStack\Uploads\Attachment;
 | 
			
		||||
use BookStack\Uploads\AttachmentService;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
 | 
			
		||||
class AttachmentController extends Controller
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ class AttachmentController extends Controller
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * AttachmentController constructor.
 | 
			
		||||
     * @param AttachmentService $attachmentService
 | 
			
		||||
     * @param \BookStack\Uploads\AttachmentService $attachmentService
 | 
			
		||||
     * @param Attachment $attachment
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,11 +2,11 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Http\Controllers\Auth;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\Access\LdapService;
 | 
			
		||||
use BookStack\Auth\Access\SocialAuthService;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use BookStack\Exceptions\AuthException;
 | 
			
		||||
use BookStack\Http\Controllers\Controller;
 | 
			
		||||
use BookStack\Repos\UserRepo;
 | 
			
		||||
use BookStack\Services\LdapService;
 | 
			
		||||
use BookStack\Services\SocialAuthService;
 | 
			
		||||
use Illuminate\Contracts\Auth\Authenticatable;
 | 
			
		||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
| 
						 | 
				
			
			@ -43,9 +43,9 @@ class LoginController extends Controller
 | 
			
		|||
    /**
 | 
			
		||||
     * Create a new controller instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param SocialAuthService $socialAuthService
 | 
			
		||||
     * @param \BookStack\Auth\\BookStack\Auth\Access\SocialAuthService $socialAuthService
 | 
			
		||||
     * @param LdapService $ldapService
 | 
			
		||||
     * @param UserRepo $userRepo
 | 
			
		||||
     * @param \BookStack\Auth\UserRepo $userRepo
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(SocialAuthService $socialAuthService, LdapService $ldapService, UserRepo $userRepo)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,21 +2,19 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Http\Controllers\Auth;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\SocialAccount;
 | 
			
		||||
use BookStack\Auth\User;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use BookStack\Exceptions\SocialSignInAccountNotUsed;
 | 
			
		||||
use BookStack\Exceptions\SocialSignInException;
 | 
			
		||||
use BookStack\Exceptions\UserRegistrationException;
 | 
			
		||||
use BookStack\Repos\UserRepo;
 | 
			
		||||
use BookStack\Services\EmailConfirmationService;
 | 
			
		||||
use BookStack\Services\SocialAuthService;
 | 
			
		||||
use BookStack\SocialAccount;
 | 
			
		||||
use BookStack\User;
 | 
			
		||||
use BookStack\Http\Controllers\Controller;
 | 
			
		||||
use Exception;
 | 
			
		||||
use Illuminate\Foundation\Auth\RegistersUsers;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use Validator;
 | 
			
		||||
use BookStack\Http\Controllers\Controller;
 | 
			
		||||
use Illuminate\Foundation\Auth\RegistersUsers;
 | 
			
		||||
use Laravel\Socialite\Contracts\User as SocialUser;
 | 
			
		||||
use Validator;
 | 
			
		||||
 | 
			
		||||
class RegisterController extends Controller
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -48,11 +46,11 @@ class RegisterController extends Controller
 | 
			
		|||
    /**
 | 
			
		||||
     * Create a new controller instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param SocialAuthService $socialAuthService
 | 
			
		||||
     * @param EmailConfirmationService $emailConfirmationService
 | 
			
		||||
     * @param UserRepo $userRepo
 | 
			
		||||
     * @param \BookStack\Auth\Access\SocialAuthService $socialAuthService
 | 
			
		||||
     * @param \BookStack\Auth\EmailConfirmationService $emailConfirmationService
 | 
			
		||||
     * @param \BookStack\Auth\UserRepo $userRepo
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(SocialAuthService $socialAuthService, EmailConfirmationService $emailConfirmationService, UserRepo $userRepo)
 | 
			
		||||
    public function __construct(\BookStack\Auth\Access\SocialAuthService $socialAuthService, \BookStack\Auth\Access\EmailConfirmationService $emailConfirmationService, UserRepo $userRepo)
 | 
			
		||||
    {
 | 
			
		||||
        $this->middleware('guest')->only(['getRegister', 'postRegister', 'socialRegister']);
 | 
			
		||||
        $this->socialAuthService = $socialAuthService;
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +117,7 @@ class RegisterController extends Controller
 | 
			
		|||
    /**
 | 
			
		||||
     * Create a new user instance after a valid registration.
 | 
			
		||||
     * @param  array  $data
 | 
			
		||||
     * @return User
 | 
			
		||||
     * @return \BookStack\Auth\User
 | 
			
		||||
     */
 | 
			
		||||
    protected function create(array $data)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,10 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use Activity;
 | 
			
		||||
use BookStack\Book;
 | 
			
		||||
use BookStack\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Repos\UserRepo;
 | 
			
		||||
use BookStack\Services\ExportService;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use BookStack\Entities\Book;
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Entities\ExportService;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use Views;
 | 
			
		||||
| 
						 | 
				
			
			@ -19,8 +19,8 @@ class BookController extends Controller
 | 
			
		|||
    /**
 | 
			
		||||
     * BookController constructor.
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     * @param UserRepo $userRepo
 | 
			
		||||
     * @param ExportService $exportService
 | 
			
		||||
     * @param \BookStack\Auth\UserRepo $userRepo
 | 
			
		||||
     * @param \BookStack\Entities\ExportService $exportService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(EntityRepo $entityRepo, UserRepo $userRepo, ExportService $exportService)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -204,7 +204,7 @@ class BookController extends Controller
 | 
			
		|||
 | 
			
		||||
        // Get the books involved in the sort
 | 
			
		||||
        $bookIdsInvolved = $bookIdsInvolved->unique()->toArray();
 | 
			
		||||
        $booksInvolved = $this->entityRepo->book->newQuery()->whereIn('id', $bookIdsInvolved)->get();
 | 
			
		||||
        $booksInvolved = $this->entityRepo->getManyById('book', $bookIdsInvolved, false, true);
 | 
			
		||||
        // Throw permission error if invalid ids or inaccessible books given.
 | 
			
		||||
        if (count($bookIdsInvolved) !== count($booksInvolved)) {
 | 
			
		||||
            $this->showPermissionError();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,10 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use Activity;
 | 
			
		||||
use BookStack\Book;
 | 
			
		||||
use BookStack\Bookshelf;
 | 
			
		||||
use BookStack\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Repos\UserRepo;
 | 
			
		||||
use BookStack\Services\ExportService;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use BookStack\Entities\Bookshelf;
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Entities\ExportService;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use Views;
 | 
			
		||||
| 
						 | 
				
			
			@ -19,9 +18,9 @@ class BookshelfController extends Controller
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * BookController constructor.
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     * @param \BookStack\Entities\Repos\EntityRepo $entityRepo
 | 
			
		||||
     * @param UserRepo $userRepo
 | 
			
		||||
     * @param ExportService $exportService
 | 
			
		||||
     * @param \BookStack\Entities\ExportService $exportService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(EntityRepo $entityRepo, UserRepo $userRepo, ExportService $exportService)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use Activity;
 | 
			
		||||
use BookStack\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Repos\UserRepo;
 | 
			
		||||
use BookStack\Services\ExportService;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Entities\ExportService;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use Views;
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ class ChapterController extends Controller
 | 
			
		|||
     * ChapterController constructor.
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     * @param UserRepo $userRepo
 | 
			
		||||
     * @param ExportService $exportService
 | 
			
		||||
     * @param \BookStack\Entities\ExportService $exportService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(EntityRepo $entityRepo, UserRepo $userRepo, ExportService $exportService)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use Activity;
 | 
			
		||||
use BookStack\Repos\CommentRepo;
 | 
			
		||||
use BookStack\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Actions\CommentRepo;
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -13,8 +13,8 @@ class CommentController extends Controller
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * CommentController constructor.
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     * @param CommentRepo $commentRepo
 | 
			
		||||
     * @param \BookStack\Entities\Repos\EntityRepo $entityRepo
 | 
			
		||||
     * @param \BookStack\Actions\CommentRepo $commentRepo
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(EntityRepo $entityRepo, CommentRepo $commentRepo)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,13 +2,13 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\User;
 | 
			
		||||
use BookStack\Ownable;
 | 
			
		||||
use Illuminate\Foundation\Bus\DispatchesJobs;
 | 
			
		||||
use Illuminate\Foundation\Validation\ValidatesRequests;
 | 
			
		||||
use Illuminate\Http\Exceptions\HttpResponseException;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Routing\Controller as BaseController;
 | 
			
		||||
use Illuminate\Foundation\Validation\ValidatesRequests;
 | 
			
		||||
use BookStack\User;
 | 
			
		||||
 | 
			
		||||
abstract class Controller extends BaseController
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,7 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use Activity;
 | 
			
		||||
use BookStack\Repos\EntityRepo;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use Views;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,12 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Exceptions\ImageUploadException;
 | 
			
		||||
use BookStack\Exceptions\NotFoundException;
 | 
			
		||||
use BookStack\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Repos\ImageRepo;
 | 
			
		||||
use BookStack\Repos\PageRepo;
 | 
			
		||||
use BookStack\Uploads\Image;
 | 
			
		||||
use BookStack\Uploads\ImageRepo;
 | 
			
		||||
use Illuminate\Filesystem\Filesystem as File;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use BookStack\Image;
 | 
			
		||||
use BookStack\Repos\PageRepo;
 | 
			
		||||
 | 
			
		||||
class ImageController extends Controller
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -220,7 +219,7 @@ class ImageController extends Controller
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show the usage of an image on pages.
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     * @param \BookStack\Entities\Repos\EntityRepo $entityRepo
 | 
			
		||||
     * @param $id
 | 
			
		||||
     * @return \Illuminate\Http\JsonResponse
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,31 +1,32 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use Activity;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Entities\ExportService;
 | 
			
		||||
use BookStack\Entities\Repos\PageRepo;
 | 
			
		||||
use BookStack\Exceptions\NotFoundException;
 | 
			
		||||
use BookStack\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Repos\UserRepo;
 | 
			
		||||
use BookStack\Services\ExportService;
 | 
			
		||||
use GatherContent\Htmldiff\Htmldiff;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use Views;
 | 
			
		||||
use GatherContent\Htmldiff\Htmldiff;
 | 
			
		||||
 | 
			
		||||
class PageController extends Controller
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    protected $entityRepo;
 | 
			
		||||
    protected $pageRepo;
 | 
			
		||||
    protected $exportService;
 | 
			
		||||
    protected $userRepo;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * PageController constructor.
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     * @param ExportService $exportService
 | 
			
		||||
     * @param \BookStack\Entities\Repos\PageRepo $pageRepo
 | 
			
		||||
     * @param \BookStack\Entities\ExportService $exportService
 | 
			
		||||
     * @param UserRepo $userRepo
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(EntityRepo $entityRepo, ExportService $exportService, UserRepo $userRepo)
 | 
			
		||||
    public function __construct(PageRepo $pageRepo, ExportService $exportService, UserRepo $userRepo)
 | 
			
		||||
    {
 | 
			
		||||
        $this->entityRepo = $entityRepo;
 | 
			
		||||
        $this->pageRepo = $pageRepo;
 | 
			
		||||
        $this->exportService = $exportService;
 | 
			
		||||
        $this->userRepo = $userRepo;
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
| 
						 | 
				
			
			@ -42,11 +43,11 @@ class PageController extends Controller
 | 
			
		|||
    public function create($bookSlug, $chapterSlug = null)
 | 
			
		||||
    {
 | 
			
		||||
        if ($chapterSlug !== null) {
 | 
			
		||||
            $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
 | 
			
		||||
            $chapter = $this->pageRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
 | 
			
		||||
            $book = $chapter->book;
 | 
			
		||||
        } else {
 | 
			
		||||
            $chapter = null;
 | 
			
		||||
            $book = $this->entityRepo->getBySlug('book', $bookSlug);
 | 
			
		||||
            $book = $this->pageRepo->getBySlug('book', $bookSlug);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $parent = $chapter ? $chapter : $book;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +55,7 @@ class PageController extends Controller
 | 
			
		|||
 | 
			
		||||
        // Redirect to draft edit screen if signed in
 | 
			
		||||
        if ($this->signedIn) {
 | 
			
		||||
            $draft = $this->entityRepo->getDraftPage($book, $chapter);
 | 
			
		||||
            $draft = $this->pageRepo->getDraftPage($book, $chapter);
 | 
			
		||||
            return redirect($draft->getUrl());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -78,18 +79,18 @@ class PageController extends Controller
 | 
			
		|||
        ]);
 | 
			
		||||
 | 
			
		||||
        if ($chapterSlug !== null) {
 | 
			
		||||
            $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
 | 
			
		||||
            $chapter = $this->pageRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
 | 
			
		||||
            $book = $chapter->book;
 | 
			
		||||
        } else {
 | 
			
		||||
            $chapter = null;
 | 
			
		||||
            $book = $this->entityRepo->getBySlug('book', $bookSlug);
 | 
			
		||||
            $book = $this->pageRepo->getBySlug('book', $bookSlug);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $parent = $chapter ? $chapter : $book;
 | 
			
		||||
        $this->checkOwnablePermission('page-create', $parent);
 | 
			
		||||
 | 
			
		||||
        $page = $this->entityRepo->getDraftPage($book, $chapter);
 | 
			
		||||
        $this->entityRepo->publishPageDraft($page, [
 | 
			
		||||
        $page = $this->pageRepo->getDraftPage($book, $chapter);
 | 
			
		||||
        $this->pageRepo->publishPageDraft($page, [
 | 
			
		||||
            'name' => $request->get('name'),
 | 
			
		||||
            'html' => ''
 | 
			
		||||
        ]);
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +105,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function editDraft($bookSlug, $pageId)
 | 
			
		||||
    {
 | 
			
		||||
        $draft = $this->entityRepo->getById('page', $pageId, true);
 | 
			
		||||
        $draft = $this->pageRepo->getById('page', $pageId, true);
 | 
			
		||||
        $this->checkOwnablePermission('page-create', $draft->parent);
 | 
			
		||||
        $this->setPageTitle(trans('entities.pages_edit_draft'));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -131,19 +132,19 @@ class PageController extends Controller
 | 
			
		|||
        ]);
 | 
			
		||||
 | 
			
		||||
        $input = $request->all();
 | 
			
		||||
        $draftPage = $this->entityRepo->getById('page', $pageId, true);
 | 
			
		||||
        $draftPage = $this->pageRepo->getById('page', $pageId, true);
 | 
			
		||||
        $book = $draftPage->book;
 | 
			
		||||
 | 
			
		||||
        $parent = $draftPage->parent;
 | 
			
		||||
        $this->checkOwnablePermission('page-create', $parent);
 | 
			
		||||
 | 
			
		||||
        if ($parent->isA('chapter')) {
 | 
			
		||||
            $input['priority'] = $this->entityRepo->getNewChapterPriority($parent);
 | 
			
		||||
            $input['priority'] = $this->pageRepo->getNewChapterPriority($parent);
 | 
			
		||||
        } else {
 | 
			
		||||
            $input['priority'] = $this->entityRepo->getNewBookPriority($parent);
 | 
			
		||||
            $input['priority'] = $this->pageRepo->getNewBookPriority($parent);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $page = $this->entityRepo->publishPageDraft($draftPage, $input);
 | 
			
		||||
        $page = $this->pageRepo->publishPageDraft($draftPage, $input);
 | 
			
		||||
 | 
			
		||||
        Activity::add($page, 'page_create', $book->id);
 | 
			
		||||
        return redirect($page->getUrl());
 | 
			
		||||
| 
						 | 
				
			
			@ -160,9 +161,9 @@ class PageController extends Controller
 | 
			
		|||
    public function show($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
            $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        } catch (NotFoundException $e) {
 | 
			
		||||
            $page = $this->entityRepo->getPageByOldSlug($pageSlug, $bookSlug);
 | 
			
		||||
            $page = $this->pageRepo->getPageByOldSlug($pageSlug, $bookSlug);
 | 
			
		||||
            if ($page === null) {
 | 
			
		||||
                throw $e;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -171,9 +172,9 @@ class PageController extends Controller
 | 
			
		|||
 | 
			
		||||
        $this->checkOwnablePermission('page-view', $page);
 | 
			
		||||
 | 
			
		||||
        $page->html = $this->entityRepo->renderPage($page);
 | 
			
		||||
        $sidebarTree = $this->entityRepo->getBookChildren($page->book);
 | 
			
		||||
        $pageNav = $this->entityRepo->getPageNav($page->html);
 | 
			
		||||
        $page->html = $this->pageRepo->renderPage($page);
 | 
			
		||||
        $sidebarTree = $this->pageRepo->getBookChildren($page->book);
 | 
			
		||||
        $pageNav = $this->pageRepo->getPageNav($page->html);
 | 
			
		||||
 | 
			
		||||
        // check if the comment's are enabled
 | 
			
		||||
        $commentsEnabled = !setting('app-disable-comments');
 | 
			
		||||
| 
						 | 
				
			
			@ -199,7 +200,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function getPageAjax($pageId)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getById('page', $pageId);
 | 
			
		||||
        $page = $this->pageRepo->getById('page', $pageId);
 | 
			
		||||
        return response()->json($page);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -208,28 +209,29 @@ class PageController extends Controller
 | 
			
		|||
     * @param string $bookSlug
 | 
			
		||||
     * @param string $pageSlug
 | 
			
		||||
     * @return Response
 | 
			
		||||
     * @throws NotFoundException
 | 
			
		||||
     */
 | 
			
		||||
    public function edit($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('page-update', $page);
 | 
			
		||||
        $this->setPageTitle(trans('entities.pages_editing_named', ['pageName'=>$page->getShortName()]));
 | 
			
		||||
        $page->isDraft = false;
 | 
			
		||||
 | 
			
		||||
        // Check for active editing
 | 
			
		||||
        $warnings = [];
 | 
			
		||||
        if ($this->entityRepo->isPageEditingActive($page, 60)) {
 | 
			
		||||
            $warnings[] = $this->entityRepo->getPageEditingActiveMessage($page, 60);
 | 
			
		||||
        if ($this->pageRepo->isPageEditingActive($page, 60)) {
 | 
			
		||||
            $warnings[] = $this->pageRepo->getPageEditingActiveMessage($page, 60);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check for a current draft version for this user
 | 
			
		||||
        if ($this->entityRepo->hasUserGotPageDraft($page, $this->currentUser->id)) {
 | 
			
		||||
            $draft = $this->entityRepo->getUserPageDraft($page, $this->currentUser->id);
 | 
			
		||||
            $page->name = $draft->name;
 | 
			
		||||
            $page->html = $draft->html;
 | 
			
		||||
            $page->markdown = $draft->markdown;
 | 
			
		||||
        $userPageDraft = $this->pageRepo->getUserPageDraft($page, $this->currentUser->id);
 | 
			
		||||
        if ($userPageDraft !== null) {
 | 
			
		||||
            $page->name = $userPageDraft->name;
 | 
			
		||||
            $page->html = $userPageDraft->html;
 | 
			
		||||
            $page->markdown = $userPageDraft->markdown;
 | 
			
		||||
            $page->isDraft = true;
 | 
			
		||||
            $warnings [] = $this->entityRepo->getUserPageDraftMessage($draft);
 | 
			
		||||
            $warnings [] = $this->pageRepo->getUserPageDraftMessage($userPageDraft);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (count($warnings) > 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -257,9 +259,9 @@ class PageController extends Controller
 | 
			
		|||
        $this->validate($request, [
 | 
			
		||||
            'name' => 'required|string|max:255'
 | 
			
		||||
        ]);
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('page-update', $page);
 | 
			
		||||
        $this->entityRepo->updatePage($page, $page->book->id, $request->all());
 | 
			
		||||
        $this->pageRepo->updatePage($page, $page->book->id, $request->all());
 | 
			
		||||
        Activity::add($page, 'page_update', $page->book->id);
 | 
			
		||||
        return redirect($page->getUrl());
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -272,7 +274,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function saveDraft(Request $request, $pageId)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getById('page', $pageId, true);
 | 
			
		||||
        $page = $this->pageRepo->getById('page', $pageId, true);
 | 
			
		||||
        $this->checkOwnablePermission('page-update', $page);
 | 
			
		||||
 | 
			
		||||
        if (!$this->signedIn) {
 | 
			
		||||
| 
						 | 
				
			
			@ -282,7 +284,7 @@ class PageController extends Controller
 | 
			
		|||
            ], 500);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $draft = $this->entityRepo->updatePageDraft($page, $request->only(['name', 'html', 'markdown']));
 | 
			
		||||
        $draft = $this->pageRepo->updatePageDraft($page, $request->only(['name', 'html', 'markdown']));
 | 
			
		||||
 | 
			
		||||
        $updateTime = $draft->updated_at->timestamp;
 | 
			
		||||
        return response()->json([
 | 
			
		||||
| 
						 | 
				
			
			@ -300,7 +302,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function redirectFromLink($pageId)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getById('page', $pageId);
 | 
			
		||||
        $page = $this->pageRepo->getById('page', $pageId);
 | 
			
		||||
        return redirect($page->getUrl());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -312,7 +314,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function showDelete($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('page-delete', $page);
 | 
			
		||||
        $this->setPageTitle(trans('entities.pages_delete_named', ['pageName'=>$page->getShortName()]));
 | 
			
		||||
        return view('pages/delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
 | 
			
		||||
| 
						 | 
				
			
			@ -328,7 +330,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function showDeleteDraft($bookSlug, $pageId)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getById('page', $pageId, true);
 | 
			
		||||
        $page = $this->pageRepo->getById('page', $pageId, true);
 | 
			
		||||
        $this->checkOwnablePermission('page-update', $page);
 | 
			
		||||
        $this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName'=>$page->getShortName()]));
 | 
			
		||||
        return view('pages/delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
 | 
			
		||||
| 
						 | 
				
			
			@ -343,10 +345,10 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function destroy($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $book = $page->book;
 | 
			
		||||
        $this->checkOwnablePermission('page-delete', $page);
 | 
			
		||||
        $this->entityRepo->destroyPage($page);
 | 
			
		||||
        $this->pageRepo->destroyPage($page);
 | 
			
		||||
 | 
			
		||||
        Activity::addMessage('page_delete', $book->id, $page->name);
 | 
			
		||||
        session()->flash('success', trans('entities.pages_delete_success'));
 | 
			
		||||
| 
						 | 
				
			
			@ -362,11 +364,11 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function destroyDraft($bookSlug, $pageId)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getById('page', $pageId, true);
 | 
			
		||||
        $page = $this->pageRepo->getById('page', $pageId, true);
 | 
			
		||||
        $book = $page->book;
 | 
			
		||||
        $this->checkOwnablePermission('page-update', $page);
 | 
			
		||||
        session()->flash('success', trans('entities.pages_delete_draft_success'));
 | 
			
		||||
        $this->entityRepo->destroyPage($page);
 | 
			
		||||
        $this->pageRepo->destroyPage($page);
 | 
			
		||||
        return redirect($book->getUrl());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -378,7 +380,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function showRevisions($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()]));
 | 
			
		||||
        return view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -392,7 +394,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function showRevision($bookSlug, $pageSlug, $revisionId)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $revision = $page->revisions()->where('id', '=', $revisionId)->first();
 | 
			
		||||
        if ($revision === null) {
 | 
			
		||||
            abort(404);
 | 
			
		||||
| 
						 | 
				
			
			@ -417,7 +419,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function showRevisionChanges($bookSlug, $pageSlug, $revisionId)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $revision = $page->revisions()->where('id', '=', $revisionId)->first();
 | 
			
		||||
        if ($revision === null) {
 | 
			
		||||
            abort(404);
 | 
			
		||||
| 
						 | 
				
			
			@ -447,9 +449,9 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function restoreRevision($bookSlug, $pageSlug, $revisionId)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('page-update', $page);
 | 
			
		||||
        $page = $this->entityRepo->restorePageRevision($page, $page->book, $revisionId);
 | 
			
		||||
        $page = $this->pageRepo->restorePageRevision($page, $page->book, $revisionId);
 | 
			
		||||
        Activity::add($page, 'page_restore', $page->book->id);
 | 
			
		||||
        return redirect($page->getUrl());
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -466,7 +468,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function destroyRevision($bookSlug, $pageSlug, $revId)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('page-delete', $page);
 | 
			
		||||
 | 
			
		||||
        $revision = $page->revisions()->where('id', '=', $revId)->first();
 | 
			
		||||
| 
						 | 
				
			
			@ -497,8 +499,8 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function exportPdf($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page->html = $this->entityRepo->renderPage($page);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $page->html = $this->pageRepo->renderPage($page);
 | 
			
		||||
        $pdfContent = $this->exportService->pageToPdf($page);
 | 
			
		||||
        return $this->downloadResponse($pdfContent, $pageSlug . '.pdf');
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -511,8 +513,8 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function exportHtml($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page->html = $this->entityRepo->renderPage($page);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $page->html = $this->pageRepo->renderPage($page);
 | 
			
		||||
        $containedHtml = $this->exportService->pageToContainedHtml($page);
 | 
			
		||||
        return $this->downloadResponse($containedHtml, $pageSlug . '.html');
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -525,7 +527,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function exportPlainText($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $pageText = $this->exportService->pageToPlainText($page);
 | 
			
		||||
        return $this->downloadResponse($pageText, $pageSlug . '.txt');
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -536,7 +538,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function showRecentlyCreated()
 | 
			
		||||
    {
 | 
			
		||||
        $pages = $this->entityRepo->getRecentlyCreatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-created'));
 | 
			
		||||
        $pages = $this->pageRepo->getRecentlyCreatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-created'));
 | 
			
		||||
        return view('pages/detailed-listing', [
 | 
			
		||||
            'title' => trans('entities.recently_created_pages'),
 | 
			
		||||
            'pages' => $pages
 | 
			
		||||
| 
						 | 
				
			
			@ -549,7 +551,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function showRecentlyUpdated()
 | 
			
		||||
    {
 | 
			
		||||
        $pages = $this->entityRepo->getRecentlyUpdatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-updated'));
 | 
			
		||||
        $pages = $this->pageRepo->getRecentlyUpdatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-updated'));
 | 
			
		||||
        return view('pages/detailed-listing', [
 | 
			
		||||
            'title' => trans('entities.recently_updated_pages'),
 | 
			
		||||
            'pages' => $pages
 | 
			
		||||
| 
						 | 
				
			
			@ -564,7 +566,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function showRestrict($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('restrictions-manage', $page);
 | 
			
		||||
        $roles = $this->userRepo->getRestrictableRoles();
 | 
			
		||||
        return view('pages/restrictions', [
 | 
			
		||||
| 
						 | 
				
			
			@ -582,7 +584,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function showMove($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('page-update', $page);
 | 
			
		||||
        return view('pages/move', [
 | 
			
		||||
            'book' => $page->book,
 | 
			
		||||
| 
						 | 
				
			
			@ -600,7 +602,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function move($bookSlug, $pageSlug, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('page-update', $page);
 | 
			
		||||
 | 
			
		||||
        $entitySelection = $request->get('entity_selection', null);
 | 
			
		||||
| 
						 | 
				
			
			@ -614,7 +616,7 @@ class PageController extends Controller
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $parent = $this->entityRepo->getById($entityType, $entityId);
 | 
			
		||||
            $parent = $this->pageRepo->getById($entityType, $entityId);
 | 
			
		||||
        } catch (\Exception $e) {
 | 
			
		||||
            session()->flash(trans('entities.selected_book_chapter_not_found'));
 | 
			
		||||
            return redirect()->back();
 | 
			
		||||
| 
						 | 
				
			
			@ -622,7 +624,7 @@ class PageController extends Controller
 | 
			
		|||
 | 
			
		||||
        $this->checkOwnablePermission('page-create', $parent);
 | 
			
		||||
 | 
			
		||||
        $this->entityRepo->changePageParent($page, $parent);
 | 
			
		||||
        $this->pageRepo->changePageParent($page, $parent);
 | 
			
		||||
        Activity::add($page, 'page_move', $page->book->id);
 | 
			
		||||
        session()->flash('success', trans('entities.pages_move_success', ['parentName' => $parent->name]));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -638,7 +640,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function showCopy($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('page-update', $page);
 | 
			
		||||
        session()->flashInput(['name' => $page->name]);
 | 
			
		||||
        return view('pages/copy', [
 | 
			
		||||
| 
						 | 
				
			
			@ -657,7 +659,7 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function copy($bookSlug, $pageSlug, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('page-update', $page);
 | 
			
		||||
 | 
			
		||||
        $entitySelection = $request->get('entity_selection', null);
 | 
			
		||||
| 
						 | 
				
			
			@ -669,7 +671,7 @@ class PageController extends Controller
 | 
			
		|||
            $entityId = intval($stringExploded[1]);
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                $parent = $this->entityRepo->getById($entityType, $entityId);
 | 
			
		||||
                $parent = $this->pageRepo->getById($entityType, $entityId);
 | 
			
		||||
            } catch (\Exception $e) {
 | 
			
		||||
                session()->flash(trans('entities.selected_book_chapter_not_found'));
 | 
			
		||||
                return redirect()->back();
 | 
			
		||||
| 
						 | 
				
			
			@ -678,7 +680,7 @@ class PageController extends Controller
 | 
			
		|||
 | 
			
		||||
        $this->checkOwnablePermission('page-create', $parent);
 | 
			
		||||
 | 
			
		||||
        $pageCopy = $this->entityRepo->copyPage($page, $parent, $request->get('name', ''));
 | 
			
		||||
        $pageCopy = $this->pageRepo->copyPage($page, $parent, $request->get('name', ''));
 | 
			
		||||
 | 
			
		||||
        Activity::add($pageCopy, 'page_create', $pageCopy->book->id);
 | 
			
		||||
        session()->flash('success', trans('entities.pages_copy_success'));
 | 
			
		||||
| 
						 | 
				
			
			@ -696,9 +698,9 @@ class PageController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function restrict($bookSlug, $pageSlug, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
			
		||||
        $this->checkOwnablePermission('restrictions-manage', $page);
 | 
			
		||||
        $this->entityRepo->updateEntityPermissionsFromRequest($request, $page);
 | 
			
		||||
        $this->pageRepo->updateEntityPermissionsFromRequest($request, $page);
 | 
			
		||||
        session()->flash('success', trans('entities.pages_permissions_success'));
 | 
			
		||||
        return redirect($page->getUrl());
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\Permissions\PermissionsRepo;
 | 
			
		||||
use BookStack\Exceptions\PermissionsException;
 | 
			
		||||
use BookStack\Repos\PermissionsRepo;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
 | 
			
		||||
class PermissionController extends Controller
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ class PermissionController extends Controller
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * PermissionController constructor.
 | 
			
		||||
     * @param PermissionsRepo $permissionsRepo
 | 
			
		||||
     * @param \BookStack\Auth\Permissions\PermissionsRepo $permissionsRepo
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(PermissionsRepo $permissionsRepo)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Services\SearchService;
 | 
			
		||||
use BookStack\Services\ViewService;
 | 
			
		||||
use BookStack\Actions\ViewService;
 | 
			
		||||
use BookStack\Entities\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Entities\SearchService;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
 | 
			
		||||
class SearchController extends Controller
 | 
			
		||||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ class SearchController extends Controller
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * SearchController constructor.
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     * @param \BookStack\Entities\Repos\EntityRepo $entityRepo
 | 
			
		||||
     * @param ViewService $viewService
 | 
			
		||||
     * @param SearchService $searchService
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +97,7 @@ class SearchController extends Controller
 | 
			
		|||
            $entities = $this->searchService->searchEntities($searchTerm, 'all', 1, 20, $permission)['results'];
 | 
			
		||||
        } else {
 | 
			
		||||
            $entityNames = $entityTypes->map(function ($type) {
 | 
			
		||||
                return 'BookStack\\' . ucfirst($type);
 | 
			
		||||
                return 'BookStack\\' . ucfirst($type); // TODO - Extract this elsewhere, too specific and stringy
 | 
			
		||||
            })->toArray();
 | 
			
		||||
            $entities = $this->viewService->getPopular(20, 0, $entityNames, $permission);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Services\ImageService;
 | 
			
		||||
use BookStack\Uploads\ImageService;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use Setting;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Repos\TagRepo;
 | 
			
		||||
use BookStack\Actions\TagRepo;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
 | 
			
		||||
class TagController extends Controller
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,10 @@
 | 
			
		|||
<?php namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use BookStack\Auth\Access\SocialAuthService;
 | 
			
		||||
use BookStack\Auth\User;
 | 
			
		||||
use BookStack\Auth\UserRepo;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use BookStack\Repos\UserRepo;
 | 
			
		||||
use BookStack\Services\SocialAuthService;
 | 
			
		||||
use BookStack\User;
 | 
			
		||||
 | 
			
		||||
class UserController extends Controller
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +15,7 @@ class UserController extends Controller
 | 
			
		|||
    /**
 | 
			
		||||
     * UserController constructor.
 | 
			
		||||
     * @param User     $user
 | 
			
		||||
     * @param UserRepo $userRepo
 | 
			
		||||
     * @param \BookStack\Auth\UserRepo $userRepo
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(User $user, UserRepo $userRepo)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -101,7 +100,7 @@ class UserController extends Controller
 | 
			
		|||
    /**
 | 
			
		||||
     * Show the form for editing the specified user.
 | 
			
		||||
     * @param  int              $id
 | 
			
		||||
     * @param SocialAuthService $socialAuthService
 | 
			
		||||
     * @param \BookStack\Auth\Access\SocialAuthService $socialAuthService
 | 
			
		||||
     * @return Response
 | 
			
		||||
     */
 | 
			
		||||
    public function edit($id, SocialAuthService $socialAuthService)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,8 @@
 | 
			
		|||
namespace BookStack\Http\Middleware;
 | 
			
		||||
 | 
			
		||||
use Closure;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Fideloper\Proxy\TrustProxies as Middleware;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
 | 
			
		||||
class TrustProxies extends Middleware
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,9 +3,9 @@
 | 
			
		|||
namespace BookStack\Notifications;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Bus\Queueable;
 | 
			
		||||
use Illuminate\Notifications\Notification;
 | 
			
		||||
use Illuminate\Contracts\Queue\ShouldQueue;
 | 
			
		||||
use Illuminate\Notifications\Messages\MailMessage;
 | 
			
		||||
use Illuminate\Notifications\Notification;
 | 
			
		||||
 | 
			
		||||
class ConfirmEmail extends Notification implements ShouldQueue
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Notifications;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Notifications\Notification;
 | 
			
		||||
use Illuminate\Notifications\Messages\MailMessage;
 | 
			
		||||
use Illuminate\Notifications\Notification;
 | 
			
		||||
 | 
			
		||||
class ResetPassword extends Notification
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,7 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\User;
 | 
			
		||||
 | 
			
		||||
abstract class Ownable extends Model
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,15 @@
 | 
			
		|||
<?php namespace BookStack\Providers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Services\SettingService;
 | 
			
		||||
use BookStack\Setting;
 | 
			
		||||
use Blade;
 | 
			
		||||
use BookStack\Entities\Book;
 | 
			
		||||
use BookStack\Entities\Bookshelf;
 | 
			
		||||
use BookStack\Entities\Chapter;
 | 
			
		||||
use BookStack\Entities\Page;
 | 
			
		||||
use BookStack\Settings\Setting;
 | 
			
		||||
use BookStack\Settings\SettingService;
 | 
			
		||||
use Illuminate\Database\Eloquent\Relations\Relation;
 | 
			
		||||
use Illuminate\Support\ServiceProvider;
 | 
			
		||||
use Schema;
 | 
			
		||||
use Validator;
 | 
			
		||||
 | 
			
		||||
class AppServiceProvider extends ServiceProvider
 | 
			
		||||
| 
						 | 
				
			
			@ -20,12 +27,21 @@ class AppServiceProvider extends ServiceProvider
 | 
			
		|||
            return in_array($value->getMimeType(), $imageMimes);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        \Blade::directive('icon', function ($expression) {
 | 
			
		||||
        // Custom blade view directives
 | 
			
		||||
        Blade::directive('icon', function ($expression) {
 | 
			
		||||
            return "<?php echo icon($expression); ?>";
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Allow longer string lengths after upgrade to utf8mb4
 | 
			
		||||
        \Schema::defaultStringLength(191);
 | 
			
		||||
        Schema::defaultStringLength(191);
 | 
			
		||||
 | 
			
		||||
        // Set morph-map due to namespace changes
 | 
			
		||||
        Relation::morphMap([
 | 
			
		||||
            'BookStack\\Bookshelf' => Bookshelf::class,
 | 
			
		||||
            'BookStack\\Book' => Book::class,
 | 
			
		||||
            'BookStack\\Chapter' => Chapter::class,
 | 
			
		||||
            'BookStack\\Page' => Page::class,
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
namespace BookStack\Providers;
 | 
			
		||||
 | 
			
		||||
use Auth;
 | 
			
		||||
use BookStack\Services\LdapService;
 | 
			
		||||
use BookStack\Auth\Access\LdapService;
 | 
			
		||||
use Illuminate\Support\ServiceProvider;
 | 
			
		||||
 | 
			
		||||
class AuthServiceProvider extends ServiceProvider
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@
 | 
			
		|||
namespace BookStack\Providers;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Support\ServiceProvider;
 | 
			
		||||
use Illuminate\Support\Facades\Broadcast;
 | 
			
		||||
 | 
			
		||||
class BroadcastServiceProvider extends ServiceProvider
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,18 +2,18 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Providers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Activity;
 | 
			
		||||
use BookStack\Image;
 | 
			
		||||
use BookStack\Services\ImageService;
 | 
			
		||||
use BookStack\Services\PermissionService;
 | 
			
		||||
use BookStack\Services\ViewService;
 | 
			
		||||
use BookStack\Setting;
 | 
			
		||||
use BookStack\View;
 | 
			
		||||
use BookStack\Actions\Activity;
 | 
			
		||||
use BookStack\Actions\ActivityService;
 | 
			
		||||
use BookStack\Actions\View;
 | 
			
		||||
use BookStack\Actions\ViewService;
 | 
			
		||||
use BookStack\Auth\Permissions\PermissionService;
 | 
			
		||||
use BookStack\Settings\Setting;
 | 
			
		||||
use BookStack\Settings\SettingService;
 | 
			
		||||
use BookStack\Uploads\Image;
 | 
			
		||||
use BookStack\Uploads\ImageService;
 | 
			
		||||
use Illuminate\Contracts\Cache\Repository;
 | 
			
		||||
use Illuminate\Contracts\Filesystem\Factory;
 | 
			
		||||
use Illuminate\Support\ServiceProvider;
 | 
			
		||||
use BookStack\Services\ActivityService;
 | 
			
		||||
use BookStack\Services\SettingService;
 | 
			
		||||
use Intervention\Image\ImageManager;
 | 
			
		||||
 | 
			
		||||
class CustomFacadeProvider extends ServiceProvider
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Providers;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
 | 
			
		||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
 | 
			
		||||
use SocialiteProviders\Manager\SocialiteWasCalled;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,9 +2,7 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Providers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Role;
 | 
			
		||||
use BookStack\Services\LdapService;
 | 
			
		||||
use BookStack\User;
 | 
			
		||||
use BookStack\Auth\Access\LdapService;
 | 
			
		||||
use Illuminate\Contracts\Auth\Authenticatable;
 | 
			
		||||
use Illuminate\Contracts\Auth\UserProvider;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +17,7 @@ class LdapUserProvider implements UserProvider
 | 
			
		|||
    protected $model;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var LdapService
 | 
			
		||||
     * @var \BookStack\Auth\LdapService
 | 
			
		||||
     */
 | 
			
		||||
    protected $ldapService;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +25,7 @@ class LdapUserProvider implements UserProvider
 | 
			
		|||
    /**
 | 
			
		||||
     * LdapUserProvider constructor.
 | 
			
		||||
     * @param             $model
 | 
			
		||||
     * @param LdapService $ldapService
 | 
			
		||||
     * @param \BookStack\Auth\LdapService $ldapService
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct($model, LdapService $ldapService)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Providers;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Routing\Router;
 | 
			
		||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
 | 
			
		||||
use Route;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Settings;
 | 
			
		||||
 | 
			
		||||
use BookStack\Model;
 | 
			
		||||
 | 
			
		||||
class Setting extends Model
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,5 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Settings;
 | 
			
		||||
 | 
			
		||||
use BookStack\Setting;
 | 
			
		||||
use BookStack\User;
 | 
			
		||||
use Illuminate\Contracts\Cache\Repository as Cache;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +53,7 @@ class SettingService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a user-specific setting from the database or cache.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param \BookStack\Auth\User $user
 | 
			
		||||
     * @param $key
 | 
			
		||||
     * @param bool $default
 | 
			
		||||
     * @return bool|string
 | 
			
		||||
| 
						 | 
				
			
			@ -174,7 +172,7 @@ class SettingService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Put a user-specific setting into the database.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param \BookStack\Auth\User $user
 | 
			
		||||
     * @param $key
 | 
			
		||||
     * @param $value
 | 
			
		||||
     * @return bool
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,7 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Uploads;
 | 
			
		||||
 | 
			
		||||
use BookStack\Entities\Page;
 | 
			
		||||
use BookStack\Ownable;
 | 
			
		||||
 | 
			
		||||
class Attachment extends Ownable
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +21,7 @@ class Attachment extends Ownable
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the page this file was uploaded to.
 | 
			
		||||
     * @return Page
 | 
			
		||||
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
 | 
			
		||||
     */
 | 
			
		||||
    public function page()
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Uploads;
 | 
			
		||||
 | 
			
		||||
use BookStack\Exceptions\FileUploadException;
 | 
			
		||||
use BookStack\Attachment;
 | 
			
		||||
use Exception;
 | 
			
		||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
<?php namespace BookStack;
 | 
			
		||||
<?php namespace BookStack\Uploads;
 | 
			
		||||
 | 
			
		||||
use BookStack\Ownable;
 | 
			
		||||
use Images;
 | 
			
		||||
 | 
			
		||||
class Image extends Ownable
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +1,7 @@
 | 
			
		|||
<?php namespace BookStack\Repos;
 | 
			
		||||
<?php namespace BookStack\Uploads;
 | 
			
		||||
 | 
			
		||||
use BookStack\Image;
 | 
			
		||||
use BookStack\Page;
 | 
			
		||||
use BookStack\Services\ImageService;
 | 
			
		||||
use BookStack\Services\PermissionService;
 | 
			
		||||
use BookStack\Auth\Permissions\PermissionService;
 | 
			
		||||
use BookStack\Entities\Page;
 | 
			
		||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
 | 
			
		||||
 | 
			
		||||
class ImageRepo
 | 
			
		||||
| 
						 | 
				
			
			@ -18,8 +16,8 @@ class ImageRepo
 | 
			
		|||
     * ImageRepo constructor.
 | 
			
		||||
     * @param Image $image
 | 
			
		||||
     * @param ImageService $imageService
 | 
			
		||||
     * @param PermissionService $permissionService
 | 
			
		||||
     * @param Page $page
 | 
			
		||||
     * @param \BookStack\Auth\Permissions\PermissionService $permissionService
 | 
			
		||||
     * @param \BookStack\Entities\Page $page
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(Image $image, ImageService $imageService, PermissionService $permissionService, Page $page)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -1,14 +1,13 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Uploads;
 | 
			
		||||
 | 
			
		||||
use BookStack\Auth\User;
 | 
			
		||||
use BookStack\Exceptions\ImageUploadException;
 | 
			
		||||
use BookStack\Image;
 | 
			
		||||
use BookStack\User;
 | 
			
		||||
use DB;
 | 
			
		||||
use Exception;
 | 
			
		||||
use Illuminate\Contracts\Cache\Repository as Cache;
 | 
			
		||||
use Illuminate\Contracts\Filesystem\Factory as FileSystem;
 | 
			
		||||
use Intervention\Image\Exception\NotSupportedException;
 | 
			
		||||
use Intervention\Image\ImageManager;
 | 
			
		||||
use Illuminate\Contracts\Filesystem\Factory as FileSystem;
 | 
			
		||||
use Illuminate\Contracts\Cache\Repository as Cache;
 | 
			
		||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
 | 
			
		||||
 | 
			
		||||
class ImageService extends UploadService
 | 
			
		||||
| 
						 | 
				
			
			@ -281,7 +280,7 @@ class ImageService extends UploadService
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Save a gravatar image and set a the profile image for a user.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param \BookStack\Auth\User $user
 | 
			
		||||
     * @param int $size
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
<?php namespace BookStack\Services;
 | 
			
		||||
<?php namespace BookStack\Uploads;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Contracts\Filesystem\Factory as FileSystem;
 | 
			
		||||
use Illuminate\Contracts\Filesystem\Filesystem as FileSystemInstance;
 | 
			
		||||
 | 
			
		||||
class UploadService
 | 
			
		||||
abstract class UploadService
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -30,11 +30,11 @@ function versioned_asset($file = '')
 | 
			
		|||
/**
 | 
			
		||||
 * Helper method to get the current User.
 | 
			
		||||
 * Defaults to public 'Guest' user if not logged in.
 | 
			
		||||
 * @return \BookStack\User
 | 
			
		||||
 * @return \BookStack\Auth\User
 | 
			
		||||
 */
 | 
			
		||||
function user()
 | 
			
		||||
{
 | 
			
		||||
    return auth()->user() ?: \BookStack\User::getDefault();
 | 
			
		||||
    return auth()->user() ?: \BookStack\Auth\User::getDefault();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -61,7 +61,7 @@ function userCan($permission, Ownable $ownable = null)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Check permission on ownable item
 | 
			
		||||
    $permissionService = app(\BookStack\Services\PermissionService::class);
 | 
			
		||||
    $permissionService = app(\BookStack\Auth\Permissions\PermissionService::class);
 | 
			
		||||
    return $permissionService->checkOwnableUserAccess($ownable, $permission);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -69,11 +69,11 @@ function userCan($permission, Ownable $ownable = null)
 | 
			
		|||
 * Helper to access system settings.
 | 
			
		||||
 * @param $key
 | 
			
		||||
 * @param bool $default
 | 
			
		||||
 * @return bool|string|\BookStack\Services\SettingService
 | 
			
		||||
 * @return bool|string|\BookStack\Settings\SettingService
 | 
			
		||||
 */
 | 
			
		||||
function setting($key = null, $default = false)
 | 
			
		||||
{
 | 
			
		||||
    $settingService = resolve(\BookStack\Services\SettingService::class);
 | 
			
		||||
    $settingService = resolve(\BookStack\Settings\SettingService::class);
 | 
			
		||||
    if (is_null($key)) {
 | 
			
		||||
        return $settingService;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -92,10 +92,15 @@ function baseUrl($path, $forceAppDomain = false)
 | 
			
		|||
    if ($isFullUrl && !$forceAppDomain) {
 | 
			
		||||
        return $path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $path = trim($path, '/');
 | 
			
		||||
    $base = rtrim(config('app.url'), '/');
 | 
			
		||||
 | 
			
		||||
    // Remove non-specified domain if forced and we have a domain
 | 
			
		||||
    if ($isFullUrl && $forceAppDomain) {
 | 
			
		||||
        if (!empty($base) && strpos($path, $base) === 0) {
 | 
			
		||||
            $path = trim(substr($path, strlen($base) - 1));
 | 
			
		||||
        }
 | 
			
		||||
        $explodedPath = explode('/', $path);
 | 
			
		||||
        $path = implode('/', array_splice($explodedPath, 3));
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +110,7 @@ function baseUrl($path, $forceAppDomain = false)
 | 
			
		|||
        return url($path);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return rtrim(config('app.url'), '/') . '/' . $path;
 | 
			
		||||
    return $base . '/' . $path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@
 | 
			
		|||
        "php": ">=7.0.0",
 | 
			
		||||
        "ext-tidy": "*",
 | 
			
		||||
        "ext-dom": "*",
 | 
			
		||||
        "laravel/framework": "~5.5.42",
 | 
			
		||||
        "laravel/framework": "~5.5.44",
 | 
			
		||||
        "fideloper/proxy": "~3.3",
 | 
			
		||||
        "intervention/image": "^2.4",
 | 
			
		||||
        "laravel/socialite": "^3.0",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -84,7 +84,7 @@ return [
 | 
			
		|||
    */
 | 
			
		||||
 | 
			
		||||
    'locale' => env('APP_LANG', 'en'),
 | 
			
		||||
    'locales' => ['en', 'ar', 'de', 'es', 'es_AR', 'fr', 'nl', 'pt_BR', 'sk', 'sv', 'ja', 'pl', 'it', 'ru', 'zh_CN', 'zh_TW'],
 | 
			
		||||
    'locales' => ['en', 'ar', 'de', 'es', 'es_AR', 'fr', 'nl', 'pt_BR', 'sk', 'sv', 'kr', 'ja', 'pl', 'it', 'ru', 'zh_CN', 'zh_TW'],
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    |--------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -274,10 +274,10 @@ return [
 | 
			
		|||
         * Custom
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        'Activity' => BookStack\Services\Facades\Activity::class,
 | 
			
		||||
        'Setting'  => BookStack\Services\Facades\Setting::class,
 | 
			
		||||
        'Views'    => BookStack\Services\Facades\Views::class,
 | 
			
		||||
        'Images'   => BookStack\Services\Facades\Images::class,
 | 
			
		||||
        'Activity' => BookStack\Facades\Activity::class,
 | 
			
		||||
        'Setting'  => BookStack\Facades\Setting::class,
 | 
			
		||||
        'Views'    => BookStack\Facades\Views::class,
 | 
			
		||||
        'Images'   => BookStack\Facades\Images::class,
 | 
			
		||||
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ return [
 | 
			
		|||
    'providers' => [
 | 
			
		||||
        'users' => [
 | 
			
		||||
            'driver' => env('AUTH_METHOD', 'standard') === 'standard' ? 'eloquent' : env('AUTH_METHOD'),
 | 
			
		||||
            'model' => BookStack\User::class,
 | 
			
		||||
            'model' => \BookStack\Auth\User::class,
 | 
			
		||||
        ],
 | 
			
		||||
 | 
			
		||||
        // 'users' => [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ return [
 | 
			
		|||
    ],
 | 
			
		||||
 | 
			
		||||
    'stripe'   => [
 | 
			
		||||
        'model'  => BookStack\User::class,
 | 
			
		||||
        'model'  => \BookStack\Auth\User::class,
 | 
			
		||||
        'key'    => '',
 | 
			
		||||
        'secret' => '',
 | 
			
		||||
    ],
 | 
			
		||||
| 
						 | 
				
			
			@ -59,6 +59,7 @@ return [
 | 
			
		|||
        'name'          => 'Google',
 | 
			
		||||
        'auto_register' => env('GOOGLE_AUTO_REGISTER', false),
 | 
			
		||||
        'auto_confirm' => env('GOOGLE_AUTO_CONFIRM_EMAIL', false),
 | 
			
		||||
        'select_account' => env('GOOGLE_SELECT_ACCOUNT', false),
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
    'slack'   => [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@
 | 
			
		|||
|
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
$factory->define(BookStack\User::class, function ($faker) {
 | 
			
		||||
$factory->define(\BookStack\Auth\User::class, function ($faker) {
 | 
			
		||||
    return [
 | 
			
		||||
        'name' => $faker->name,
 | 
			
		||||
        'email' => $faker->email,
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ $factory->define(BookStack\User::class, function ($faker) {
 | 
			
		|||
    ];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$factory->define(BookStack\Bookshelf::class, function ($faker) {
 | 
			
		||||
$factory->define(\BookStack\Entities\Bookshelf::class, function ($faker) {
 | 
			
		||||
    return [
 | 
			
		||||
        'name' => $faker->sentence,
 | 
			
		||||
        'slug' => str_random(10),
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +29,7 @@ $factory->define(BookStack\Bookshelf::class, function ($faker) {
 | 
			
		|||
    ];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$factory->define(BookStack\Book::class, function ($faker) {
 | 
			
		||||
$factory->define(\BookStack\Entities\Book::class, function ($faker) {
 | 
			
		||||
    return [
 | 
			
		||||
        'name' => $faker->sentence,
 | 
			
		||||
        'slug' => str_random(10),
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +37,7 @@ $factory->define(BookStack\Book::class, function ($faker) {
 | 
			
		|||
    ];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$factory->define(BookStack\Chapter::class, function ($faker) {
 | 
			
		||||
$factory->define(\BookStack\Entities\Chapter::class, function ($faker) {
 | 
			
		||||
    return [
 | 
			
		||||
        'name' => $faker->sentence,
 | 
			
		||||
        'slug' => str_random(10),
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ $factory->define(BookStack\Chapter::class, function ($faker) {
 | 
			
		|||
    ];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$factory->define(BookStack\Page::class, function ($faker) {
 | 
			
		||||
$factory->define(\BookStack\Entities\Page::class, function ($faker) {
 | 
			
		||||
    $html = '<p>' . implode('</p>', $faker->paragraphs(5)) . '</p>';
 | 
			
		||||
    return [
 | 
			
		||||
        'name' => $faker->sentence,
 | 
			
		||||
| 
						 | 
				
			
			@ -56,21 +56,21 @@ $factory->define(BookStack\Page::class, function ($faker) {
 | 
			
		|||
    ];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$factory->define(BookStack\Role::class, function ($faker) {
 | 
			
		||||
$factory->define(\BookStack\Auth\Role::class, function ($faker) {
 | 
			
		||||
    return [
 | 
			
		||||
        'display_name' => $faker->sentence(3),
 | 
			
		||||
        'description' => $faker->sentence(10)
 | 
			
		||||
    ];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$factory->define(BookStack\Tag::class, function ($faker) {
 | 
			
		||||
$factory->define(\BookStack\Actions\Tag::class, function ($faker) {
 | 
			
		||||
    return [
 | 
			
		||||
        'name' => $faker->city,
 | 
			
		||||
        'value' => $faker->sentence(3)
 | 
			
		||||
    ];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$factory->define(BookStack\Image::class, function ($faker) {
 | 
			
		||||
$factory->define(\BookStack\Uploads\Image::class, function ($faker) {
 | 
			
		||||
    return [
 | 
			
		||||
        'name' => $faker->slug . '.jpg',
 | 
			
		||||
        'url' => $faker->url,
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +80,7 @@ $factory->define(BookStack\Image::class, function ($faker) {
 | 
			
		|||
    ];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$factory->define(BookStack\Comment::class, function($faker) {
 | 
			
		||||
$factory->define(\BookStack\Actions\Comment::class, function($faker) {
 | 
			
		||||
    $text = $faker->paragraph(1);
 | 
			
		||||
    $html = '<p>' . $text. '</p>';
 | 
			
		||||
    return [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
use BookStack\Image;
 | 
			
		||||
use BookStack\Uploads\Image;
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -119,11 +119,11 @@ class CreateBookshelvesTable extends Migration
 | 
			
		|||
        Schema::dropIfExists('bookshelves');
 | 
			
		||||
 | 
			
		||||
        // Drop related polymorphic items
 | 
			
		||||
        DB::table('activities')->where('entity_type', '=', 'BookStack\Bookshelf')->delete();
 | 
			
		||||
        DB::table('views')->where('viewable_type', '=', 'BookStack\Bookshelf')->delete();
 | 
			
		||||
        DB::table('entity_permissions')->where('restrictable_type', '=', 'BookStack\Bookshelf')->delete();
 | 
			
		||||
        DB::table('tags')->where('entity_type', '=', 'BookStack\Bookshelf')->delete();
 | 
			
		||||
        DB::table('search_terms')->where('entity_type', '=', 'BookStack\Bookshelf')->delete();
 | 
			
		||||
        DB::table('comments')->where('entity_type', '=', 'BookStack\Bookshelf')->delete();
 | 
			
		||||
        DB::table('activities')->where('entity_type', '=', 'BookStack\Entities\Bookshelf')->delete();
 | 
			
		||||
        DB::table('views')->where('viewable_type', '=', 'BookStack\Entities\Bookshelf')->delete();
 | 
			
		||||
        DB::table('entity_permissions')->where('restrictable_type', '=', 'BookStack\Entities\Bookshelf')->delete();
 | 
			
		||||
        DB::table('tags')->where('entity_type', '=', 'BookStack\Entities\Bookshelf')->delete();
 | 
			
		||||
        DB::table('search_terms')->where('entity_type', '=', 'BookStack\Entities\Bookshelf')->delete();
 | 
			
		||||
        DB::table('comments')->where('entity_type', '=', 'BookStack\Entities\Bookshelf')->delete();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,39 +12,39 @@ class DummyContentSeeder extends Seeder
 | 
			
		|||
    public function run()
 | 
			
		||||
    {
 | 
			
		||||
        // Create an editor user
 | 
			
		||||
        $editorUser = factory(\BookStack\User::class)->create();
 | 
			
		||||
        $editorRole = \BookStack\Role::getRole('editor');
 | 
			
		||||
        $editorUser = factory(\BookStack\Auth\User::class)->create();
 | 
			
		||||
        $editorRole = \BookStack\Auth\Role::getRole('editor');
 | 
			
		||||
        $editorUser->attachRole($editorRole);
 | 
			
		||||
 | 
			
		||||
        // Create a viewer user
 | 
			
		||||
        $viewerUser = factory(\BookStack\User::class)->create();
 | 
			
		||||
        $role = \BookStack\Role::getRole('viewer');
 | 
			
		||||
        $viewerUser = factory(\BookStack\Auth\User::class)->create();
 | 
			
		||||
        $role = \BookStack\Auth\Role::getRole('viewer');
 | 
			
		||||
        $viewerUser->attachRole($role);
 | 
			
		||||
 | 
			
		||||
        $byData = ['created_by' => $editorUser->id, 'updated_by' => $editorUser->id];
 | 
			
		||||
 | 
			
		||||
        factory(\BookStack\Book::class, 5)->create($byData)
 | 
			
		||||
        factory(\BookStack\Entities\Book::class, 5)->create($byData)
 | 
			
		||||
            ->each(function($book) use ($editorUser, $byData) {
 | 
			
		||||
                $chapters = factory(\BookStack\Chapter::class, 3)->create($byData)
 | 
			
		||||
                $chapters = factory(\BookStack\Entities\Chapter::class, 3)->create($byData)
 | 
			
		||||
                    ->each(function($chapter) use ($editorUser, $book, $byData){
 | 
			
		||||
                        $pages = factory(\BookStack\Page::class, 3)->make(array_merge($byData, ['book_id' => $book->id]));
 | 
			
		||||
                        $pages = factory(\BookStack\Entities\Page::class, 3)->make(array_merge($byData, ['book_id' => $book->id]));
 | 
			
		||||
                        $chapter->pages()->saveMany($pages);
 | 
			
		||||
                    });
 | 
			
		||||
                $pages = factory(\BookStack\Page::class, 3)->make($byData);
 | 
			
		||||
                $pages = factory(\BookStack\Entities\Page::class, 3)->make($byData);
 | 
			
		||||
                $book->chapters()->saveMany($chapters);
 | 
			
		||||
                $book->pages()->saveMany($pages);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        $largeBook = factory(\BookStack\Book::class)->create(array_merge($byData, ['name' => 'Large book' . str_random(10)]));
 | 
			
		||||
        $pages = factory(\BookStack\Page::class, 200)->make($byData);
 | 
			
		||||
        $chapters = factory(\BookStack\Chapter::class, 50)->make($byData);
 | 
			
		||||
        $largeBook = factory(\BookStack\Entities\Book::class)->create(array_merge($byData, ['name' => 'Large book' . str_random(10)]));
 | 
			
		||||
        $pages = factory(\BookStack\Entities\Page::class, 200)->make($byData);
 | 
			
		||||
        $chapters = factory(\BookStack\Entities\Chapter::class, 50)->make($byData);
 | 
			
		||||
        $largeBook->pages()->saveMany($pages);
 | 
			
		||||
        $largeBook->chapters()->saveMany($chapters);
 | 
			
		||||
 | 
			
		||||
        $shelves = factory(\BookStack\Bookshelf::class, 10)->create($byData);
 | 
			
		||||
        $shelves = factory(\BookStack\Entities\Bookshelf::class, 10)->create($byData);
 | 
			
		||||
        $largeBook->shelves()->attach($shelves->pluck('id'));
 | 
			
		||||
 | 
			
		||||
        app(\BookStack\Services\PermissionService::class)->buildJointPermissions();
 | 
			
		||||
        app(\BookStack\Services\SearchService::class)->indexAllEntities();
 | 
			
		||||
        app(\BookStack\Auth\Permissions\PermissionService::class)->buildJointPermissions();
 | 
			
		||||
        app(\BookStack\Entities\SearchService::class)->indexAllEntities();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,16 +12,16 @@ class LargeContentSeeder extends Seeder
 | 
			
		|||
    public function run()
 | 
			
		||||
    {
 | 
			
		||||
        // Create an editor user
 | 
			
		||||
        $editorUser = factory(\BookStack\User::class)->create();
 | 
			
		||||
        $editorRole = \BookStack\Role::getRole('editor');
 | 
			
		||||
        $editorUser = factory(\BookStack\Auth\User::class)->create();
 | 
			
		||||
        $editorRole = \BookStack\Auth\Role::getRole('editor');
 | 
			
		||||
        $editorUser->attachRole($editorRole);
 | 
			
		||||
 | 
			
		||||
        $largeBook = factory(\BookStack\Book::class)->create(['name' => 'Large book' . str_random(10), 'created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
 | 
			
		||||
        $pages = factory(\BookStack\Page::class, 200)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
 | 
			
		||||
        $chapters = factory(\BookStack\Chapter::class, 50)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
 | 
			
		||||
        $largeBook = factory(\BookStack\Entities\Book::class)->create(['name' => 'Large book' . str_random(10), 'created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
 | 
			
		||||
        $pages = factory(\BookStack\Entities\Page::class, 200)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
 | 
			
		||||
        $chapters = factory(\BookStack\Entities\Chapter::class, 50)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
 | 
			
		||||
        $largeBook->pages()->saveMany($pages);
 | 
			
		||||
        $largeBook->chapters()->saveMany($chapters);
 | 
			
		||||
        app(\BookStack\Services\PermissionService::class)->buildJointPermissions();
 | 
			
		||||
        app(\BookStack\Services\SearchService::class)->indexAllEntities();
 | 
			
		||||
        app(\BookStack\Auth\Permissions\PermissionService::class)->buildJointPermissions();
 | 
			
		||||
        app(\BookStack\Entities\SearchService::class)->indexAllEntities();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										40
									
								
								package.json
								
								
								
								
							
							
						
						
									
										40
									
								
								package.json
								
								
								
								
							| 
						 | 
				
			
			@ -10,34 +10,34 @@
 | 
			
		|||
    "permissions": "chown -R $USER:$USER bootstrap/cache storage public/uploads"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@babel/core": "^7.0.0-beta.40",
 | 
			
		||||
    "@babel/polyfill": "^7.0.0-beta.40",
 | 
			
		||||
    "@babel/preset-env": "^7.0.0-beta.40",
 | 
			
		||||
    "autoprefixer": "^8.1.0",
 | 
			
		||||
    "babel-loader": "^8.0.0-beta.0",
 | 
			
		||||
    "css-loader": "^0.28.10",
 | 
			
		||||
    "@babel/core": "^7.1.5",
 | 
			
		||||
    "@babel/polyfill": "^7.0.0",
 | 
			
		||||
    "@babel/preset-env": "^7.1.5",
 | 
			
		||||
    "autoprefixer": "^8.6.5",
 | 
			
		||||
    "babel-loader": "^8.0.4",
 | 
			
		||||
    "css-loader": "^0.28.11",
 | 
			
		||||
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
 | 
			
		||||
    "livereload": "^0.7.0",
 | 
			
		||||
    "node-sass": "^4.9.2",
 | 
			
		||||
    "npm-run-all": "^4.1.2",
 | 
			
		||||
    "postcss-loader": "^2.1.1",
 | 
			
		||||
    "sass-loader": "^7.0.1",
 | 
			
		||||
    "node-sass": "^4.10.0",
 | 
			
		||||
    "npm-run-all": "^4.1.3",
 | 
			
		||||
    "postcss-loader": "^2.1.6",
 | 
			
		||||
    "sass-loader": "^7.1.0",
 | 
			
		||||
    "style-loader": "^0.21.0",
 | 
			
		||||
    "uglifyjs-webpack-plugin": "^1.2.3",
 | 
			
		||||
    "webpack": "^4.16.3",
 | 
			
		||||
    "webpack-cli": "^2.0.11"
 | 
			
		||||
    "uglifyjs-webpack-plugin": "^1.3.0",
 | 
			
		||||
    "webpack": "^4.25.1",
 | 
			
		||||
    "webpack-cli": "^3.1.2"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "axios": "^0.18.0",
 | 
			
		||||
    "clipboard": "^2.0.0",
 | 
			
		||||
    "codemirror": "^5.26.0",
 | 
			
		||||
    "dropzone": "^5.4.0",
 | 
			
		||||
    "clipboard": "^2.0.1",
 | 
			
		||||
    "codemirror": "^5.41.0",
 | 
			
		||||
    "dropzone": "^5.5.1",
 | 
			
		||||
    "jquery": "^3.3.1",
 | 
			
		||||
    "jquery-sortable": "^0.9.13",
 | 
			
		||||
    "markdown-it": "^8.3.1",
 | 
			
		||||
    "markdown-it-task-lists": "^2.0.0",
 | 
			
		||||
    "vue": "^2.2.6",
 | 
			
		||||
    "vuedraggable": "^2.14.1"
 | 
			
		||||
    "markdown-it": "^8.4.2",
 | 
			
		||||
    "markdown-it-task-lists": "^2.1.1",
 | 
			
		||||
    "vue": "^2.5.17",
 | 
			
		||||
    "vuedraggable": "^2.16.0"
 | 
			
		||||
  },
 | 
			
		||||
  "browser": {
 | 
			
		||||
    "vue": "vue/dist/vue.common.js"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,6 +41,8 @@
 | 
			
		|||
        <env name="GOOGLE_APP_SECRET" value="aaaaaaaaaaaaaa"/>
 | 
			
		||||
        <env name="GOOGLE_AUTO_REGISTER" value=""/>
 | 
			
		||||
        <env name="GOOGLE_AUTO_CONFIRM_EMAIL" value=""/>
 | 
			
		||||
        <env name="GOOGLE_SELECT_ACCOUNT" value=""/>
 | 
			
		||||
        <env name="APP_URL" value="http://bookstack.dev"/>
 | 
			
		||||
        <env name="DEBUGBAR_ENABLED" value="false"/>
 | 
			
		||||
    </php>
 | 
			
		||||
</phpunit>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,4 +56,4 @@ class BackToTop {
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = BackToTop;
 | 
			
		||||
export default BackToTop;
 | 
			
		||||
| 
						 | 
				
			
			@ -69,4 +69,4 @@ class ChapterToggle {
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = ChapterToggle;
 | 
			
		||||
export default ChapterToggle;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,4 +34,4 @@ class Collapsible {
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = Collapsible;
 | 
			
		||||
export default Collapsible;
 | 
			
		||||
| 
						 | 
				
			
			@ -45,4 +45,4 @@ class DropDown {
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = DropDown;
 | 
			
		||||
export default DropDown;
 | 
			
		||||
| 
						 | 
				
			
			@ -44,4 +44,4 @@ class EditorToolbox {
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = EditorToolbox;
 | 
			
		||||
export default EditorToolbox;
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue