mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-05-07 01:30:06 +00:00
Set /app PHP code to PSR-2 standard
Also adde draw.io to attribution list. Closes #649
This commit is contained in:
parent
30b4f81fc6
commit
62342433f4
80 changed files with 593 additions and 335 deletions
app
Activity.phpAttachment.phpBook.phpChapter.phpModel.php
composer.jsoncomposer.lockphpcs.xmlreadme.mdConsole/Commands
Entity.phpEntityPermission.phpExceptions
AuthException.phpConfirmationEmailException.phpFileUploadException.phpHandler.phpImageUploadException.phpLdapException.phpNotFoundException.phpNotifyException.phpPermissionsException.phpPrettyException.phpSocialDriverNotConfigured.phpSocialSignInException.phpUserRegistrationException.php
Http
Controllers
Auth
BookController.phpChapterController.phpController.phpHomeController.phpImageController.phpPageController.phpPermissionController.phpSearchController.phpSettingController.phpTagController.phpUserController.phpMiddleware
Notifications
Ownable.phpPage.phpPageRevision.phpProviders
AppServiceProvider.phpAuthServiceProvider.phpCustomFacadeProvider.phpLdapUserProvider.phpPaginationServiceProvider.php
Repos
Role.phpRolePermission.phpSearchTerm.phpServices
ActivityService.phpAttachmentService.phpEmailConfirmationService.phpExportService.php
SocialAccount.phpTag.phpUser.phphelpers.phpFacades
ImageService.phpLdap.phpLdapService.phpPermissionService.phpSearchService.phpSettingService.phpSocialAuthService.phpUploadService.phpViewService.php
|
@ -16,7 +16,9 @@ class Activity extends Model
|
||||||
*/
|
*/
|
||||||
public function entity()
|
public function entity()
|
||||||
{
|
{
|
||||||
if ($this->entity_type === '') $this->entity_type = null;
|
if ($this->entity_type === '') {
|
||||||
|
$this->entity_type = null;
|
||||||
|
}
|
||||||
return $this->morphTo('entity');
|
return $this->morphTo('entity');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,8 +45,8 @@ class Activity extends Model
|
||||||
* @param $activityB
|
* @param $activityB
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isSimilarTo($activityB) {
|
public function isSimilarTo($activityB)
|
||||||
|
{
|
||||||
return [$this->key, $this->entity_type, $this->entity_id] === [$activityB->key, $activityB->entity_type, $activityB->entity_id];
|
return [$this->key, $this->entity_type, $this->entity_id] === [$activityB->key, $activityB->entity_type, $activityB->entity_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack;
|
<?php namespace BookStack;
|
||||||
|
|
||||||
|
|
||||||
class Attachment extends Ownable
|
class Attachment extends Ownable
|
||||||
{
|
{
|
||||||
protected $fillable = ['name', 'order'];
|
protected $fillable = ['name', 'order'];
|
||||||
|
@ -11,7 +10,9 @@ class Attachment extends Ownable
|
||||||
*/
|
*/
|
||||||
public function getFileName()
|
public function getFileName()
|
||||||
{
|
{
|
||||||
if (str_contains($this->name, '.')) return $this->name;
|
if (str_contains($this->name, '.')) {
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
return $this->name . '.' . $this->extension;
|
return $this->name . '.' . $this->extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,5 +33,4 @@ class Attachment extends Ownable
|
||||||
{
|
{
|
||||||
return baseUrl('/attachments/' . $this->id);
|
return baseUrl('/attachments/' . $this->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,9 @@ class Book extends Entity
|
||||||
public function getBookCover($width = 440, $height = 250)
|
public function getBookCover($width = 440, $height = 250)
|
||||||
{
|
{
|
||||||
$default = baseUrl('/book_default_cover.png');
|
$default = baseUrl('/book_default_cover.png');
|
||||||
if (!$this->image_id) return $default;
|
if (!$this->image_id) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$cover = $this->cover ? baseUrl($this->cover->getThumb($width, $height, false)) : $default;
|
$cover = $this->cover ? baseUrl($this->cover->getThumb($width, $height, false)) : $default;
|
||||||
|
@ -91,5 +93,4 @@ class Book extends Entity
|
||||||
{
|
{
|
||||||
return "'BookStack\\\\Book' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text,'' as html, '0' as book_id, '0' as priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at";
|
return "'BookStack\\\\Book' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text,'' as html, '0' as book_id, '0' as priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack;
|
<?php namespace BookStack;
|
||||||
|
|
||||||
|
|
||||||
class Chapter extends Entity
|
class Chapter extends Entity
|
||||||
{
|
{
|
||||||
protected $fillable = ['name', 'description', 'priority', 'book_id'];
|
protected $fillable = ['name', 'description', 'priority', 'book_id'];
|
||||||
|
@ -59,5 +58,4 @@ class Chapter extends Entity
|
||||||
{
|
{
|
||||||
return "'BookStack\\\\Chapter' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text, '' as html, book_id, priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at";
|
return "'BookStack\\\\Chapter' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text, '' as html, book_id, priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,8 @@ use BookStack\User;
|
||||||
use BookStack\Repos\UserRepo;
|
use BookStack\Repos\UserRepo;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class DeleteUsers extends Command{
|
class DeleteUsers extends Command
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* The name and signature of the console command.
|
||||||
|
@ -37,14 +38,11 @@ class DeleteUsers extends Command{
|
||||||
{
|
{
|
||||||
$confirm = $this->ask('This will delete all users from the system that are not "admin" or system users. Are you sure you want to continue? (Type "yes" to continue)');
|
$confirm = $this->ask('This will delete all users from the system that are not "admin" or system users. Are you sure you want to continue? (Type "yes" to continue)');
|
||||||
$numDeleted = 0;
|
$numDeleted = 0;
|
||||||
if (strtolower(trim($confirm)) === 'yes')
|
if (strtolower(trim($confirm)) === 'yes') {
|
||||||
{
|
|
||||||
$totalUsers = $this->user->count();
|
$totalUsers = $this->user->count();
|
||||||
$users = $this->user->where('system_name', '=', null)->with('roles')->get();
|
$users = $this->user->where('system_name', '=', null)->with('roles')->get();
|
||||||
foreach ($users as $user)
|
foreach ($users as $user) {
|
||||||
{
|
if ($user->hasSystemRole('admin')) {
|
||||||
if ($user->hasSystemRole('admin'))
|
|
||||||
{
|
|
||||||
// don't delete users with "admin" role
|
// don't delete users with "admin" role
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -52,11 +50,8 @@ class DeleteUsers extends Command{
|
||||||
++$numDeleted;
|
++$numDeleted;
|
||||||
}
|
}
|
||||||
$this->info("Deleted $numDeleted of $totalUsers total users.");
|
$this->info("Deleted $numDeleted of $totalUsers total users.");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->info('Exiting...');
|
$this->info('Exiting...');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack;
|
<?php namespace BookStack;
|
||||||
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||||
|
|
||||||
class Entity extends Ownable
|
class Entity extends Ownable
|
||||||
|
@ -28,7 +27,9 @@ class Entity extends Ownable
|
||||||
{
|
{
|
||||||
$matches = [get_class($this), $this->id] === [get_class($entity), $entity->id];
|
$matches = [get_class($this), $this->id] === [get_class($entity), $entity->id];
|
||||||
|
|
||||||
if ($matches) return true;
|
if ($matches) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (($entity->isA('chapter') || $entity->isA('page')) && $this->isA('book')) {
|
if (($entity->isA('chapter') || $entity->isA('page')) && $this->isA('book')) {
|
||||||
return $entity->book_id === $this->id;
|
return $entity->book_id === $this->id;
|
||||||
|
@ -159,7 +160,9 @@ class Entity extends Ownable
|
||||||
*/
|
*/
|
||||||
public function getShortName($length = 25)
|
public function getShortName($length = 25)
|
||||||
{
|
{
|
||||||
if (strlen($this->name) <= $length) return $this->name;
|
if (strlen($this->name) <= $length) {
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
return substr($this->name, 0, $length - 3) . '...';
|
return substr($this->name, 0, $length - 3) . '...';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,13 +179,18 @@ class Entity extends Ownable
|
||||||
* Return a generalised, common raw query that can be 'unioned' across entities.
|
* Return a generalised, common raw query that can be 'unioned' across entities.
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function entityRawQuery(){return '';}
|
public function entityRawQuery()
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the url of this entity
|
* Get the url of this entity
|
||||||
* @param $path
|
* @param $path
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getUrl($path){return '/';}
|
public function getUrl($path)
|
||||||
|
{
|
||||||
|
return '/';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack;
|
<?php namespace BookStack;
|
||||||
|
|
||||||
|
|
||||||
class EntityPermission extends Model
|
class EntityPermission extends Model
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?php namespace BookStack\Exceptions;
|
<?php namespace BookStack\Exceptions;
|
||||||
|
|
||||||
|
class AuthException extends PrettyException
|
||||||
|
{
|
||||||
|
|
||||||
class AuthException extends PrettyException {}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?php namespace BookStack\Exceptions;
|
<?php namespace BookStack\Exceptions;
|
||||||
|
|
||||||
|
class ConfirmationEmailException extends NotifyException
|
||||||
|
{
|
||||||
|
|
||||||
class ConfirmationEmailException extends NotifyException {}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?php namespace BookStack\Exceptions;
|
<?php namespace BookStack\Exceptions;
|
||||||
|
|
||||||
|
class FileUploadException extends PrettyException
|
||||||
|
{
|
||||||
|
|
||||||
class FileUploadException extends PrettyException {}
|
}
|
||||||
|
|
|
@ -95,9 +95,12 @@ class Handler extends ExceptionHandler
|
||||||
* @param $type
|
* @param $type
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function isExceptionType(Exception $e, $type) {
|
protected function isExceptionType(Exception $e, $type)
|
||||||
|
{
|
||||||
do {
|
do {
|
||||||
if (is_a($e, $type)) return true;
|
if (is_a($e, $type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} while ($e = $e->getPrevious());
|
} while ($e = $e->getPrevious());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -107,7 +110,8 @@ class Handler extends ExceptionHandler
|
||||||
* @param Exception $e
|
* @param Exception $e
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function getOriginalMessage(Exception $e) {
|
protected function getOriginalMessage(Exception $e)
|
||||||
|
{
|
||||||
do {
|
do {
|
||||||
$message = $e->getMessage();
|
$message = $e->getMessage();
|
||||||
} while ($e = $e->getPrevious());
|
} while ($e = $e->getPrevious());
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
<?php namespace BookStack\Exceptions;
|
<?php namespace BookStack\Exceptions;
|
||||||
|
|
||||||
class ImageUploadException extends PrettyException {}
|
class ImageUploadException extends PrettyException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
<?php namespace BookStack\Exceptions;
|
<?php namespace BookStack\Exceptions;
|
||||||
|
|
||||||
class LdapException extends PrettyException {}
|
class LdapException extends PrettyException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php namespace BookStack\Exceptions;
|
<?php namespace BookStack\Exceptions;
|
||||||
|
|
||||||
|
class NotFoundException extends PrettyException
|
||||||
class NotFoundException extends PrettyException {
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NotFoundException constructor.
|
* NotFoundException constructor.
|
||||||
|
@ -11,4 +11,4 @@ class NotFoundException extends PrettyException {
|
||||||
{
|
{
|
||||||
parent::__construct($message, 404);
|
parent::__construct($message, 404);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack\Exceptions;
|
<?php namespace BookStack\Exceptions;
|
||||||
|
|
||||||
|
|
||||||
class NotifyException extends \Exception
|
class NotifyException extends \Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -18,4 +17,4 @@ class NotifyException extends \Exception
|
||||||
$this->redirectLocation = $redirectLocation;
|
$this->redirectLocation = $redirectLocation;
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<?php namespace BookStack\Exceptions;
|
<?php namespace BookStack\Exceptions;
|
||||||
|
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class PermissionsException extends Exception {}
|
class PermissionsException extends Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
<?php namespace BookStack\Exceptions;
|
<?php namespace BookStack\Exceptions;
|
||||||
|
|
||||||
class PrettyException extends \Exception {}
|
class PrettyException extends \Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?php namespace BookStack\Exceptions;
|
<?php namespace BookStack\Exceptions;
|
||||||
|
|
||||||
|
class SocialDriverNotConfigured extends PrettyException
|
||||||
|
{
|
||||||
|
|
||||||
class SocialDriverNotConfigured extends PrettyException {}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?php namespace BookStack\Exceptions;
|
<?php namespace BookStack\Exceptions;
|
||||||
|
|
||||||
|
class SocialSignInException extends NotifyException
|
||||||
|
{
|
||||||
|
|
||||||
class SocialSignInException extends NotifyException {}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?php namespace BookStack\Exceptions;
|
<?php namespace BookStack\Exceptions;
|
||||||
|
|
||||||
|
class UserRegistrationException extends NotifyException
|
||||||
|
{
|
||||||
|
|
||||||
class UserRegistrationException extends NotifyException {}
|
}
|
||||||
|
|
|
@ -64,5 +64,4 @@ class ForgotPasswordController extends Controller
|
||||||
['email' => trans($response)]
|
['email' => trans($response)]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -70,7 +70,9 @@ class LoginController extends Controller
|
||||||
protected function authenticated(Request $request, Authenticatable $user)
|
protected function authenticated(Request $request, Authenticatable $user)
|
||||||
{
|
{
|
||||||
// Explicitly log them out for now if they do no exist.
|
// Explicitly log them out for now if they do no exist.
|
||||||
if (!$user->exists) auth()->logout($user);
|
if (!$user->exists) {
|
||||||
|
auth()->logout($user);
|
||||||
|
}
|
||||||
|
|
||||||
if (!$user->exists && $user->email === null && !$request->filled('email')) {
|
if (!$user->exists && $user->email === null && !$request->filled('email')) {
|
||||||
$request->flash();
|
$request->flash();
|
||||||
|
@ -83,7 +85,6 @@ class LoginController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$user->exists) {
|
if (!$user->exists) {
|
||||||
|
|
||||||
// Check for users with same email already
|
// Check for users with same email already
|
||||||
$alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0;
|
$alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0;
|
||||||
if ($alreadyUser) {
|
if ($alreadyUser) {
|
||||||
|
@ -130,4 +131,4 @@ class LoginController extends Controller
|
||||||
session()->put('social-callback', 'login');
|
session()->put('social-callback', 'login');
|
||||||
return $this->socialAuthService->startLogIn($socialDriver);
|
return $this->socialAuthService->startLogIn($socialDriver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,8 @@ class RegisterController extends Controller
|
||||||
|
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
$this->throwValidationException(
|
$this->throwValidationException(
|
||||||
$request, $validator
|
$request,
|
||||||
|
$validator
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,8 +273,12 @@ class RegisterController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
$action = session()->pull('social-callback');
|
$action = session()->pull('social-callback');
|
||||||
if ($action == 'login') return $this->socialAuthService->handleLoginCallback($socialDriver);
|
if ($action == 'login') {
|
||||||
if ($action == 'register') return $this->socialRegisterCallback($socialDriver);
|
return $this->socialAuthService->handleLoginCallback($socialDriver);
|
||||||
|
}
|
||||||
|
if ($action == 'register') {
|
||||||
|
return $this->socialRegisterCallback($socialDriver);
|
||||||
|
}
|
||||||
return redirect()->back();
|
return redirect()->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,5 +313,4 @@ class RegisterController extends Controller
|
||||||
];
|
];
|
||||||
return $this->registerUser($userData, $socialAccount);
|
return $this->registerUser($userData, $socialAccount);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -46,4 +46,4 @@ class ResetPasswordController extends Controller
|
||||||
return redirect($this->redirectPath())
|
return redirect($this->redirectPath())
|
||||||
->with('status', trans($response));
|
->with('status', trans($response));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ class BookController extends Controller
|
||||||
{
|
{
|
||||||
$book = $this->entityRepo->getBySlug('book', $slug);
|
$book = $this->entityRepo->getBySlug('book', $slug);
|
||||||
$this->checkOwnablePermission('book-update', $book);
|
$this->checkOwnablePermission('book-update', $book);
|
||||||
$this->setPageTitle(trans('entities.books_edit_named',['bookName'=>$book->getShortName()]));
|
$this->setPageTitle(trans('entities.books_edit_named', ['bookName'=>$book->getShortName()]));
|
||||||
return view('books/edit', ['book' => $book, 'current' => $book]);
|
return view('books/edit', ['book' => $book, 'current' => $book]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ class BookController extends Controller
|
||||||
$bookIdsInvolved = collect([$book->id]);
|
$bookIdsInvolved = collect([$book->id]);
|
||||||
|
|
||||||
// Load models into map
|
// Load models into map
|
||||||
$sortMap->each(function($mapItem) use ($bookIdsInvolved) {
|
$sortMap->each(function ($mapItem) use ($bookIdsInvolved) {
|
||||||
$mapItem->type = ($mapItem->type === 'page' ? 'page' : 'chapter');
|
$mapItem->type = ($mapItem->type === 'page' ? 'page' : 'chapter');
|
||||||
$mapItem->model = $this->entityRepo->getById($mapItem->type, $mapItem->id);
|
$mapItem->model = $this->entityRepo->getById($mapItem->type, $mapItem->id);
|
||||||
// Store source and target books
|
// Store source and target books
|
||||||
|
@ -210,12 +210,12 @@ class BookController extends Controller
|
||||||
$this->showPermissionError();
|
$this->showPermissionError();
|
||||||
}
|
}
|
||||||
// Check permissions of involved books
|
// Check permissions of involved books
|
||||||
$booksInvolved->each(function(Book $book) {
|
$booksInvolved->each(function (Book $book) {
|
||||||
$this->checkOwnablePermission('book-update', $book);
|
$this->checkOwnablePermission('book-update', $book);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Perform the sort
|
// Perform the sort
|
||||||
$sortMap->each(function($mapItem) {
|
$sortMap->each(function ($mapItem) {
|
||||||
$model = $mapItem->model;
|
$model = $mapItem->model;
|
||||||
|
|
||||||
$priorityChanged = intval($model->priority) !== intval($mapItem->sort);
|
$priorityChanged = intval($model->priority) !== intval($mapItem->sort);
|
||||||
|
@ -236,7 +236,7 @@ class BookController extends Controller
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rebuild permissions and add activity for involved books.
|
// Rebuild permissions and add activity for involved books.
|
||||||
$booksInvolved->each(function(Book $book) {
|
$booksInvolved->each(function (Book $book) {
|
||||||
$this->entityRepo->buildJointPermissionsForBook($book);
|
$this->entityRepo->buildJointPermissionsForBook($book);
|
||||||
Activity::add($book, 'book_sort', $book->id);
|
Activity::add($book, 'book_sort', $book->id);
|
||||||
});
|
});
|
||||||
|
|
|
@ -159,7 +159,8 @@ class ChapterController extends Controller
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws \BookStack\Exceptions\NotFoundException
|
* @throws \BookStack\Exceptions\NotFoundException
|
||||||
*/
|
*/
|
||||||
public function showMove($bookSlug, $chapterSlug) {
|
public function showMove($bookSlug, $chapterSlug)
|
||||||
|
{
|
||||||
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()]));
|
$this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()]));
|
||||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||||
|
@ -177,7 +178,8 @@ class ChapterController extends Controller
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws \BookStack\Exceptions\NotFoundException
|
* @throws \BookStack\Exceptions\NotFoundException
|
||||||
*/
|
*/
|
||||||
public function move($bookSlug, $chapterSlug, Request $request) {
|
public function move($bookSlug, $chapterSlug, Request $request)
|
||||||
|
{
|
||||||
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,9 @@ abstract class Controller extends BaseController
|
||||||
*/
|
*/
|
||||||
protected function preventAccessForDemoUsers()
|
protected function preventAccessForDemoUsers()
|
||||||
{
|
{
|
||||||
if (config('app.env') === 'demo') $this->showPermissionError();
|
if (config('app.env') === 'demo') {
|
||||||
|
$this->showPermissionError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,7 +102,9 @@ abstract class Controller extends BaseController
|
||||||
*/
|
*/
|
||||||
protected function checkOwnablePermission($permission, Ownable $ownable)
|
protected function checkOwnablePermission($permission, Ownable $ownable)
|
||||||
{
|
{
|
||||||
if (userCan($permission, $ownable)) return true;
|
if (userCan($permission, $ownable)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return $this->showPermissionError();
|
return $this->showPermissionError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +117,9 @@ abstract class Controller extends BaseController
|
||||||
protected function checkPermissionOr($permissionName, $callback)
|
protected function checkPermissionOr($permissionName, $callback)
|
||||||
{
|
{
|
||||||
$callbackResult = $callback();
|
$callbackResult = $callback();
|
||||||
if ($callbackResult === false) $this->checkPermission($permissionName);
|
if ($callbackResult === false) {
|
||||||
|
$this->checkPermission($permissionName);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,5 +151,4 @@ abstract class Controller extends BaseController
|
||||||
->withInput($request->input())
|
->withInput($request->input())
|
||||||
->withErrors($errors, $this->errorBag());
|
->withErrors($errors, $this->errorBag());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,8 @@ class HomeController extends Controller
|
||||||
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
|
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function getTranslations() {
|
public function getTranslations()
|
||||||
|
{
|
||||||
$locale = app()->getLocale();
|
$locale = app()->getLocale();
|
||||||
$cacheKey = 'GLOBAL_TRANSLATIONS_' . $locale;
|
$cacheKey = 'GLOBAL_TRANSLATIONS_' . $locale;
|
||||||
if (cache()->has($cacheKey) && config('app.env') !== 'development') {
|
if (cache()->has($cacheKey) && config('app.env') !== 'development') {
|
||||||
|
@ -95,5 +96,4 @@ class HomeController extends Controller
|
||||||
{
|
{
|
||||||
return view('partials/custom-head-content');
|
return view('partials/custom-head-content');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,14 +63,14 @@ class ImageController extends Controller
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function searchByType($type, $page = 0, Request $request)
|
public function searchByType(Request $request, $type, $page = 0)
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'term' => 'required|string'
|
'term' => 'required|string'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$searchTerm = $request->get('term');
|
$searchTerm = $request->get('term');
|
||||||
$imgData = $this->imageRepo->searchPaginatedByType($type, $page, 24, $searchTerm);
|
$imgData = $this->imageRepo->searchPaginatedByType($type, $searchTerm, $page, 24);
|
||||||
return response()->json($imgData);
|
return response()->json($imgData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,17 +92,19 @@ class ImageController extends Controller
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
|
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
|
||||||
*/
|
*/
|
||||||
public function getGalleryFiltered($filter, $page = 0, Request $request)
|
public function getGalleryFiltered(Request $request, $filter, $page = 0)
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'page_id' => 'required|integer'
|
'page_id' => 'required|integer'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$validFilters = collect(['page', 'book']);
|
$validFilters = collect(['page', 'book']);
|
||||||
if (!$validFilters->contains($filter)) return response('Invalid filter', 500);
|
if (!$validFilters->contains($filter)) {
|
||||||
|
return response('Invalid filter', 500);
|
||||||
|
}
|
||||||
|
|
||||||
$pageId = $request->get('page_id');
|
$pageId = $request->get('page_id');
|
||||||
$imgData = $this->imageRepo->getGalleryFiltered($page, 24, strtolower($filter), $pageId);
|
$imgData = $this->imageRepo->getGalleryFiltered(strtolower($filter), $pageId, $page, 24);
|
||||||
|
|
||||||
return response()->json($imgData);
|
return response()->json($imgData);
|
||||||
}
|
}
|
||||||
|
@ -265,6 +267,4 @@ class ImageController extends Controller
|
||||||
$this->imageRepo->destroyImage($image);
|
$this->imageRepo->destroyImage($image);
|
||||||
return response()->json(trans('components.images_deleted'));
|
return response()->json(trans('components.images_deleted'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,9 @@ class PageController extends Controller
|
||||||
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
} catch (NotFoundException $e) {
|
} catch (NotFoundException $e) {
|
||||||
$page = $this->entityRepo->getPageByOldSlug($pageSlug, $bookSlug);
|
$page = $this->entityRepo->getPageByOldSlug($pageSlug, $bookSlug);
|
||||||
if ($page === null) throw $e;
|
if ($page === null) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
return redirect($page->getUrl());
|
return redirect($page->getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,7 +222,9 @@ class PageController extends Controller
|
||||||
$warnings [] = $this->entityRepo->getUserPageDraftMessage($draft);
|
$warnings [] = $this->entityRepo->getUserPageDraftMessage($draft);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($warnings) > 0) session()->flash('warning', implode("\n", $warnings));
|
if (count($warnings) > 0) {
|
||||||
|
session()->flash('warning', implode("\n", $warnings));
|
||||||
|
}
|
||||||
|
|
||||||
$draftsEnabled = $this->signedIn;
|
$draftsEnabled = $this->signedIn;
|
||||||
return view('pages/edit', [
|
return view('pages/edit', [
|
||||||
|
@ -604,5 +608,4 @@ class PageController extends Controller
|
||||||
session()->flash('success', trans('entities.pages_permissions_success'));
|
session()->flash('success', trans('entities.pages_permissions_success'));
|
||||||
return redirect($page->getUrl());
|
return redirect($page->getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,9 @@ class PermissionController extends Controller
|
||||||
{
|
{
|
||||||
$this->checkPermission('user-roles-manage');
|
$this->checkPermission('user-roles-manage');
|
||||||
$role = $this->permissionsRepo->getRoleById($id);
|
$role = $this->permissionsRepo->getRoleById($id);
|
||||||
if ($role->hidden) throw new PermissionsException(trans('errors.role_cannot_be_edited'));
|
if ($role->hidden) {
|
||||||
|
throw new PermissionsException(trans('errors.role_cannot_be_edited'));
|
||||||
|
}
|
||||||
return view('settings/roles/edit', ['role' => $role]);
|
return view('settings/roles/edit', ['role' => $role]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,4 @@ class SearchController extends Controller
|
||||||
|
|
||||||
return view('search/entity-ajax-list', ['entities' => $entities]);
|
return view('search/entity-ajax-list', ['entities' => $entities]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,9 @@ class SettingController extends Controller
|
||||||
|
|
||||||
// Cycles through posted settings and update them
|
// Cycles through posted settings and update them
|
||||||
foreach ($request->all() as $name => $value) {
|
foreach ($request->all() as $name => $value) {
|
||||||
if (strpos($name, 'setting-') !== 0) continue;
|
if (strpos($name, 'setting-') !== 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$key = str_replace('setting-', '', trim($name));
|
$key = str_replace('setting-', '', trim($name));
|
||||||
Setting::put($key, $value);
|
Setting::put($key, $value);
|
||||||
}
|
}
|
||||||
|
@ -41,5 +43,4 @@ class SettingController extends Controller
|
||||||
session()->flash('success', trans('settings.settings_save_success'));
|
session()->flash('success', trans('settings.settings_save_success'));
|
||||||
return redirect('/settings');
|
return redirect('/settings');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,5 +54,4 @@ class TagController extends Controller
|
||||||
$suggestions = $this->tagRepo->getValueSuggestions($searchTerm, $tagName);
|
$suggestions = $this->tagRepo->getValueSuggestions($searchTerm, $tagName);
|
||||||
return response()->json($suggestions);
|
return response()->json($suggestions);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,6 @@ class UserController extends Controller
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
\Log::error('Failed to save user gravatar image');
|
\Log::error('Failed to save user gravatar image');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect('/settings/users');
|
return redirect('/settings/users');
|
||||||
|
@ -256,7 +255,8 @@ class UserController extends Controller
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function switchBookView($id, Request $request) {
|
public function switchBookView($id, Request $request)
|
||||||
|
{
|
||||||
$this->checkPermissionOr('users-manage', function () use ($id) {
|
$this->checkPermissionOr('users-manage', function () use ($id) {
|
||||||
return $this->currentUser->id == $id;
|
return $this->currentUser->id == $id;
|
||||||
});
|
});
|
||||||
|
@ -271,5 +271,4 @@ class UserController extends Controller
|
||||||
|
|
||||||
return redirect()->back(302, [], "/settings/users/$id");
|
return redirect()->back(302, [], "/settings/users/$id");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,9 @@ class Localization
|
||||||
$locale = $defaultLang;
|
$locale = $defaultLang;
|
||||||
$availableLocales = config('app.locales');
|
$availableLocales = config('app.locales');
|
||||||
foreach ($request->getLanguages() as $lang) {
|
foreach ($request->getLanguages() as $lang) {
|
||||||
if (!in_array($lang, $availableLocales)) continue;
|
if (!in_array($lang, $availableLocales)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$locale = $lang;
|
$locale = $lang;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,5 +15,4 @@ class Model extends EloquentModel
|
||||||
{
|
{
|
||||||
return parent::getAttributeFromArray($key);
|
return parent::getAttributeFromArray($key);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -49,5 +49,4 @@ class ConfirmEmail extends Notification implements ShouldQueue
|
||||||
->line(trans('auth.email_confirm_text'))
|
->line(trans('auth.email_confirm_text'))
|
||||||
->action(trans('auth.email_confirm_action'), baseUrl('/register/confirm/' . $this->token));
|
->action(trans('auth.email_confirm_action'), baseUrl('/register/confirm/' . $this->token));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack;
|
<?php namespace BookStack;
|
||||||
|
|
||||||
|
|
||||||
abstract class Ownable extends Model
|
abstract class Ownable extends Model
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -29,5 +28,4 @@ abstract class Ownable extends Model
|
||||||
{
|
{
|
||||||
return strtolower(array_slice(explode('\\', static::class), -1, 1)[0]);
|
return strtolower(array_slice(explode('\\', static::class), -1, 1)[0]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack;
|
<?php namespace BookStack;
|
||||||
|
|
||||||
|
|
||||||
class Page extends Entity
|
class Page extends Entity
|
||||||
{
|
{
|
||||||
protected $fillable = ['name', 'html', 'priority', 'markdown'];
|
protected $fillable = ['name', 'html', 'priority', 'markdown'];
|
||||||
|
@ -101,8 +100,8 @@ class Page extends Entity
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function entityRawQuery($withContent = false)
|
public function entityRawQuery($withContent = false)
|
||||||
{ $htmlQuery = $withContent ? 'html' : "'' as html";
|
{
|
||||||
|
$htmlQuery = $withContent ? 'html' : "'' as html";
|
||||||
return "'BookStack\\\\Page' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text, {$htmlQuery}, book_id, priority, chapter_id, draft, created_by, updated_by, updated_at, created_at";
|
return "'BookStack\\\\Page' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text, {$htmlQuery}, book_id, priority, chapter_id, draft, created_by, updated_by, updated_at, created_at";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack;
|
<?php namespace BookStack;
|
||||||
|
|
||||||
|
|
||||||
class PageRevision extends Model
|
class PageRevision extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = ['name', 'html', 'text', 'markdown', 'summary'];
|
protected $fillable = ['name', 'html', 'text', 'markdown', 'summary'];
|
||||||
|
@ -31,7 +30,9 @@ class PageRevision extends Model
|
||||||
public function getUrl($path = null)
|
public function getUrl($path = null)
|
||||||
{
|
{
|
||||||
$url = $this->page->getUrl() . '/revisions/' . $this->id;
|
$url = $this->page->getUrl() . '/revisions/' . $this->id;
|
||||||
if ($path) return $url . '/' . trim($path, '/');
|
if ($path) {
|
||||||
|
return $url . '/' . trim($path, '/');
|
||||||
|
}
|
||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,5 +59,4 @@ class PageRevision extends Model
|
||||||
{
|
{
|
||||||
return $type === 'revision';
|
return $type === 'revision';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,12 @@ class AppServiceProvider extends ServiceProvider
|
||||||
public function boot()
|
public function boot()
|
||||||
{
|
{
|
||||||
// Custom validation methods
|
// Custom validation methods
|
||||||
Validator::extend('is_image', function($attribute, $value, $parameters, $validator) {
|
Validator::extend('is_image', function ($attribute, $value, $parameters, $validator) {
|
||||||
$imageMimes = ['image/png', 'image/bmp', 'image/gif', 'image/jpeg', 'image/jpg', 'image/tiff', 'image/webp'];
|
$imageMimes = ['image/png', 'image/bmp', 'image/gif', 'image/jpeg', 'image/jpg', 'image/tiff', 'image/webp'];
|
||||||
return in_array($value->getMimeType(), $imageMimes);
|
return in_array($value->getMimeType(), $imageMimes);
|
||||||
});
|
});
|
||||||
|
|
||||||
\Blade::directive('icon', function($expression) {
|
\Blade::directive('icon', function ($expression) {
|
||||||
return "<?php echo icon($expression); ?>";
|
return "<?php echo icon($expression); ?>";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ class AppServiceProvider extends ServiceProvider
|
||||||
*/
|
*/
|
||||||
public function register()
|
public function register()
|
||||||
{
|
{
|
||||||
$this->app->singleton(SettingService::class, function($app) {
|
$this->app->singleton(SettingService::class, function ($app) {
|
||||||
return new SettingService($app->make(Setting::class), $app->make('Illuminate\Contracts\Cache\Repository'));
|
return new SettingService($app->make(Setting::class), $app->make('Illuminate\Contracts\Cache\Repository'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ class AuthServiceProvider extends ServiceProvider
|
||||||
*/
|
*/
|
||||||
public function register()
|
public function register()
|
||||||
{
|
{
|
||||||
Auth::provider('ldap', function($app, array $config) {
|
Auth::provider('ldap', function ($app, array $config) {
|
||||||
return new LdapUserProvider($config['model'], $app[LdapService::class]);
|
return new LdapUserProvider($config['model'], $app[LdapService::class]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,28 +34,28 @@ class CustomFacadeProvider extends ServiceProvider
|
||||||
*/
|
*/
|
||||||
public function register()
|
public function register()
|
||||||
{
|
{
|
||||||
$this->app->bind('activity', function() {
|
$this->app->bind('activity', function () {
|
||||||
return new ActivityService(
|
return new ActivityService(
|
||||||
$this->app->make(Activity::class),
|
$this->app->make(Activity::class),
|
||||||
$this->app->make(PermissionService::class)
|
$this->app->make(PermissionService::class)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->app->bind('views', function() {
|
$this->app->bind('views', function () {
|
||||||
return new ViewService(
|
return new ViewService(
|
||||||
$this->app->make(View::class),
|
$this->app->make(View::class),
|
||||||
$this->app->make(PermissionService::class)
|
$this->app->make(PermissionService::class)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->app->bind('setting', function() {
|
$this->app->bind('setting', function () {
|
||||||
return new SettingService(
|
return new SettingService(
|
||||||
$this->app->make(Setting::class),
|
$this->app->make(Setting::class),
|
||||||
$this->app->make(Repository::class)
|
$this->app->make(Repository::class)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->app->bind('images', function() {
|
$this->app->bind('images', function () {
|
||||||
return new ImageService(
|
return new ImageService(
|
||||||
$this->app->make(ImageManager::class),
|
$this->app->make(ImageManager::class),
|
||||||
$this->app->make(Factory::class),
|
$this->app->make(Factory::class),
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace BookStack\Providers;
|
namespace BookStack\Providers;
|
||||||
|
|
||||||
|
|
||||||
use BookStack\Role;
|
use BookStack\Role;
|
||||||
use BookStack\Services\LdapService;
|
use BookStack\Services\LdapService;
|
||||||
use BookStack\User;
|
use BookStack\User;
|
||||||
|
@ -102,7 +101,9 @@ class LdapUserProvider implements UserProvider
|
||||||
{
|
{
|
||||||
// Get user via LDAP
|
// Get user via LDAP
|
||||||
$userDetails = $this->ldapService->getUserDetails($credentials['username']);
|
$userDetails = $this->ldapService->getUserDetails($credentials['username']);
|
||||||
if ($userDetails === null) return null;
|
if ($userDetails === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Search current user base by looking up a uid
|
// Search current user base by looking up a uid
|
||||||
$model = $this->createModel();
|
$model = $this->createModel();
|
||||||
|
@ -110,7 +111,9 @@ class LdapUserProvider implements UserProvider
|
||||||
->where('external_auth_id', $userDetails['uid'])
|
->where('external_auth_id', $userDetails['uid'])
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
if ($currentUser !== null) return $currentUser;
|
if ($currentUser !== null) {
|
||||||
|
return $currentUser;
|
||||||
|
}
|
||||||
|
|
||||||
$model->name = $userDetails['name'];
|
$model->name = $userDetails['name'];
|
||||||
$model->external_auth_id = $userDetails['uid'];
|
$model->external_auth_id = $userDetails['uid'];
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack\Providers;
|
<?php namespace BookStack\Providers;
|
||||||
|
|
||||||
|
|
||||||
use Illuminate\Pagination\PaginationServiceProvider as IlluminatePaginationServiceProvider;
|
use Illuminate\Pagination\PaginationServiceProvider as IlluminatePaginationServiceProvider;
|
||||||
use Illuminate\Pagination\Paginator;
|
use Illuminate\Pagination\Paginator;
|
||||||
|
|
||||||
|
@ -32,4 +31,4 @@ class PaginationServiceProvider extends IlluminatePaginationServiceProvider
|
||||||
return 1;
|
return 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@ use BookStack\Entity;
|
||||||
* Class CommentRepo
|
* Class CommentRepo
|
||||||
* @package BookStack\Repos
|
* @package BookStack\Repos
|
||||||
*/
|
*/
|
||||||
class CommentRepo {
|
class CommentRepo
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Comment $comment
|
* @var Comment $comment
|
||||||
|
@ -39,7 +40,7 @@ class CommentRepo {
|
||||||
* @param array $data
|
* @param array $data
|
||||||
* @return Comment
|
* @return Comment
|
||||||
*/
|
*/
|
||||||
public function create (Entity $entity, $data = [])
|
public function create(Entity $entity, $data = [])
|
||||||
{
|
{
|
||||||
$userId = user()->id;
|
$userId = user()->id;
|
||||||
$comment = $this->comment->newInstance($data);
|
$comment = $this->comment->newInstance($data);
|
||||||
|
@ -81,7 +82,9 @@ class CommentRepo {
|
||||||
protected function getNextLocalId(Entity $entity)
|
protected function getNextLocalId(Entity $entity)
|
||||||
{
|
{
|
||||||
$comments = $entity->comments(false)->orderBy('local_id', 'desc')->first();
|
$comments = $entity->comments(false)->orderBy('local_id', 'desc')->first();
|
||||||
if ($comments === null) return 1;
|
if ($comments === null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
return $comments->local_id + 1;
|
return $comments->local_id + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,11 +77,15 @@ class EntityRepo
|
||||||
* @param SearchService $searchService
|
* @param SearchService $searchService
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Book $book, Chapter $chapter, Page $page, PageRevision $pageRevision,
|
Book $book,
|
||||||
ViewService $viewService, PermissionService $permissionService,
|
Chapter $chapter,
|
||||||
TagRepo $tagRepo, SearchService $searchService
|
Page $page,
|
||||||
)
|
PageRevision $pageRevision,
|
||||||
{
|
ViewService $viewService,
|
||||||
|
PermissionService $permissionService,
|
||||||
|
TagRepo $tagRepo,
|
||||||
|
SearchService $searchService
|
||||||
|
) {
|
||||||
$this->book = $book;
|
$this->book = $book;
|
||||||
$this->chapter = $chapter;
|
$this->chapter = $chapter;
|
||||||
$this->page = $page;
|
$this->page = $page;
|
||||||
|
@ -163,14 +167,16 @@ class EntityRepo
|
||||||
$q = $this->entityQuery($type)->where('slug', '=', $slug);
|
$q = $this->entityQuery($type)->where('slug', '=', $slug);
|
||||||
|
|
||||||
if (strtolower($type) === 'chapter' || strtolower($type) === 'page') {
|
if (strtolower($type) === 'chapter' || strtolower($type) === 'page') {
|
||||||
$q = $q->where('book_id', '=', function($query) use ($bookSlug) {
|
$q = $q->where('book_id', '=', function ($query) use ($bookSlug) {
|
||||||
$query->select('id')
|
$query->select('id')
|
||||||
->from($this->book->getTable())
|
->from($this->book->getTable())
|
||||||
->where('slug', '=', $bookSlug)->limit(1);
|
->where('slug', '=', $bookSlug)->limit(1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$entity = $q->first();
|
$entity = $q->first();
|
||||||
if ($entity === null) throw new NotFoundException(trans('errors.' . strtolower($type) . '_not_found'));
|
if ($entity === null) {
|
||||||
|
throw new NotFoundException(trans('errors.' . strtolower($type) . '_not_found'));
|
||||||
|
}
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +211,9 @@ class EntityRepo
|
||||||
public function getAll($type, $count = 20, $permission = 'view')
|
public function getAll($type, $count = 20, $permission = 'view')
|
||||||
{
|
{
|
||||||
$q = $this->entityQuery($type, false, $permission)->orderBy('name', 'asc');
|
$q = $this->entityQuery($type, false, $permission)->orderBy('name', 'asc');
|
||||||
if ($count !== false) $q = $q->take($count);
|
if ($count !== false) {
|
||||||
|
$q = $q->take($count);
|
||||||
|
}
|
||||||
return $q->get();
|
return $q->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +240,9 @@ class EntityRepo
|
||||||
{
|
{
|
||||||
$query = $this->permissionService->enforceEntityRestrictions($type, $this->getEntity($type))
|
$query = $this->permissionService->enforceEntityRestrictions($type, $this->getEntity($type))
|
||||||
->orderBy('created_at', 'desc');
|
->orderBy('created_at', 'desc');
|
||||||
if (strtolower($type) === 'page') $query = $query->where('draft', '=', false);
|
if (strtolower($type) === 'page') {
|
||||||
|
$query = $query->where('draft', '=', false);
|
||||||
|
}
|
||||||
if ($additionalQuery !== false && is_callable($additionalQuery)) {
|
if ($additionalQuery !== false && is_callable($additionalQuery)) {
|
||||||
$additionalQuery($query);
|
$additionalQuery($query);
|
||||||
}
|
}
|
||||||
|
@ -251,7 +261,9 @@ class EntityRepo
|
||||||
{
|
{
|
||||||
$query = $this->permissionService->enforceEntityRestrictions($type, $this->getEntity($type))
|
$query = $this->permissionService->enforceEntityRestrictions($type, $this->getEntity($type))
|
||||||
->orderBy('updated_at', 'desc');
|
->orderBy('updated_at', 'desc');
|
||||||
if (strtolower($type) === 'page') $query = $query->where('draft', '=', false);
|
if (strtolower($type) === 'page') {
|
||||||
|
$query = $query->where('draft', '=', false);
|
||||||
|
}
|
||||||
if ($additionalQuery !== false && is_callable($additionalQuery)) {
|
if ($additionalQuery !== false && is_callable($additionalQuery)) {
|
||||||
$additionalQuery($query);
|
$additionalQuery($query);
|
||||||
}
|
}
|
||||||
|
@ -348,12 +360,16 @@ class EntityRepo
|
||||||
$parents[$key] = $entities[$index];
|
$parents[$key] = $entities[$index];
|
||||||
$parents[$key]->setAttribute('pages', collect());
|
$parents[$key]->setAttribute('pages', collect());
|
||||||
}
|
}
|
||||||
if ($entities[$index]->chapter_id === 0 || $entities[$index]->chapter_id === '0') $tree[] = $entities[$index];
|
if ($entities[$index]->chapter_id === 0 || $entities[$index]->chapter_id === '0') {
|
||||||
|
$tree[] = $entities[$index];
|
||||||
|
}
|
||||||
$entities[$index]->book = $book;
|
$entities[$index]->book = $book;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($entities as $entity) {
|
foreach ($entities as $entity) {
|
||||||
if ($entity->chapter_id === 0 || $entity->chapter_id === '0') continue;
|
if ($entity->chapter_id === 0 || $entity->chapter_id === '0') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$parentKey = 'BookStack\\Chapter:' . $entity->chapter_id;
|
$parentKey = 'BookStack\\Chapter:' . $entity->chapter_id;
|
||||||
if (!isset($parents[$parentKey])) {
|
if (!isset($parents[$parentKey])) {
|
||||||
$tree[] = $entity;
|
$tree[] = $entity;
|
||||||
|
@ -432,7 +448,9 @@ class EntityRepo
|
||||||
if (strtolower($type) === 'page' || strtolower($type) === 'chapter') {
|
if (strtolower($type) === 'page' || strtolower($type) === 'chapter') {
|
||||||
$query = $query->where('book_id', '=', $bookId);
|
$query = $query->where('book_id', '=', $bookId);
|
||||||
}
|
}
|
||||||
if ($currentId) $query = $query->where('id', '!=', $currentId);
|
if ($currentId) {
|
||||||
|
$query = $query->where('id', '!=', $currentId);
|
||||||
|
}
|
||||||
return $query->count() > 0;
|
return $query->count() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,7 +577,9 @@ class EntityRepo
|
||||||
$slug = preg_replace('/[\+\/\\\?\@\}\{\.\,\=\[\]\#\&\!\*\'\;\:\$\%]/', '', mb_strtolower($name));
|
$slug = preg_replace('/[\+\/\\\?\@\}\{\.\,\=\[\]\#\&\!\*\'\;\:\$\%]/', '', mb_strtolower($name));
|
||||||
$slug = preg_replace('/\s{2,}/', ' ', $slug);
|
$slug = preg_replace('/\s{2,}/', ' ', $slug);
|
||||||
$slug = str_replace(' ', '-', $slug);
|
$slug = str_replace(' ', '-', $slug);
|
||||||
if ($slug === "") $slug = substr(md5(rand(1, 500)), 0, 5);
|
if ($slug === "") {
|
||||||
|
$slug = substr(md5(rand(1, 500)), 0, 5);
|
||||||
|
}
|
||||||
return $slug;
|
return $slug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,7 +620,9 @@ class EntityRepo
|
||||||
public function savePageRevision(Page $page, $summary = null)
|
public function savePageRevision(Page $page, $summary = null)
|
||||||
{
|
{
|
||||||
$revision = $this->pageRevision->newInstance($page->toArray());
|
$revision = $this->pageRevision->newInstance($page->toArray());
|
||||||
if (setting('app-editor') !== 'markdown') $revision->markdown = '';
|
if (setting('app-editor') !== 'markdown') {
|
||||||
|
$revision->markdown = '';
|
||||||
|
}
|
||||||
$revision->page_id = $page->id;
|
$revision->page_id = $page->id;
|
||||||
$revision->slug = $page->slug;
|
$revision->slug = $page->slug;
|
||||||
$revision->book_slug = $page->book->slug;
|
$revision->book_slug = $page->book->slug;
|
||||||
|
@ -628,7 +650,9 @@ class EntityRepo
|
||||||
*/
|
*/
|
||||||
protected function formatHtml($htmlText)
|
protected function formatHtml($htmlText)
|
||||||
{
|
{
|
||||||
if ($htmlText == '') return $htmlText;
|
if ($htmlText == '') {
|
||||||
|
return $htmlText;
|
||||||
|
}
|
||||||
libxml_use_internal_errors(true);
|
libxml_use_internal_errors(true);
|
||||||
$doc = new DOMDocument();
|
$doc = new DOMDocument();
|
||||||
$doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8'));
|
$doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8'));
|
||||||
|
@ -642,7 +666,9 @@ class EntityRepo
|
||||||
|
|
||||||
foreach ($childNodes as $index => $childNode) {
|
foreach ($childNodes as $index => $childNode) {
|
||||||
/** @var \DOMElement $childNode */
|
/** @var \DOMElement $childNode */
|
||||||
if (get_class($childNode) !== 'DOMElement') continue;
|
if (get_class($childNode) !== 'DOMElement') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Overwrite id if not a BookStack custom id
|
// Overwrite id if not a BookStack custom id
|
||||||
if ($childNode->hasAttribute('id')) {
|
if ($childNode->hasAttribute('id')) {
|
||||||
|
@ -689,13 +715,17 @@ class EntityRepo
|
||||||
$content = $page->html;
|
$content = $page->html;
|
||||||
$matches = [];
|
$matches = [];
|
||||||
preg_match_all("/{{@\s?([0-9].*?)}}/", $content, $matches);
|
preg_match_all("/{{@\s?([0-9].*?)}}/", $content, $matches);
|
||||||
if (count($matches[0]) === 0) return $content;
|
if (count($matches[0]) === 0) {
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
$topLevelTags = ['table', 'ul', 'ol'];
|
$topLevelTags = ['table', 'ul', 'ol'];
|
||||||
foreach ($matches[1] as $index => $includeId) {
|
foreach ($matches[1] as $index => $includeId) {
|
||||||
$splitInclude = explode('#', $includeId, 2);
|
$splitInclude = explode('#', $includeId, 2);
|
||||||
$pageId = intval($splitInclude[0]);
|
$pageId = intval($splitInclude[0]);
|
||||||
if (is_nan($pageId)) continue;
|
if (is_nan($pageId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$matchedPage = $this->getById('page', $pageId, false, $ignorePermissions);
|
$matchedPage = $this->getById('page', $pageId, false, $ignorePermissions);
|
||||||
if ($matchedPage === null) {
|
if ($matchedPage === null) {
|
||||||
|
@ -755,7 +785,9 @@ class EntityRepo
|
||||||
$page->updated_by = user()->id;
|
$page->updated_by = user()->id;
|
||||||
$page->draft = true;
|
$page->draft = true;
|
||||||
|
|
||||||
if ($chapter) $page->chapter_id = $chapter->id;
|
if ($chapter) {
|
||||||
|
$page->chapter_id = $chapter->id;
|
||||||
|
}
|
||||||
|
|
||||||
$book->pages()->save($page);
|
$book->pages()->save($page);
|
||||||
$page = $this->page->find($page->id);
|
$page = $this->page->find($page->id);
|
||||||
|
@ -786,14 +818,18 @@ class EntityRepo
|
||||||
*/
|
*/
|
||||||
public function getPageNav($pageContent)
|
public function getPageNav($pageContent)
|
||||||
{
|
{
|
||||||
if ($pageContent == '') return [];
|
if ($pageContent == '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
libxml_use_internal_errors(true);
|
libxml_use_internal_errors(true);
|
||||||
$doc = new DOMDocument();
|
$doc = new DOMDocument();
|
||||||
$doc->loadHTML(mb_convert_encoding($pageContent, 'HTML-ENTITIES', 'UTF-8'));
|
$doc->loadHTML(mb_convert_encoding($pageContent, 'HTML-ENTITIES', 'UTF-8'));
|
||||||
$xPath = new DOMXPath($doc);
|
$xPath = new DOMXPath($doc);
|
||||||
$headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6");
|
$headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6");
|
||||||
|
|
||||||
if (is_null($headers)) return [];
|
if (is_null($headers)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
$tree = collect([]);
|
$tree = collect([]);
|
||||||
foreach ($headers as $header) {
|
foreach ($headers as $header) {
|
||||||
|
@ -809,7 +845,7 @@ class EntityRepo
|
||||||
// Normalise headers if only smaller headers have been used
|
// Normalise headers if only smaller headers have been used
|
||||||
if (count($tree) > 0) {
|
if (count($tree) > 0) {
|
||||||
$minLevel = $tree->pluck('level')->min();
|
$minLevel = $tree->pluck('level')->min();
|
||||||
$tree = $tree->map(function($header) use ($minLevel) {
|
$tree = $tree->map(function ($header) use ($minLevel) {
|
||||||
$header['level'] -= ($minLevel - 2);
|
$header['level'] -= ($minLevel - 2);
|
||||||
return $header;
|
return $header;
|
||||||
});
|
});
|
||||||
|
@ -845,7 +881,9 @@ class EntityRepo
|
||||||
$page->fill($input);
|
$page->fill($input);
|
||||||
$page->html = $this->formatHtml($input['html']);
|
$page->html = $this->formatHtml($input['html']);
|
||||||
$page->text = $this->pageToPlainText($page);
|
$page->text = $this->pageToPlainText($page);
|
||||||
if (setting('app-editor') !== 'markdown') $page->markdown = '';
|
if (setting('app-editor') !== 'markdown') {
|
||||||
|
$page->markdown = '';
|
||||||
|
}
|
||||||
$page->updated_by = $userId;
|
$page->updated_by = $userId;
|
||||||
$page->revision_count++;
|
$page->revision_count++;
|
||||||
$page->save();
|
$page->save();
|
||||||
|
@ -907,7 +945,9 @@ class EntityRepo
|
||||||
public function getUserPageDraftMessage(PageRevision $draft)
|
public function getUserPageDraftMessage(PageRevision $draft)
|
||||||
{
|
{
|
||||||
$message = trans('entities.pages_editing_draft_notification', ['timeDiff' => $draft->updated_at->diffForHumans()]);
|
$message = trans('entities.pages_editing_draft_notification', ['timeDiff' => $draft->updated_at->diffForHumans()]);
|
||||||
if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) return $message;
|
if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) {
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
return $message . "\n" . trans('entities.pages_draft_edited_notification');
|
return $message . "\n" . trans('entities.pages_draft_edited_notification');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1003,7 +1043,9 @@ class EntityRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
$draft->fill($data);
|
$draft->fill($data);
|
||||||
if (setting('app-editor') !== 'markdown') $draft->markdown = '';
|
if (setting('app-editor') !== 'markdown') {
|
||||||
|
$draft->markdown = '';
|
||||||
|
}
|
||||||
|
|
||||||
$draft->save();
|
$draft->save();
|
||||||
return $draft;
|
return $draft;
|
||||||
|
@ -1110,17 +1152,4 @@ class EntityRepo
|
||||||
|
|
||||||
$page->delete();
|
$page->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ class ImageRepo
|
||||||
* @param string $searchTerm
|
* @param string $searchTerm
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function searchPaginatedByType($type, $page = 0, $pageSize = 24, $searchTerm)
|
public function searchPaginatedByType($type, $searchTerm, $page = 0, $pageSize = 24)
|
||||||
{
|
{
|
||||||
$images = $this->image->where('type', '=', strtolower($type))->where('name', 'LIKE', '%' . $searchTerm . '%');
|
$images = $this->image->where('type', '=', strtolower($type))->where('name', 'LIKE', '%' . $searchTerm . '%');
|
||||||
return $this->returnPaginated($images, $page, $pageSize);
|
return $this->returnPaginated($images, $page, $pageSize);
|
||||||
|
@ -101,13 +101,13 @@ class ImageRepo
|
||||||
/**
|
/**
|
||||||
* Get gallery images with a particular filter criteria such as
|
* Get gallery images with a particular filter criteria such as
|
||||||
* being within the current book or page.
|
* being within the current book or page.
|
||||||
* @param int $pagination
|
|
||||||
* @param int $pageSize
|
|
||||||
* @param $filter
|
* @param $filter
|
||||||
* @param $pageId
|
* @param $pageId
|
||||||
|
* @param int $pageNum
|
||||||
|
* @param int $pageSize
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getGalleryFiltered($pagination = 0, $pageSize = 24, $filter, $pageId)
|
public function getGalleryFiltered($filter, $pageId, $pageNum = 0, $pageSize = 24)
|
||||||
{
|
{
|
||||||
$images = $this->image->where('type', '=', 'gallery');
|
$images = $this->image->where('type', '=', 'gallery');
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ class ImageRepo
|
||||||
$images = $images->whereIn('uploaded_to', $validPageIds);
|
$images = $images->whereIn('uploaded_to', $validPageIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->returnPaginated($images, $pagination, $pageSize);
|
return $this->returnPaginated($images, $pageNum, $pageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -254,5 +254,4 @@ class ImageRepo
|
||||||
$validTypes = ['drawing', 'gallery', 'cover', 'system', 'user'];
|
$validTypes = ['drawing', 'gallery', 'cover', 'system', 'user'];
|
||||||
return in_array($type, $validTypes);
|
return in_array($type, $validTypes);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack\Repos;
|
<?php namespace BookStack\Repos;
|
||||||
|
|
||||||
|
|
||||||
use BookStack\Exceptions\PermissionsException;
|
use BookStack\Exceptions\PermissionsException;
|
||||||
use BookStack\RolePermission;
|
use BookStack\RolePermission;
|
||||||
use BookStack\Role;
|
use BookStack\Role;
|
||||||
|
@ -149,5 +148,4 @@ class PermissionsRepo
|
||||||
$this->permissionService->deleteJointPermissionsForRole($role);
|
$this->permissionService->deleteJointPermissionsForRole($role);
|
||||||
$role->delete();
|
$role->delete();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -52,7 +52,9 @@ class TagRepo
|
||||||
public function getForEntity($entityType, $entityId)
|
public function getForEntity($entityType, $entityId)
|
||||||
{
|
{
|
||||||
$entity = $this->getEntity($entityType, $entityId);
|
$entity = $this->getEntity($entityType, $entityId);
|
||||||
if ($entity === null) return collect();
|
if ($entity === null) {
|
||||||
|
return collect();
|
||||||
|
}
|
||||||
|
|
||||||
return $entity->tags;
|
return $entity->tags;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +97,9 @@ class TagRepo
|
||||||
$query = $query->orderBy('count', 'desc')->take(50);
|
$query = $query->orderBy('count', 'desc')->take(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($tagName !== false) $query = $query->where('name', '=', $tagName);
|
if ($tagName !== false) {
|
||||||
|
$query = $query->where('name', '=', $tagName);
|
||||||
|
}
|
||||||
|
|
||||||
$query = $this->permissionService->filterRestrictedEntityRelations($query, 'tags', 'entity_id', 'entity_type');
|
$query = $this->permissionService->filterRestrictedEntityRelations($query, 'tags', 'entity_id', 'entity_type');
|
||||||
return $query->get(['value'])->pluck('value');
|
return $query->get(['value'])->pluck('value');
|
||||||
|
@ -112,7 +116,9 @@ class TagRepo
|
||||||
$entity->tags()->delete();
|
$entity->tags()->delete();
|
||||||
$newTags = [];
|
$newTags = [];
|
||||||
foreach ($tags as $tag) {
|
foreach ($tags as $tag) {
|
||||||
if (trim($tag['name']) === '') continue;
|
if (trim($tag['name']) === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$newTags[] = $this->newInstanceFromInput($tag);
|
$newTags[] = $this->newInstanceFromInput($tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,5 +138,4 @@ class TagRepo
|
||||||
$values = ['name' => $name, 'value' => $value];
|
$values = ['name' => $name, 'value' => $value];
|
||||||
return $this->tag->newInstance($values);
|
return $this->tag->newInstance($values);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -60,13 +60,13 @@ class UserRepo
|
||||||
* @param $sortData
|
* @param $sortData
|
||||||
* @return \Illuminate\Database\Eloquent\Builder|static
|
* @return \Illuminate\Database\Eloquent\Builder|static
|
||||||
*/
|
*/
|
||||||
public function getAllUsersPaginatedAndSorted($count = 20, $sortData)
|
public function getAllUsersPaginatedAndSorted($count, $sortData)
|
||||||
{
|
{
|
||||||
$query = $this->user->with('roles', 'avatar')->orderBy($sortData['sort'], $sortData['order']);
|
$query = $this->user->with('roles', 'avatar')->orderBy($sortData['sort'], $sortData['order']);
|
||||||
|
|
||||||
if ($sortData['search']) {
|
if ($sortData['search']) {
|
||||||
$term = '%' . $sortData['search'] . '%';
|
$term = '%' . $sortData['search'] . '%';
|
||||||
$query->where(function($query) use ($term) {
|
$query->where(function ($query) use ($term) {
|
||||||
$query->where('name', 'like', $term)
|
$query->where('name', 'like', $term)
|
||||||
->orWhere('email', 'like', $term);
|
->orWhere('email', 'like', $term);
|
||||||
});
|
});
|
||||||
|
@ -107,7 +107,9 @@ class UserRepo
|
||||||
public function attachDefaultRole($user)
|
public function attachDefaultRole($user)
|
||||||
{
|
{
|
||||||
$roleId = setting('registration-role');
|
$roleId = setting('registration-role');
|
||||||
if ($roleId === false) $roleId = $this->role->first()->id;
|
if ($roleId === false) {
|
||||||
|
$roleId = $this->role->first()->id;
|
||||||
|
}
|
||||||
$user->attachRoleId($roleId);
|
$user->attachRoleId($roleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,10 +120,14 @@ class UserRepo
|
||||||
*/
|
*/
|
||||||
public function isOnlyAdmin(User $user)
|
public function isOnlyAdmin(User $user)
|
||||||
{
|
{
|
||||||
if (!$user->hasSystemRole('admin')) return false;
|
if (!$user->hasSystemRole('admin')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$adminRole = $this->role->getSystemRole('admin');
|
$adminRole = $this->role->getSystemRole('admin');
|
||||||
if ($adminRole->users->count() > 1) return false;
|
if ($adminRole->users->count() > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,5 +228,4 @@ class UserRepo
|
||||||
{
|
{
|
||||||
return $this->role->where('system_name', '!=', 'admin')->get();
|
return $this->role->where('system_name', '!=', 'admin')->get();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack;
|
<?php namespace BookStack;
|
||||||
|
|
||||||
|
|
||||||
class Role extends Model
|
class Role extends Model
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -40,7 +39,9 @@ class Role extends Model
|
||||||
{
|
{
|
||||||
$permissions = $this->getRelationValue('permissions');
|
$permissions = $this->getRelationValue('permissions');
|
||||||
foreach ($permissions as $permission) {
|
foreach ($permissions as $permission) {
|
||||||
if ($permission->getRawAttribute('name') === $permissionName) return true;
|
if ($permission->getRawAttribute('name') === $permissionName) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -91,5 +92,4 @@ class Role extends Model
|
||||||
{
|
{
|
||||||
return static::where('hidden', '=', false)->orderBy('name')->get();
|
return static::where('hidden', '=', false)->orderBy('name')->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack;
|
<?php namespace BookStack;
|
||||||
|
|
||||||
|
|
||||||
class RolePermission extends Model
|
class RolePermission extends Model
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -8,7 +7,7 @@ class RolePermission extends Model
|
||||||
*/
|
*/
|
||||||
public function roles()
|
public function roles()
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(Role::class, 'permission_role','permission_id', 'role_id');
|
return $this->belongsToMany(Role::class, 'permission_role', 'permission_id', 'role_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,5 +14,4 @@ class SearchTerm extends Model
|
||||||
{
|
{
|
||||||
return $this->morphTo('entity');
|
return $this->morphTo('entity');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,5 +170,4 @@ class ActivityService
|
||||||
Session::flash('success', $message);
|
Session::flash('success', $message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -14,7 +14,9 @@ class AttachmentService extends UploadService
|
||||||
*/
|
*/
|
||||||
protected function getStorage()
|
protected function getStorage()
|
||||||
{
|
{
|
||||||
if ($this->storageInstance !== null) return $this->storageInstance;
|
if ($this->storageInstance !== null) {
|
||||||
|
return $this->storageInstance;
|
||||||
|
}
|
||||||
|
|
||||||
$storageType = config('filesystems.default');
|
$storageType = config('filesystems.default');
|
||||||
|
|
||||||
|
@ -205,5 +207,4 @@ class AttachmentService extends UploadService
|
||||||
|
|
||||||
return $attachmentPath;
|
return $attachmentPath;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -108,6 +108,4 @@ class EmailConfirmationService
|
||||||
}
|
}
|
||||||
return $token;
|
return $token;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ class ExportService
|
||||||
public function chapterToContainedHtml(Chapter $chapter)
|
public function chapterToContainedHtml(Chapter $chapter)
|
||||||
{
|
{
|
||||||
$pages = $this->entityRepo->getChapterChildren($chapter);
|
$pages = $this->entityRepo->getChapterChildren($chapter);
|
||||||
$pages->each(function($page) {
|
$pages->each(function ($page) {
|
||||||
$page->html = $this->entityRepo->renderPage($page);
|
$page->html = $this->entityRepo->renderPage($page);
|
||||||
});
|
});
|
||||||
$html = view('chapters/export', [
|
$html = view('chapters/export', [
|
||||||
|
@ -89,7 +89,7 @@ class ExportService
|
||||||
public function chapterToPdf(Chapter $chapter)
|
public function chapterToPdf(Chapter $chapter)
|
||||||
{
|
{
|
||||||
$pages = $this->entityRepo->getChapterChildren($chapter);
|
$pages = $this->entityRepo->getChapterChildren($chapter);
|
||||||
$pages->each(function($page) {
|
$pages->each(function ($page) {
|
||||||
$page->html = $this->entityRepo->renderPage($page);
|
$page->html = $this->entityRepo->renderPage($page);
|
||||||
});
|
});
|
||||||
$html = view('chapters/export', [
|
$html = view('chapters/export', [
|
||||||
|
@ -163,7 +163,9 @@ class ExportService
|
||||||
$pathString = public_path(trim($relString, '/'));
|
$pathString = public_path(trim($relString, '/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($isLocal && !file_exists($pathString)) continue;
|
if ($isLocal && !file_exists($pathString)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if ($isLocal) {
|
if ($isLocal) {
|
||||||
$imageContent = file_get_contents($pathString);
|
$imageContent = file_get_contents($pathString);
|
||||||
|
@ -173,7 +175,9 @@ class ExportService
|
||||||
$imageContent = curl_exec($ch);
|
$imageContent = curl_exec($ch);
|
||||||
$err = curl_error($ch);
|
$err = curl_error($ch);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
if ($err) throw new \Exception("Image fetch failed, Received error: " . $err);
|
if ($err) {
|
||||||
|
throw new \Exception("Image fetch failed, Received error: " . $err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$imageEncoded = 'data:image/' . pathinfo($pathString, PATHINFO_EXTENSION) . ';base64,' . base64_encode($imageContent);
|
$imageEncoded = 'data:image/' . pathinfo($pathString, PATHINFO_EXTENSION) . ';base64,' . base64_encode($imageContent);
|
||||||
$newImageString = str_replace($srcString, $imageEncoded, $oldImgString);
|
$newImageString = str_replace($srcString, $imageEncoded, $oldImgString);
|
||||||
|
@ -257,17 +261,4 @@ class ExportService
|
||||||
}
|
}
|
||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack\Services\Facades;
|
<?php namespace BookStack\Services\Facades;
|
||||||
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Facade;
|
use Illuminate\Support\Facades\Facade;
|
||||||
|
|
||||||
class Activity extends Facade
|
class Activity extends Facade
|
||||||
|
@ -10,5 +9,8 @@ class Activity extends Facade
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected static function getFacadeAccessor() { return 'activity'; }
|
protected static function getFacadeAccessor()
|
||||||
}
|
{
|
||||||
|
return 'activity';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack\Services\Facades;
|
<?php namespace BookStack\Services\Facades;
|
||||||
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Facade;
|
use Illuminate\Support\Facades\Facade;
|
||||||
|
|
||||||
class Images extends Facade
|
class Images extends Facade
|
||||||
|
@ -10,5 +9,8 @@ class Images extends Facade
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected static function getFacadeAccessor() { return 'images'; }
|
protected static function getFacadeAccessor()
|
||||||
}
|
{
|
||||||
|
return 'images';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack\Services\Facades;
|
<?php namespace BookStack\Services\Facades;
|
||||||
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Facade;
|
use Illuminate\Support\Facades\Facade;
|
||||||
|
|
||||||
class Setting extends Facade
|
class Setting extends Facade
|
||||||
|
@ -10,5 +9,8 @@ class Setting extends Facade
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected static function getFacadeAccessor() { return 'setting'; }
|
protected static function getFacadeAccessor()
|
||||||
}
|
{
|
||||||
|
return 'setting';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,5 +9,8 @@ class Views extends Facade
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected static function getFacadeAccessor() { return 'views'; }
|
protected static function getFacadeAccessor()
|
||||||
}
|
{
|
||||||
|
return 'views';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -102,7 +102,9 @@ class ImageService extends UploadService
|
||||||
{
|
{
|
||||||
$imageName = $imageName ? $imageName : basename($url);
|
$imageName = $imageName ? $imageName : basename($url);
|
||||||
$imageData = file_get_contents($url);
|
$imageData = file_get_contents($url);
|
||||||
if($imageData === false) throw new \Exception(trans('errors.cannot_get_image_from_url', ['url' => $url]));
|
if ($imageData === false) {
|
||||||
|
throw new \Exception(trans('errors.cannot_get_image_from_url', ['url' => $url]));
|
||||||
|
}
|
||||||
return $this->saveNew($imageName, $imageData, $type);
|
return $this->saveNew($imageName, $imageData, $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +123,9 @@ class ImageService extends UploadService
|
||||||
$secureUploads = setting('app-secure-images');
|
$secureUploads = setting('app-secure-images');
|
||||||
$imageName = str_replace(' ', '-', $imageName);
|
$imageName = str_replace(' ', '-', $imageName);
|
||||||
|
|
||||||
if ($secureUploads) $imageName = str_random(16) . '-' . $imageName;
|
if ($secureUploads) {
|
||||||
|
$imageName = str_random(16) . '-' . $imageName;
|
||||||
|
}
|
||||||
|
|
||||||
$imagePath = '/uploads/images/' . $type . '/' . Date('Y-m-M') . '/';
|
$imagePath = '/uploads/images/' . $type . '/' . Date('Y-m-M') . '/';
|
||||||
|
|
||||||
|
@ -255,9 +259,13 @@ class ImageService extends UploadService
|
||||||
|
|
||||||
// Cleanup of empty folders
|
// Cleanup of empty folders
|
||||||
foreach ($storage->directories($imageFolder) as $directory) {
|
foreach ($storage->directories($imageFolder) as $directory) {
|
||||||
if ($this->isFolderEmpty($directory)) $storage->deleteDirectory($directory);
|
if ($this->isFolderEmpty($directory)) {
|
||||||
|
$storage->deleteDirectory($directory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($this->isFolderEmpty($imageFolder)) {
|
||||||
|
$storage->deleteDirectory($imageFolder);
|
||||||
}
|
}
|
||||||
if ($this->isFolderEmpty($imageFolder)) $storage->deleteDirectory($imageFolder);
|
|
||||||
|
|
||||||
$image->delete();
|
$image->delete();
|
||||||
return true;
|
return true;
|
||||||
|
@ -308,6 +316,4 @@ class ImageService extends UploadService
|
||||||
$basePath = ($this->storageUrl == false) ? baseUrl('/') : $this->storageUrl;
|
$basePath = ($this->storageUrl == false) ? baseUrl('/') : $this->storageUrl;
|
||||||
return rtrim($basePath, '/') . $filePath;
|
return rtrim($basePath, '/') . $filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack\Services;
|
<?php namespace BookStack\Services;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Ldap
|
* Class Ldap
|
||||||
* An object-orientated thin abstraction wrapper for common PHP LDAP functions.
|
* An object-orientated thin abstraction wrapper for common PHP LDAP functions.
|
||||||
|
@ -93,5 +92,4 @@ class Ldap
|
||||||
{
|
{
|
||||||
return ldap_bind($ldapConnection, $bindRdn, $bindPassword);
|
return ldap_bind($ldapConnection, $bindRdn, $bindPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack\Services;
|
<?php namespace BookStack\Services;
|
||||||
|
|
||||||
|
|
||||||
use BookStack\Exceptions\LdapException;
|
use BookStack\Exceptions\LdapException;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
|
|
||||||
|
@ -45,7 +44,9 @@ class LdapService
|
||||||
$followReferrals = $this->config['follow_referrals'] ? 1 : 0;
|
$followReferrals = $this->config['follow_referrals'] ? 1 : 0;
|
||||||
$this->ldap->setOption($ldapConnection, LDAP_OPT_REFERRALS, $followReferrals);
|
$this->ldap->setOption($ldapConnection, LDAP_OPT_REFERRALS, $followReferrals);
|
||||||
$users = $this->ldap->searchAndGetEntries($ldapConnection, $baseDn, $userFilter, ['cn', 'uid', 'dn', $emailAttr]);
|
$users = $this->ldap->searchAndGetEntries($ldapConnection, $baseDn, $userFilter, ['cn', 'uid', 'dn', $emailAttr]);
|
||||||
if ($users['count'] === 0) return null;
|
if ($users['count'] === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$user = $users[0];
|
$user = $users[0];
|
||||||
return [
|
return [
|
||||||
|
@ -66,8 +67,12 @@ class LdapService
|
||||||
public function validateUserCredentials(Authenticatable $user, $username, $password)
|
public function validateUserCredentials(Authenticatable $user, $username, $password)
|
||||||
{
|
{
|
||||||
$ldapUser = $this->getUserDetails($username);
|
$ldapUser = $this->getUserDetails($username);
|
||||||
if ($ldapUser === null) return false;
|
if ($ldapUser === null) {
|
||||||
if ($ldapUser['uid'] !== $user->external_auth_id) return false;
|
return false;
|
||||||
|
}
|
||||||
|
if ($ldapUser['uid'] !== $user->external_auth_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$ldapConnection = $this->getConnection();
|
$ldapConnection = $this->getConnection();
|
||||||
try {
|
try {
|
||||||
|
@ -97,7 +102,9 @@ class LdapService
|
||||||
$ldapBind = $this->ldap->bind($connection, $ldapDn, $ldapPass);
|
$ldapBind = $this->ldap->bind($connection, $ldapDn, $ldapPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$ldapBind) throw new LdapException(($isAnonymous ? trans('errors.ldap_fail_anonymous') : trans('errors.ldap_fail_authed')));
|
if (!$ldapBind) {
|
||||||
|
throw new LdapException(($isAnonymous ? trans('errors.ldap_fail_anonymous') : trans('errors.ldap_fail_authed')));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -108,7 +115,9 @@ class LdapService
|
||||||
*/
|
*/
|
||||||
protected function getConnection()
|
protected function getConnection()
|
||||||
{
|
{
|
||||||
if ($this->ldapConnection !== null) return $this->ldapConnection;
|
if ($this->ldapConnection !== null) {
|
||||||
|
return $this->ldapConnection;
|
||||||
|
}
|
||||||
|
|
||||||
// Check LDAP extension in installed
|
// Check LDAP extension in installed
|
||||||
if (!function_exists('ldap_connect') && config('app.env') !== 'testing') {
|
if (!function_exists('ldap_connect') && config('app.env') !== 'testing') {
|
||||||
|
@ -118,7 +127,9 @@ class LdapService
|
||||||
// Get port from server string and protocol if specified.
|
// Get port from server string and protocol if specified.
|
||||||
$ldapServer = explode(':', $this->config['server']);
|
$ldapServer = explode(':', $this->config['server']);
|
||||||
$hasProtocol = preg_match('/^ldaps{0,1}\:\/\//', $this->config['server']) === 1;
|
$hasProtocol = preg_match('/^ldaps{0,1}\:\/\//', $this->config['server']) === 1;
|
||||||
if (!$hasProtocol) array_unshift($ldapServer, '');
|
if (!$hasProtocol) {
|
||||||
|
array_unshift($ldapServer, '');
|
||||||
|
}
|
||||||
$hostName = $ldapServer[0] . ($hasProtocol?':':'') . $ldapServer[1];
|
$hostName = $ldapServer[0] . ($hasProtocol?':':'') . $ldapServer[1];
|
||||||
$defaultPort = $ldapServer[0] === 'ldaps' ? 636 : 389;
|
$defaultPort = $ldapServer[0] === 'ldaps' ? 636 : 389;
|
||||||
$ldapConnection = $this->ldap->connect($hostName, count($ldapServer) > 2 ? intval($ldapServer[2]) : $defaultPort);
|
$ldapConnection = $this->ldap->connect($hostName, count($ldapServer) > 2 ? intval($ldapServer[2]) : $defaultPort);
|
||||||
|
@ -151,5 +162,4 @@ class LdapService
|
||||||
}
|
}
|
||||||
return strtr($filterString, $newAttrs);
|
return strtr($filterString, $newAttrs);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -88,7 +88,9 @@ class PermissionService
|
||||||
}
|
}
|
||||||
|
|
||||||
$book = $this->book->find($bookId);
|
$book = $this->book->find($bookId);
|
||||||
if ($book === null) $book = false;
|
if ($book === null) {
|
||||||
|
$book = false;
|
||||||
|
}
|
||||||
if (isset($this->entityCache['books'])) {
|
if (isset($this->entityCache['books'])) {
|
||||||
$this->entityCache['books']->put($bookId, $book);
|
$this->entityCache['books']->put($bookId, $book);
|
||||||
}
|
}
|
||||||
|
@ -108,7 +110,9 @@ class PermissionService
|
||||||
}
|
}
|
||||||
|
|
||||||
$chapter = $this->chapter->find($chapterId);
|
$chapter = $this->chapter->find($chapterId);
|
||||||
if ($chapter === null) $chapter = false;
|
if ($chapter === null) {
|
||||||
|
$chapter = false;
|
||||||
|
}
|
||||||
if (isset($this->entityCache['chapters'])) {
|
if (isset($this->entityCache['chapters'])) {
|
||||||
$this->entityCache['chapters']->put($chapterId, $chapter);
|
$this->entityCache['chapters']->put($chapterId, $chapter);
|
||||||
}
|
}
|
||||||
|
@ -122,7 +126,9 @@ class PermissionService
|
||||||
*/
|
*/
|
||||||
protected function getRoles()
|
protected function getRoles()
|
||||||
{
|
{
|
||||||
if ($this->userRoles !== false) return $this->userRoles;
|
if ($this->userRoles !== false) {
|
||||||
|
return $this->userRoles;
|
||||||
|
}
|
||||||
|
|
||||||
$roles = [];
|
$roles = [];
|
||||||
|
|
||||||
|
@ -161,9 +167,9 @@ class PermissionService
|
||||||
*/
|
*/
|
||||||
protected function bookFetchQuery()
|
protected function bookFetchQuery()
|
||||||
{
|
{
|
||||||
return $this->book->newQuery()->select(['id', 'restricted', 'created_by'])->with(['chapters' => function($query) {
|
return $this->book->newQuery()->select(['id', 'restricted', 'created_by'])->with(['chapters' => function ($query) {
|
||||||
$query->select(['id', 'restricted', 'created_by', 'book_id']);
|
$query->select(['id', 'restricted', 'created_by', 'book_id']);
|
||||||
}, 'pages' => function($query) {
|
}, 'pages' => function ($query) {
|
||||||
$query->select(['id', 'restricted', 'created_by', 'book_id', 'chapter_id']);
|
$query->select(['id', 'restricted', 'created_by', 'book_id', 'chapter_id']);
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
@ -174,7 +180,8 @@ class PermissionService
|
||||||
* @param array $roles
|
* @param array $roles
|
||||||
* @param bool $deleteOld
|
* @param bool $deleteOld
|
||||||
*/
|
*/
|
||||||
protected function buildJointPermissionsForBooks($books, $roles, $deleteOld = false) {
|
protected function buildJointPermissionsForBooks($books, $roles, $deleteOld = false)
|
||||||
|
{
|
||||||
$entities = clone $books;
|
$entities = clone $books;
|
||||||
|
|
||||||
/** @var Book $book */
|
/** @var Book $book */
|
||||||
|
@ -187,7 +194,9 @@ class PermissionService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($deleteOld) $this->deleteManyJointPermissionsForEntities($entities->all());
|
if ($deleteOld) {
|
||||||
|
$this->deleteManyJointPermissionsForEntities($entities->all());
|
||||||
|
}
|
||||||
$this->createManyJointPermissions($entities, $roles);
|
$this->createManyJointPermissions($entities, $roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +270,7 @@ class PermissionService
|
||||||
*/
|
*/
|
||||||
protected function deleteManyJointPermissionsForRoles($roles)
|
protected function deleteManyJointPermissionsForRoles($roles)
|
||||||
{
|
{
|
||||||
$roleIds = array_map(function($role) {
|
$roleIds = array_map(function ($role) {
|
||||||
return $role->id;
|
return $role->id;
|
||||||
}, $roles);
|
}, $roles);
|
||||||
$this->jointPermission->newQuery()->whereIn('role_id', $roleIds)->delete();
|
$this->jointPermission->newQuery()->whereIn('role_id', $roleIds)->delete();
|
||||||
|
@ -282,21 +291,22 @@ class PermissionService
|
||||||
*/
|
*/
|
||||||
protected function deleteManyJointPermissionsForEntities($entities)
|
protected function deleteManyJointPermissionsForEntities($entities)
|
||||||
{
|
{
|
||||||
if (count($entities) === 0) return;
|
if (count($entities) === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$this->db->transaction(function() use ($entities) {
|
$this->db->transaction(function () use ($entities) {
|
||||||
|
|
||||||
foreach (array_chunk($entities, 1000) as $entityChunk) {
|
foreach (array_chunk($entities, 1000) as $entityChunk) {
|
||||||
$query = $this->db->table('joint_permissions');
|
$query = $this->db->table('joint_permissions');
|
||||||
foreach ($entityChunk as $entity) {
|
foreach ($entityChunk as $entity) {
|
||||||
$query->orWhere(function(QueryBuilder $query) use ($entity) {
|
$query->orWhere(function (QueryBuilder $query) use ($entity) {
|
||||||
$query->where('entity_id', '=', $entity->id)
|
$query->where('entity_id', '=', $entity->id)
|
||||||
->where('entity_type', '=', $entity->getMorphClass());
|
->where('entity_type', '=', $entity->getMorphClass());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$query->delete();
|
$query->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,7 +325,7 @@ class PermissionService
|
||||||
$permissionFetch = $this->entityPermission->newQuery();
|
$permissionFetch = $this->entityPermission->newQuery();
|
||||||
foreach ($entities as $entity) {
|
foreach ($entities as $entity) {
|
||||||
$entityRestrictedMap[$entity->getMorphClass() . ':' . $entity->id] = boolval($entity->getRawAttribute('restricted'));
|
$entityRestrictedMap[$entity->getMorphClass() . ':' . $entity->id] = boolval($entity->getRawAttribute('restricted'));
|
||||||
$permissionFetch->orWhere(function($query) use ($entity) {
|
$permissionFetch->orWhere(function ($query) use ($entity) {
|
||||||
$query->where('restrictable_id', '=', $entity->id)->where('restrictable_type', '=', $entity->getMorphClass());
|
$query->where('restrictable_id', '=', $entity->id)->where('restrictable_type', '=', $entity->getMorphClass());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -346,7 +356,7 @@ class PermissionService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->db->transaction(function() use ($jointPermissions) {
|
$this->db->transaction(function () use ($jointPermissions) {
|
||||||
foreach (array_chunk($jointPermissions, 1000) as $jointPermissionChunk) {
|
foreach (array_chunk($jointPermissions, 1000) as $jointPermissionChunk) {
|
||||||
$this->db->table('joint_permissions')->insert($jointPermissionChunk);
|
$this->db->table('joint_permissions')->insert($jointPermissionChunk);
|
||||||
}
|
}
|
||||||
|
@ -362,8 +372,12 @@ class PermissionService
|
||||||
protected function getActions(Entity $entity)
|
protected function getActions(Entity $entity)
|
||||||
{
|
{
|
||||||
$baseActions = ['view', 'update', 'delete'];
|
$baseActions = ['view', 'update', 'delete'];
|
||||||
if ($entity->isA('chapter') || $entity->isA('book')) $baseActions[] = 'page-create';
|
if ($entity->isA('chapter') || $entity->isA('book')) {
|
||||||
if ($entity->isA('book')) $baseActions[] = 'chapter-create';
|
$baseActions[] = 'page-create';
|
||||||
|
}
|
||||||
|
if ($entity->isA('book')) {
|
||||||
|
$baseActions[] = 'chapter-create';
|
||||||
|
}
|
||||||
return $baseActions;
|
return $baseActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,7 +426,10 @@ class PermissionService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->createJointPermissionDataArray($entity, $role, $action,
|
return $this->createJointPermissionDataArray(
|
||||||
|
$entity,
|
||||||
|
$role,
|
||||||
|
$action,
|
||||||
($hasExplicitAccessToParents || ($roleHasPermission && $hasPermissiveAccessToParents)),
|
($hasExplicitAccessToParents || ($roleHasPermission && $hasPermissiveAccessToParents)),
|
||||||
($hasExplicitAccessToParents || ($roleHasPermissionOwn && $hasPermissiveAccessToParents))
|
($hasExplicitAccessToParents || ($roleHasPermissionOwn && $hasPermissiveAccessToParents))
|
||||||
);
|
);
|
||||||
|
@ -426,7 +443,8 @@ class PermissionService
|
||||||
* @param $action
|
* @param $action
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function mapHasActiveRestriction($entityMap, Entity $entity, Role $role, $action) {
|
protected function mapHasActiveRestriction($entityMap, Entity $entity, Role $role, $action)
|
||||||
|
{
|
||||||
$key = $entity->getMorphClass() . ':' . $entity->getRawAttribute('id') . ':' . $role->getRawAttribute('id') . ':' . $action;
|
$key = $entity->getMorphClass() . ':' . $entity->getRawAttribute('id') . ':' . $role->getRawAttribute('id') . ':' . $action;
|
||||||
return isset($entityMap[$key]) ? $entityMap[$key] : false;
|
return isset($entityMap[$key]) ? $entityMap[$key] : false;
|
||||||
}
|
}
|
||||||
|
@ -545,11 +563,12 @@ class PermissionService
|
||||||
* @param bool $fetchPageContent
|
* @param bool $fetchPageContent
|
||||||
* @return QueryBuilder
|
* @return QueryBuilder
|
||||||
*/
|
*/
|
||||||
public function bookChildrenQuery($book_id, $filterDrafts = false, $fetchPageContent = false) {
|
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) {
|
{
|
||||||
|
$pageSelect = $this->db->table('pages')->selectRaw($this->page->entityRawQuery($fetchPageContent))->where('book_id', '=', $book_id)->where(function ($query) use ($filterDrafts) {
|
||||||
$query->where('draft', '=', 0);
|
$query->where('draft', '=', 0);
|
||||||
if (!$filterDrafts) {
|
if (!$filterDrafts) {
|
||||||
$query->orWhere(function($query) {
|
$query->orWhere(function ($query) {
|
||||||
$query->where('draft', '=', 1)->where('created_by', '=', $this->currentUser()->id);
|
$query->where('draft', '=', 1)->where('created_by', '=', $this->currentUser()->id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -562,8 +581,8 @@ class PermissionService
|
||||||
$whereQuery = $this->db->table('joint_permissions as jp')->selectRaw('COUNT(*)')
|
$whereQuery = $this->db->table('joint_permissions as jp')->selectRaw('COUNT(*)')
|
||||||
->whereRaw('jp.entity_id=U.id')->whereRaw('jp.entity_type=U.entity_type')
|
->whereRaw('jp.entity_id=U.id')->whereRaw('jp.entity_type=U.entity_type')
|
||||||
->where('jp.action', '=', 'view')->whereIn('jp.role_id', $this->getRoles())
|
->where('jp.action', '=', 'view')->whereIn('jp.role_id', $this->getRoles())
|
||||||
->where(function($query) {
|
->where(function ($query) {
|
||||||
$query->where('jp.has_permission', '=', 1)->orWhere(function($query) {
|
$query->where('jp.has_permission', '=', 1)->orWhere(function ($query) {
|
||||||
$query->where('jp.has_permission_own', '=', 1)->where('jp.created_by', '=', $this->currentUser()->id);
|
$query->where('jp.has_permission_own', '=', 1)->where('jp.created_by', '=', $this->currentUser()->id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -715,5 +734,4 @@ class PermissionService
|
||||||
$this->userRoles = false;
|
$this->userRoles = false;
|
||||||
$this->isAdminUser = null;
|
$this->isAdminUser = null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -83,7 +83,9 @@ class SearchService
|
||||||
$total = 0;
|
$total = 0;
|
||||||
|
|
||||||
foreach ($entityTypesToSearch as $entityType) {
|
foreach ($entityTypesToSearch as $entityType) {
|
||||||
if (!in_array($entityType, $entityTypes)) continue;
|
if (!in_array($entityType, $entityTypes)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$search = $this->searchEntityTable($terms, $entityType, $page, $count);
|
$search = $this->searchEntityTable($terms, $entityType, $page, $count);
|
||||||
$total += $this->searchEntityTable($terms, $entityType, $page, $count, true);
|
$total += $this->searchEntityTable($terms, $entityType, $page, $count, true);
|
||||||
$results = $results->merge($search);
|
$results = $results->merge($search);
|
||||||
|
@ -111,7 +113,9 @@ class SearchService
|
||||||
|
|
||||||
$results = collect();
|
$results = collect();
|
||||||
foreach ($entityTypesToSearch as $entityType) {
|
foreach ($entityTypesToSearch as $entityType) {
|
||||||
if (!in_array($entityType, $entityTypes)) continue;
|
if (!in_array($entityType, $entityTypes)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$search = $this->buildEntitySearchQuery($terms, $entityType)->where('book_id', '=', $bookId)->take(20)->get();
|
$search = $this->buildEntitySearchQuery($terms, $entityType)->where('book_id', '=', $bookId)->take(20)->get();
|
||||||
$results = $results->merge($search);
|
$results = $results->merge($search);
|
||||||
}
|
}
|
||||||
|
@ -143,7 +147,9 @@ class SearchService
|
||||||
public function searchEntityTable($terms, $entityType = 'page', $page = 1, $count = 20, $getCount = false)
|
public function searchEntityTable($terms, $entityType = 'page', $page = 1, $count = 20, $getCount = false)
|
||||||
{
|
{
|
||||||
$query = $this->buildEntitySearchQuery($terms, $entityType);
|
$query = $this->buildEntitySearchQuery($terms, $entityType);
|
||||||
if ($getCount) return $query->count();
|
if ($getCount) {
|
||||||
|
return $query->count();
|
||||||
|
}
|
||||||
|
|
||||||
$query = $query->skip(($page-1) * $count)->take($count);
|
$query = $query->skip(($page-1) * $count)->take($count);
|
||||||
return $query->get();
|
return $query->get();
|
||||||
|
@ -164,12 +170,12 @@ class SearchService
|
||||||
if (count($terms['search']) > 0) {
|
if (count($terms['search']) > 0) {
|
||||||
$subQuery = $this->db->table('search_terms')->select('entity_id', 'entity_type', \DB::raw('SUM(score) as score'));
|
$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', '=', 'BookStack\\' . ucfirst($entityType));
|
||||||
$subQuery->where(function(Builder $query) use ($terms) {
|
$subQuery->where(function (Builder $query) use ($terms) {
|
||||||
foreach ($terms['search'] as $inputTerm) {
|
foreach ($terms['search'] as $inputTerm) {
|
||||||
$query->orWhere('term', 'like', $inputTerm .'%');
|
$query->orWhere('term', 'like', $inputTerm .'%');
|
||||||
}
|
}
|
||||||
})->groupBy('entity_type', 'entity_id');
|
})->groupBy('entity_type', 'entity_id');
|
||||||
$entitySelect->join(\DB::raw('(' . $subQuery->toSql() . ') as s'), function(JoinClause $join) {
|
$entitySelect->join(\DB::raw('(' . $subQuery->toSql() . ') as s'), function (JoinClause $join) {
|
||||||
$join->on('id', '=', 'entity_id');
|
$join->on('id', '=', 'entity_id');
|
||||||
})->selectRaw($entity->getTable().'.*, s.score')->orderBy('score', 'desc');
|
})->selectRaw($entity->getTable().'.*, s.score')->orderBy('score', 'desc');
|
||||||
$entitySelect->mergeBindings($subQuery);
|
$entitySelect->mergeBindings($subQuery);
|
||||||
|
@ -177,7 +183,7 @@ class SearchService
|
||||||
|
|
||||||
// Handle exact term matching
|
// Handle exact term matching
|
||||||
if (count($terms['exact']) > 0) {
|
if (count($terms['exact']) > 0) {
|
||||||
$entitySelect->where(function(\Illuminate\Database\Eloquent\Builder $query) use ($terms, $entity) {
|
$entitySelect->where(function (\Illuminate\Database\Eloquent\Builder $query) use ($terms, $entity) {
|
||||||
foreach ($terms['exact'] as $inputTerm) {
|
foreach ($terms['exact'] as $inputTerm) {
|
||||||
$query->where(function (\Illuminate\Database\Eloquent\Builder $query) use ($inputTerm, $entity) {
|
$query->where(function (\Illuminate\Database\Eloquent\Builder $query) use ($inputTerm, $entity) {
|
||||||
$query->where('name', 'like', '%'.$inputTerm .'%')
|
$query->where('name', 'like', '%'.$inputTerm .'%')
|
||||||
|
@ -195,7 +201,9 @@ class SearchService
|
||||||
// Handle filters
|
// Handle filters
|
||||||
foreach ($terms['filters'] as $filterTerm => $filterValue) {
|
foreach ($terms['filters'] as $filterTerm => $filterValue) {
|
||||||
$functionName = camel_case('filter_' . $filterTerm);
|
$functionName = camel_case('filter_' . $filterTerm);
|
||||||
if (method_exists($this, $functionName)) $this->$functionName($entitySelect, $entity, $filterValue);
|
if (method_exists($this, $functionName)) {
|
||||||
|
$this->$functionName($entitySelect, $entity, $filterValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->permissionService->enforceEntityRestrictions($entityType, $entitySelect, 'view');
|
return $this->permissionService->enforceEntityRestrictions($entityType, $entitySelect, 'view');
|
||||||
|
@ -234,7 +242,9 @@ class SearchService
|
||||||
|
|
||||||
// Parse standard terms
|
// Parse standard terms
|
||||||
foreach (explode(' ', trim($searchString)) as $searchTerm) {
|
foreach (explode(' ', trim($searchString)) as $searchTerm) {
|
||||||
if ($searchTerm !== '') $terms['search'][] = $searchTerm;
|
if ($searchTerm !== '') {
|
||||||
|
$terms['search'][] = $searchTerm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split filter values out
|
// Split filter values out
|
||||||
|
@ -267,15 +277,18 @@ class SearchService
|
||||||
* @param string $tagTerm
|
* @param string $tagTerm
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
protected function applyTagSearch(\Illuminate\Database\Eloquent\Builder $query, $tagTerm) {
|
protected function applyTagSearch(\Illuminate\Database\Eloquent\Builder $query, $tagTerm)
|
||||||
|
{
|
||||||
preg_match("/^(.*?)((".$this->getRegexEscapedOperators().")(.*?))?$/", $tagTerm, $tagSplit);
|
preg_match("/^(.*?)((".$this->getRegexEscapedOperators().")(.*?))?$/", $tagTerm, $tagSplit);
|
||||||
$query->whereHas('tags', function(\Illuminate\Database\Eloquent\Builder $query) use ($tagSplit) {
|
$query->whereHas('tags', function (\Illuminate\Database\Eloquent\Builder $query) use ($tagSplit) {
|
||||||
$tagName = $tagSplit[1];
|
$tagName = $tagSplit[1];
|
||||||
$tagOperator = count($tagSplit) > 2 ? $tagSplit[3] : '';
|
$tagOperator = count($tagSplit) > 2 ? $tagSplit[3] : '';
|
||||||
$tagValue = count($tagSplit) > 3 ? $tagSplit[4] : '';
|
$tagValue = count($tagSplit) > 3 ? $tagSplit[4] : '';
|
||||||
$validOperator = in_array($tagOperator, $this->queryOperators);
|
$validOperator = in_array($tagOperator, $this->queryOperators);
|
||||||
if (!empty($tagOperator) && !empty($tagValue) && $validOperator) {
|
if (!empty($tagOperator) && !empty($tagValue) && $validOperator) {
|
||||||
if (!empty($tagName)) $query->where('name', '=', $tagName);
|
if (!empty($tagName)) {
|
||||||
|
$query->where('name', '=', $tagName);
|
||||||
|
}
|
||||||
if (is_numeric($tagValue) && $tagOperator !== 'like') {
|
if (is_numeric($tagValue) && $tagOperator !== 'like') {
|
||||||
// We have to do a raw sql query for this since otherwise PDO will quote the value and MySQL will
|
// We have to do a raw sql query for this since otherwise PDO will quote the value and MySQL will
|
||||||
// search the value as a string which prevents being able to do number-based operations
|
// search the value as a string which prevents being able to do number-based operations
|
||||||
|
@ -323,7 +336,8 @@ class SearchService
|
||||||
* Index multiple Entities at once
|
* Index multiple Entities at once
|
||||||
* @param Entity[] $entities
|
* @param Entity[] $entities
|
||||||
*/
|
*/
|
||||||
protected function indexEntities($entities) {
|
protected function indexEntities($entities)
|
||||||
|
{
|
||||||
$terms = [];
|
$terms = [];
|
||||||
foreach ($entities as $entity) {
|
foreach ($entities as $entity) {
|
||||||
$nameTerms = $this->generateTermArrayFromText($entity->name, 5);
|
$nameTerms = $this->generateTermArrayFromText($entity->name, 5);
|
||||||
|
@ -386,7 +400,9 @@ class SearchService
|
||||||
$token = strtok($text, $splitChars);
|
$token = strtok($text, $splitChars);
|
||||||
|
|
||||||
while ($token !== false) {
|
while ($token !== false) {
|
||||||
if (!isset($tokenMap[$token])) $tokenMap[$token] = 0;
|
if (!isset($tokenMap[$token])) {
|
||||||
|
$tokenMap[$token] = 0;
|
||||||
|
}
|
||||||
$tokenMap[$token]++;
|
$tokenMap[$token]++;
|
||||||
$token = strtok($splitChars);
|
$token = strtok($splitChars);
|
||||||
}
|
}
|
||||||
|
@ -410,43 +426,63 @@ class SearchService
|
||||||
|
|
||||||
protected function filterUpdatedAfter(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
protected function filterUpdatedAfter(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
||||||
{
|
{
|
||||||
try { $date = date_create($input);
|
try {
|
||||||
} catch (\Exception $e) {return;}
|
$date = date_create($input);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$query->where('updated_at', '>=', $date);
|
$query->where('updated_at', '>=', $date);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function filterUpdatedBefore(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
protected function filterUpdatedBefore(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
||||||
{
|
{
|
||||||
try { $date = date_create($input);
|
try {
|
||||||
} catch (\Exception $e) {return;}
|
$date = date_create($input);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$query->where('updated_at', '<', $date);
|
$query->where('updated_at', '<', $date);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function filterCreatedAfter(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
protected function filterCreatedAfter(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
||||||
{
|
{
|
||||||
try { $date = date_create($input);
|
try {
|
||||||
} catch (\Exception $e) {return;}
|
$date = date_create($input);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$query->where('created_at', '>=', $date);
|
$query->where('created_at', '>=', $date);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function filterCreatedBefore(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
protected function filterCreatedBefore(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
||||||
{
|
{
|
||||||
try { $date = date_create($input);
|
try {
|
||||||
} catch (\Exception $e) {return;}
|
$date = date_create($input);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$query->where('created_at', '<', $date);
|
$query->where('created_at', '<', $date);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function filterCreatedBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
protected function filterCreatedBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
||||||
{
|
{
|
||||||
if (!is_numeric($input) && $input !== 'me') return;
|
if (!is_numeric($input) && $input !== 'me') {
|
||||||
if ($input === 'me') $input = user()->id;
|
return;
|
||||||
|
}
|
||||||
|
if ($input === 'me') {
|
||||||
|
$input = user()->id;
|
||||||
|
}
|
||||||
$query->where('created_by', '=', $input);
|
$query->where('created_by', '=', $input);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function filterUpdatedBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
protected function filterUpdatedBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
||||||
{
|
{
|
||||||
if (!is_numeric($input) && $input !== 'me') return;
|
if (!is_numeric($input) && $input !== 'me') {
|
||||||
if ($input === 'me') $input = user()->id;
|
return;
|
||||||
|
}
|
||||||
|
if ($input === 'me') {
|
||||||
|
$input = user()->id;
|
||||||
|
}
|
||||||
$query->where('updated_by', '=', $input);
|
$query->where('updated_by', '=', $input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,7 +491,10 @@ class SearchService
|
||||||
$query->where('name', 'like', '%' .$input. '%');
|
$query->where('name', 'like', '%' .$input. '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function filterInTitle(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input) {$this->filterInName($query, $model, $input);}
|
protected function filterInTitle(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
||||||
|
{
|
||||||
|
$this->filterInName($query, $model, $input);
|
||||||
|
}
|
||||||
|
|
||||||
protected function filterInBody(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
protected function filterInBody(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
||||||
{
|
{
|
||||||
|
@ -469,14 +508,14 @@ class SearchService
|
||||||
|
|
||||||
protected function filterViewedByMe(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
protected function filterViewedByMe(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
||||||
{
|
{
|
||||||
$query->whereHas('views', function($query) {
|
$query->whereHas('views', function ($query) {
|
||||||
$query->where('user_id', '=', user()->id);
|
$query->where('user_id', '=', user()->id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function filterNotViewedByMe(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
protected function filterNotViewedByMe(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
||||||
{
|
{
|
||||||
$query->whereDoesntHave('views', function($query) {
|
$query->whereDoesntHave('views', function ($query) {
|
||||||
$query->where('user_id', '=', user()->id);
|
$query->where('user_id', '=', user()->id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -484,7 +523,9 @@ class SearchService
|
||||||
protected function filterSortBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
protected function filterSortBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
|
||||||
{
|
{
|
||||||
$functionName = camel_case('sort_by_' . $input);
|
$functionName = camel_case('sort_by_' . $input);
|
||||||
if (method_exists($this, $functionName)) $this->$functionName($query, $model);
|
if (method_exists($this, $functionName)) {
|
||||||
|
$this->$functionName($query, $model);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -500,4 +541,4 @@ class SearchService
|
||||||
|
|
||||||
$query->join($commentQuery, $model->getTable() . '.id', '=', 'comments.entity_id')->orderBy('last_commented', 'desc');
|
$query->join($commentQuery, $model->getTable() . '.id', '=', 'comments.entity_id')->orderBy('last_commented', 'desc');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,8 +40,12 @@ class SettingService
|
||||||
*/
|
*/
|
||||||
public function get($key, $default = false)
|
public function get($key, $default = false)
|
||||||
{
|
{
|
||||||
if ($default === false) $default = config('setting-defaults.' . $key, false);
|
if ($default === false) {
|
||||||
if (isset($this->localCache[$key])) return $this->localCache[$key];
|
$default = config('setting-defaults.' . $key, false);
|
||||||
|
}
|
||||||
|
if (isset($this->localCache[$key])) {
|
||||||
|
return $this->localCache[$key];
|
||||||
|
}
|
||||||
|
|
||||||
$value = $this->getValueFromStore($key, $default);
|
$value = $this->getValueFromStore($key, $default);
|
||||||
$formatted = $this->formatValue($value, $default);
|
$formatted = $this->formatValue($value, $default);
|
||||||
|
@ -72,12 +76,16 @@ class SettingService
|
||||||
{
|
{
|
||||||
// Check for an overriding value
|
// Check for an overriding value
|
||||||
$overrideValue = $this->getOverrideValue($key);
|
$overrideValue = $this->getOverrideValue($key);
|
||||||
if ($overrideValue !== null) return $overrideValue;
|
if ($overrideValue !== null) {
|
||||||
|
return $overrideValue;
|
||||||
|
}
|
||||||
|
|
||||||
// Check the cache
|
// Check the cache
|
||||||
$cacheKey = $this->cachePrefix . $key;
|
$cacheKey = $this->cachePrefix . $key;
|
||||||
$cacheVal = $this->cache->get($cacheKey, null);
|
$cacheVal = $this->cache->get($cacheKey, null);
|
||||||
if ($cacheVal !== null) return $cacheVal;
|
if ($cacheVal !== null) {
|
||||||
|
return $cacheVal;
|
||||||
|
}
|
||||||
|
|
||||||
// Check the database
|
// Check the database
|
||||||
$settingObject = $this->getSettingObjectByKey($key);
|
$settingObject = $this->getSettingObjectByKey($key);
|
||||||
|
@ -112,11 +120,17 @@ class SettingService
|
||||||
protected function formatValue($value, $default)
|
protected function formatValue($value, $default)
|
||||||
{
|
{
|
||||||
// Change string booleans to actual booleans
|
// Change string booleans to actual booleans
|
||||||
if ($value === 'true') $value = true;
|
if ($value === 'true') {
|
||||||
if ($value === 'false') $value = false;
|
$value = true;
|
||||||
|
}
|
||||||
|
if ($value === 'false') {
|
||||||
|
$value = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Set to default if empty
|
// Set to default if empty
|
||||||
if ($value === '') $value = $default;
|
if ($value === '') {
|
||||||
|
$value = $default;
|
||||||
|
}
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,8 +239,9 @@ class SettingService
|
||||||
*/
|
*/
|
||||||
protected function getOverrideValue($key)
|
protected function getOverrideValue($key)
|
||||||
{
|
{
|
||||||
if ($key === 'registration-enabled' && config('auth.method') === 'ldap') return false;
|
if ($key === 'registration-enabled' && config('auth.method') === 'ldap') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -150,8 +150,12 @@ class SocialAuthService
|
||||||
{
|
{
|
||||||
$driver = trim(strtolower($socialDriver));
|
$driver = trim(strtolower($socialDriver));
|
||||||
|
|
||||||
if (!in_array($driver, $this->validSocialDrivers)) abort(404, trans('errors.social_driver_not_found'));
|
if (!in_array($driver, $this->validSocialDrivers)) {
|
||||||
if (!$this->checkDriverConfigured($driver)) throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => title_case($socialDriver)]));
|
abort(404, trans('errors.social_driver_not_found'));
|
||||||
|
}
|
||||||
|
if (!$this->checkDriverConfigured($driver)) {
|
||||||
|
throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => title_case($socialDriver)]));
|
||||||
|
}
|
||||||
|
|
||||||
return $driver;
|
return $driver;
|
||||||
}
|
}
|
||||||
|
@ -220,5 +224,4 @@ class SocialAuthService
|
||||||
session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => title_case($socialDriver)]));
|
session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => title_case($socialDriver)]));
|
||||||
return redirect(user()->getEditUrl());
|
return redirect(user()->getEditUrl());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -32,7 +32,9 @@ class UploadService
|
||||||
*/
|
*/
|
||||||
protected function getStorage()
|
protected function getStorage()
|
||||||
{
|
{
|
||||||
if ($this->storageInstance !== null) return $this->storageInstance;
|
if ($this->storageInstance !== null) {
|
||||||
|
return $this->storageInstance;
|
||||||
|
}
|
||||||
|
|
||||||
$storageType = config('filesystems.default');
|
$storageType = config('filesystems.default');
|
||||||
$this->storageInstance = $this->fileSystem->disk($storageType);
|
$this->storageInstance = $this->fileSystem->disk($storageType);
|
||||||
|
@ -60,4 +62,4 @@ class UploadService
|
||||||
{
|
{
|
||||||
return strtolower(config('filesystems.default')) === 'local';
|
return strtolower(config('filesystems.default')) === 'local';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,9 @@ class ViewService
|
||||||
public function add(Entity $entity)
|
public function add(Entity $entity)
|
||||||
{
|
{
|
||||||
$user = user();
|
$user = user();
|
||||||
if ($user === null || $user->isDefault()) return 0;
|
if ($user === null || $user->isDefault()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
$view = $entity->views()->where('user_id', '=', $user->id)->first();
|
$view = $entity->views()->where('user_id', '=', $user->id)->first();
|
||||||
// Add view if model exists
|
// Add view if model exists
|
||||||
if ($view) {
|
if ($view) {
|
||||||
|
@ -77,12 +79,16 @@ class ViewService
|
||||||
public function getUserRecentlyViewed($count = 10, $page = 0, $filterModel = false)
|
public function getUserRecentlyViewed($count = 10, $page = 0, $filterModel = false)
|
||||||
{
|
{
|
||||||
$user = user();
|
$user = user();
|
||||||
if ($user === null || $user->isDefault()) return collect();
|
if ($user === null || $user->isDefault()) {
|
||||||
|
return collect();
|
||||||
|
}
|
||||||
|
|
||||||
$query = $this->permissionService
|
$query = $this->permissionService
|
||||||
->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type');
|
->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type');
|
||||||
|
|
||||||
if ($filterModel) $query = $query->where('viewable_type', '=', get_class($filterModel));
|
if ($filterModel) {
|
||||||
|
$query = $query->where('viewable_type', '=', get_class($filterModel));
|
||||||
|
}
|
||||||
$query = $query->where('user_id', '=', $user->id);
|
$query = $query->where('user_id', '=', $user->id);
|
||||||
|
|
||||||
$viewables = $query->with('viewable')->orderBy('updated_at', 'desc')
|
$viewables = $query->with('viewable')->orderBy('updated_at', 'desc')
|
||||||
|
@ -97,5 +103,4 @@ class ViewService
|
||||||
{
|
{
|
||||||
$this->view->truncate();
|
$this->view->truncate();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php namespace BookStack;
|
<?php namespace BookStack;
|
||||||
|
|
||||||
|
|
||||||
class SocialAccount extends Model
|
class SocialAccount extends Model
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -16,4 +16,4 @@ class Tag extends Model
|
||||||
{
|
{
|
||||||
return $this->morphTo('entity');
|
return $this->morphTo('entity');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
26
app/User.php
26
app/User.php
|
@ -60,7 +60,9 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||||
*/
|
*/
|
||||||
public function roles()
|
public function roles()
|
||||||
{
|
{
|
||||||
if ($this->id === 0) return ;
|
if ($this->id === 0) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
return $this->belongsToMany(Role::class);
|
return $this->belongsToMany(Role::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,9 +93,11 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||||
*/
|
*/
|
||||||
public function permissions($cache = true)
|
public function permissions($cache = true)
|
||||||
{
|
{
|
||||||
if(isset($this->permissions) && $cache) return $this->permissions;
|
if (isset($this->permissions) && $cache) {
|
||||||
|
return $this->permissions;
|
||||||
|
}
|
||||||
$this->load('roles.permissions');
|
$this->load('roles.permissions');
|
||||||
$permissions = $this->roles->map(function($role) {
|
$permissions = $this->roles->map(function ($role) {
|
||||||
return $role->permissions;
|
return $role->permissions;
|
||||||
})->flatten()->unique();
|
})->flatten()->unique();
|
||||||
$this->permissions = $permissions;
|
$this->permissions = $permissions;
|
||||||
|
@ -107,7 +111,9 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||||
*/
|
*/
|
||||||
public function can($permissionName)
|
public function can($permissionName)
|
||||||
{
|
{
|
||||||
if ($this->email === 'guest') return false;
|
if ($this->email === 'guest') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return $this->permissions()->pluck('name')->contains($permissionName);
|
return $this->permissions()->pluck('name')->contains($permissionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +168,9 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||||
{
|
{
|
||||||
$default = baseUrl('/user_avatar.png');
|
$default = baseUrl('/user_avatar.png');
|
||||||
$imageId = $this->image_id;
|
$imageId = $this->image_id;
|
||||||
if ($imageId === 0 || $imageId === '0' || $imageId === null) return $default;
|
if ($imageId === 0 || $imageId === '0' || $imageId === null) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$avatar = $this->avatar ? baseUrl($this->avatar->getThumb($size, $size, false)) : $default;
|
$avatar = $this->avatar ? baseUrl($this->avatar->getThumb($size, $size, false)) : $default;
|
||||||
|
@ -206,10 +214,14 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||||
*/
|
*/
|
||||||
public function getShortName($chars = 8)
|
public function getShortName($chars = 8)
|
||||||
{
|
{
|
||||||
if (strlen($this->name) <= $chars) return $this->name;
|
if (strlen($this->name) <= $chars) {
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
$splitName = explode(' ', $this->name);
|
$splitName = explode(' ', $this->name);
|
||||||
if (strlen($splitName[0]) <= $chars) return $splitName[0];
|
if (strlen($splitName[0]) <= $chars) {
|
||||||
|
return $splitName[0];
|
||||||
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,9 @@ function userCan($permission, Ownable $ownable = null)
|
||||||
function setting($key = null, $default = false)
|
function setting($key = null, $default = false)
|
||||||
{
|
{
|
||||||
$settingService = resolve(\BookStack\Services\SettingService::class);
|
$settingService = resolve(\BookStack\Services\SettingService::class);
|
||||||
if (is_null($key)) return $settingService;
|
if (is_null($key)) {
|
||||||
|
return $settingService;
|
||||||
|
}
|
||||||
return $settingService->get($key, $default);
|
return $settingService->get($key, $default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +89,9 @@ function setting($key = null, $default = false)
|
||||||
function baseUrl($path, $forceAppDomain = false)
|
function baseUrl($path, $forceAppDomain = false)
|
||||||
{
|
{
|
||||||
$isFullUrl = strpos($path, 'http') === 0;
|
$isFullUrl = strpos($path, 'http') === 0;
|
||||||
if ($isFullUrl && !$forceAppDomain) return $path;
|
if ($isFullUrl && !$forceAppDomain) {
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
$path = trim($path, '/');
|
$path = trim($path, '/');
|
||||||
|
|
||||||
// Remove non-specified domain if forced and we have a domain
|
// Remove non-specified domain if forced and we have a domain
|
||||||
|
@ -126,7 +130,8 @@ function redirect($to = null, $status = 302, $headers = [], $secure = null)
|
||||||
return app('redirect')->to($to, $status, $headers, $secure);
|
return app('redirect')->to($to, $status, $headers, $secure);
|
||||||
}
|
}
|
||||||
|
|
||||||
function icon($name, $attrs = []) {
|
function icon($name, $attrs = [])
|
||||||
|
{
|
||||||
$iconPath = resource_path('assets/icons/' . $name . '.svg');
|
$iconPath = resource_path('assets/icons/' . $name . '.svg');
|
||||||
$attrString = ' ';
|
$attrString = ' ';
|
||||||
foreach ($attrs as $attrName => $attr) {
|
foreach ($attrs as $attrName => $attr) {
|
||||||
|
@ -159,11 +164,15 @@ function sortUrl($path, $data, $overrideData = [])
|
||||||
|
|
||||||
foreach ($queryData as $name => $value) {
|
foreach ($queryData as $name => $value) {
|
||||||
$trimmedVal = trim($value);
|
$trimmedVal = trim($value);
|
||||||
if ($trimmedVal === '') continue;
|
if ($trimmedVal === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$queryStringSections[] = urlencode($name) . '=' . urlencode($trimmedVal);
|
$queryStringSections[] = urlencode($name) . '=' . urlencode($trimmedVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($queryStringSections) === 0) return $path;
|
if (count($queryStringSections) === 0) {
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
return baseUrl($path . '?' . implode('&', $queryStringSections));
|
return baseUrl($path . '?' . implode('&', $queryStringSections));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,8 @@
|
||||||
"symfony/dom-crawler": "3.1.*",
|
"symfony/dom-crawler": "3.1.*",
|
||||||
"laravel/browser-kit-testing": "^2.0",
|
"laravel/browser-kit-testing": "^2.0",
|
||||||
"barryvdh/laravel-ide-helper": "^2.4.1",
|
"barryvdh/laravel-ide-helper": "^2.4.1",
|
||||||
"barryvdh/laravel-debugbar": "^3.1.0"
|
"barryvdh/laravel-debugbar": "^3.1.0",
|
||||||
|
"squizlabs/php_codesniffer": "^3.2"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": [
|
"classmap": [
|
||||||
|
|
53
composer.lock
generated
53
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "7d60f09393b99551e9ffdb6622ed7ade",
|
"content-hash": "8ad5cb7acc1115a77404d1be899984ac",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "aws/aws-sdk-php",
|
"name": "aws/aws-sdk-php",
|
||||||
|
@ -5027,6 +5027,57 @@
|
||||||
"homepage": "https://github.com/sebastianbergmann/version",
|
"homepage": "https://github.com/sebastianbergmann/version",
|
||||||
"time": "2016-10-03T07:35:21+00:00"
|
"time": "2016-10-03T07:35:21+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "squizlabs/php_codesniffer",
|
||||||
|
"version": "3.2.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
||||||
|
"reference": "d7c00c3000ac0ce79c96fcbfef86b49a71158cd1"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/d7c00c3000ac0ce79c96fcbfef86b49a71158cd1",
|
||||||
|
"reference": "d7c00c3000ac0ce79c96fcbfef86b49a71158cd1",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"ext-tokenizer": "*",
|
||||||
|
"ext-xmlwriter": "*",
|
||||||
|
"php": ">=5.4.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/phpcs",
|
||||||
|
"bin/phpcbf"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Greg Sherwood",
|
||||||
|
"role": "lead"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
||||||
|
"homepage": "http://www.squizlabs.com/php-codesniffer",
|
||||||
|
"keywords": [
|
||||||
|
"phpcs",
|
||||||
|
"standards"
|
||||||
|
],
|
||||||
|
"time": "2017-12-19T21:44:46+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/class-loader",
|
"name": "symfony/class-loader",
|
||||||
"version": "v3.3.6",
|
"version": "v3.3.6",
|
||||||
|
|
8
phpcs.xml
Normal file
8
phpcs.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<ruleset name="PHP_CodeSniffer">
|
||||||
|
<description>The coding standard for BookStack.</description>
|
||||||
|
<file>app</file>
|
||||||
|
<exclude-pattern>*/migrations/*</exclude-pattern>
|
||||||
|
<arg value="np"/>
|
||||||
|
<rule ref="PSR2"/>
|
||||||
|
</ruleset>
|
|
@ -72,7 +72,11 @@ Some strings have colon-prefixed variables in such as `:userName`. Leave these v
|
||||||
|
|
||||||
Feel free to create issues to request new features or to report bugs and problems. Just please follow the template given when creating the issue.
|
Feel free to create issues to request new features or to report bugs and problems. Just please follow the template given when creating the issue.
|
||||||
|
|
||||||
### Pull Request
|
### Standards
|
||||||
|
|
||||||
|
PHP code within BookStack is generally to [PSR-2](http://www.php-fig.org/psr/psr-2/) standards. From the BookStack root folder you can run `./vendor/bin/phpcs` to check code is formatted correctly and `./vendor/bin/phpcbf` to auto-fix non-PSR-2 code.
|
||||||
|
|
||||||
|
### Pull Requests
|
||||||
|
|
||||||
Pull requests are very welcome. If the scope of your pull request is large it may be best to open the pull request early or create an issue for it to discuss how it will fit in to the project and plan out the merge.
|
Pull requests are very welcome. If the scope of your pull request is large it may be best to open the pull request early or create an issue for it to discuss how it will fit in to the project and plan out the merge.
|
||||||
|
|
||||||
|
@ -111,3 +115,4 @@ These are the great open-source projects used to help build BookStack:
|
||||||
* [Snappy (WKHTML2PDF)](https://github.com/barryvdh/laravel-snappy)
|
* [Snappy (WKHTML2PDF)](https://github.com/barryvdh/laravel-snappy)
|
||||||
* [Laravel IDE helper](https://github.com/barryvdh/laravel-ide-helper)
|
* [Laravel IDE helper](https://github.com/barryvdh/laravel-ide-helper)
|
||||||
* [WKHTMLtoPDF](http://wkhtmltopdf.org/index.html)
|
* [WKHTMLtoPDF](http://wkhtmltopdf.org/index.html)
|
||||||
|
* [Draw.io](https://github.com/jgraph/drawio)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue