diff --git a/.env.example b/.env.example
index ddb32c0bc..80afb6274 100644
--- a/.env.example
+++ b/.env.example
@@ -47,10 +47,15 @@ GITHUB_APP_SECRET=false
GOOGLE_APP_ID=false
GOOGLE_APP_SECRET=false
OKTA_BASE_URL=false
-OKTA_KEY=false
-OKTA_SECRET=false
+OKTA_APP_ID=false
+OKTA_APP_SECRET=false
+TWITCH_APP_ID=false
+TWITCH_APP_SECRET=false
+GITLAB_APP_ID=false
+GITLAB_APP_SECRET=false
+GITLAB_BASE_URI=false
-# External services such as Gravatar
+# External services such as Gravatar and Draw.IO
DISABLE_EXTERNAL_SERVICES=false
# LDAP Settings
@@ -67,4 +72,4 @@ MAIL_HOST=localhost
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
-MAIL_ENCRYPTION=null
\ No newline at end of file
+MAIL_ENCRYPTION=null
diff --git a/app/Activity.php b/app/Activity.php
index af386700a..c01da1f6c 100644
--- a/app/Activity.php
+++ b/app/Activity.php
@@ -16,7 +16,9 @@ class Activity extends Model
*/
public function entity()
{
- if ($this->entity_type === '') $this->entity_type = null;
+ if ($this->entity_type === '') {
+ $this->entity_type = null;
+ }
return $this->morphTo('entity');
}
@@ -43,8 +45,8 @@ class Activity extends Model
* @param $activityB
* @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];
}
-
}
diff --git a/app/Attachment.php b/app/Attachment.php
index fe291bec2..55344cd7d 100644
--- a/app/Attachment.php
+++ b/app/Attachment.php
@@ -1,6 +1,5 @@
name, '.')) return $this->name;
+ if (str_contains($this->name, '.')) {
+ return $this->name;
+ }
return $this->name . '.' . $this->extension;
}
@@ -32,5 +33,4 @@ class Attachment extends Ownable
{
return baseUrl('/attachments/' . $this->id);
}
-
}
diff --git a/app/Book.php b/app/Book.php
index 3fb87b4c5..457a4c928 100644
--- a/app/Book.php
+++ b/app/Book.php
@@ -27,7 +27,9 @@ class Book extends Entity
public function getBookCover($width = 440, $height = 250)
{
$default = baseUrl('/book_default_cover.png');
- if (!$this->image_id) return $default;
+ if (!$this->image_id) {
+ return $default;
+ }
try {
$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";
}
-
}
diff --git a/app/Chapter.php b/app/Chapter.php
index b08cb913a..6dab9dc47 100644
--- a/app/Chapter.php
+++ b/app/Chapter.php
@@ -1,6 +1,5 @@
textField} as text, '' as html, book_id, priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at";
}
-
}
diff --git a/app/Console/Commands/CreateAdmin.php b/app/Console/Commands/CreateAdmin.php
new file mode 100644
index 000000000..c7a9969e8
--- /dev/null
+++ b/app/Console/Commands/CreateAdmin.php
@@ -0,0 +1,85 @@
+userRepo = $userRepo;
+ parent::__construct();
+ }
+
+ /**
+ * Execute the console command.
+ *
+ * @return mixed
+ * @throws \BookStack\Exceptions\NotFoundException
+ */
+ public function handle()
+ {
+ $email = trim($this->option('email'));
+ if (empty($email)) {
+ $email = $this->ask('Please specify an email address for the new admin user');
+ }
+ if (strlen($email) < 5 || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ return $this->error('Invalid email address provided');
+ }
+
+ if ($this->userRepo->getByEmail($email) !== null) {
+ return $this->error('A user with the provided email already exists!');
+ }
+
+ $name = trim($this->option('name'));
+ if (empty($name)) {
+ $name = $this->ask('Please specify an name for the new admin user');
+ }
+ if (strlen($name) < 2) {
+ return $this->error('Invalid name provided');
+ }
+
+ $password = trim($this->option('password'));
+ if (empty($password)) {
+ $password = $this->secret('Please specify a password for the new admin user');
+ }
+ if (strlen($password) < 5) {
+ return $this->error('Invalid password provided, Must be at least 5 characters');
+ }
+
+
+ $user = $this->userRepo->create(['email' => $email, 'name' => $name, 'password' => $password]);
+ $this->userRepo->attachSystemRole($user, 'admin');
+ $this->userRepo->downloadGravatarToUserAvatar($user);
+ $user->email_confirmed = true;
+ $user->save();
+
+ $this->info("Admin account with email \"{$user->email}\" successfully created!");
+ }
+}
diff --git a/app/Console/Commands/DeleteUsers.php b/app/Console/Commands/DeleteUsers.php
new file mode 100644
index 000000000..6dba83e13
--- /dev/null
+++ b/app/Console/Commands/DeleteUsers.php
@@ -0,0 +1,57 @@
+user = $user;
+ $this->userRepo = $userRepo;
+ parent::__construct();
+ }
+
+ public function handle()
+ {
+ $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;
+ if (strtolower(trim($confirm)) === 'yes') {
+ $totalUsers = $this->user->count();
+ $users = $this->user->where('system_name', '=', null)->with('roles')->get();
+ foreach ($users as $user) {
+ if ($user->hasSystemRole('admin')) {
+ // don't delete users with "admin" role
+ continue;
+ }
+ $this->userRepo->destroy($user);
+ ++$numDeleted;
+ }
+ $this->info("Deleted $numDeleted of $totalUsers total users.");
+ } else {
+ $this->info('Exiting...');
+ }
+ }
+}
diff --git a/app/Entity.php b/app/Entity.php
index df8e4d38b..1ea4e8dac 100644
--- a/app/Entity.php
+++ b/app/Entity.php
@@ -1,6 +1,5 @@
id] === [get_class($entity), $entity->id];
- if ($matches) return true;
+ if ($matches) {
+ return true;
+ }
if (($entity->isA('chapter') || $entity->isA('page')) && $this->isA('book')) {
return $entity->book_id === $this->id;
@@ -159,7 +160,9 @@ class Entity extends Ownable
*/
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) . '...';
}
@@ -176,13 +179,18 @@ class Entity extends Ownable
* Return a generalised, common raw query that can be 'unioned' across entities.
* @return string
*/
- public function entityRawQuery(){return '';}
+ public function entityRawQuery()
+ {
+ return '';
+ }
/**
* Get the url of this entity
* @param $path
* @return string
*/
- public function getUrl($path){return '/';}
-
+ public function getUrl($path)
+ {
+ return '/';
+ }
}
diff --git a/app/EntityPermission.php b/app/EntityPermission.php
index eaf0a8951..0f49e07f5 100644
--- a/app/EntityPermission.php
+++ b/app/EntityPermission.php
@@ -1,6 +1,5 @@
view('errors/' . $code, ['message' => $message], $code);
}
+ // Handle 404 errors with a loaded session to enable showing user-specific information
+ if ($this->isExceptionType($e, NotFoundHttpException::class)) {
+ return $this->loadErrorMiddleware($request, function ($request) use ($e) {
+ $message = $e->getMessage() ?: trans('errors.404_page_not_found');
+ return response()->view('errors/404', ['message' => $message], 404);
+ });
+ }
+
return parent::render($request, $e);
}
+ /**
+ * Load the middleware required to show state/session-enabled error pages.
+ * @param Request $request
+ * @param $callback
+ * @return mixed
+ */
+ protected function loadErrorMiddleware(Request $request, $callback)
+ {
+ $middleware = (\Route::getMiddlewareGroups()['web_errors']);
+ return (new Pipeline($this->container))
+ ->send($request)
+ ->through($middleware)
+ ->then($callback);
+ }
+
/**
* Check the exception chain to compare against the original exception type.
* @param Exception $e
* @param $type
* @return bool
*/
- protected function isExceptionType(Exception $e, $type) {
+ protected function isExceptionType(Exception $e, $type)
+ {
do {
- if (is_a($e, $type)) return true;
+ if (is_a($e, $type)) {
+ return true;
+ }
} while ($e = $e->getPrevious());
return false;
}
@@ -81,7 +110,8 @@ class Handler extends ExceptionHandler
* @param Exception $e
* @return string
*/
- protected function getOriginalMessage(Exception $e) {
+ protected function getOriginalMessage(Exception $e)
+ {
do {
$message = $e->getMessage();
} while ($e = $e->getPrevious());
diff --git a/app/Exceptions/ImageUploadException.php b/app/Exceptions/ImageUploadException.php
index 6f4c73037..c64dddaa2 100644
--- a/app/Exceptions/ImageUploadException.php
+++ b/app/Exceptions/ImageUploadException.php
@@ -1,3 +1,6 @@
redirectLocation = $redirectLocation;
parent::__construct();
}
-}
\ No newline at end of file
+}
diff --git a/app/Exceptions/PermissionsException.php b/app/Exceptions/PermissionsException.php
index ae4c676d6..e2a8c53b4 100644
--- a/app/Exceptions/PermissionsException.php
+++ b/app/Exceptions/PermissionsException.php
@@ -1,6 +1,8 @@
attachment->findOrFail($attachmentId);
$page = $this->entityRepo->getById('page', $attachment->uploaded_to);
+ if ($page === null) {
+ throw new NotFoundException(trans('errors.attachment_not_found'));
+ }
+
$this->checkOwnablePermission('page-view', $page);
if ($attachment->external) {
@@ -204,6 +210,7 @@ class AttachmentController extends Controller
* Delete a specific attachment in the system.
* @param $attachmentId
* @return mixed
+ * @throws \Exception
*/
public function delete($attachmentId)
{
diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php
index d1fbddc50..a0cbae9c6 100644
--- a/app/Http/Controllers/Auth/ForgotPasswordController.php
+++ b/app/Http/Controllers/Auth/ForgotPasswordController.php
@@ -64,5 +64,4 @@ class ForgotPasswordController extends Controller
['email' => trans($response)]
);
}
-
-}
\ No newline at end of file
+}
diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php
index 3617652c2..106b90524 100644
--- a/app/Http/Controllers/Auth/LoginController.php
+++ b/app/Http/Controllers/Auth/LoginController.php
@@ -70,7 +70,9 @@ class LoginController extends Controller
protected function authenticated(Request $request, Authenticatable $user)
{
// 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')) {
$request->flash();
@@ -83,7 +85,6 @@ class LoginController extends Controller
}
if (!$user->exists) {
-
// Check for users with same email already
$alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0;
if ($alreadyUser) {
@@ -130,4 +131,4 @@ class LoginController extends Controller
session()->put('social-callback', 'login');
return $this->socialAuthService->startLogIn($socialDriver);
}
-}
\ No newline at end of file
+}
diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php
index 5a7a5e971..1bbd5e2ba 100644
--- a/app/Http/Controllers/Auth/RegisterController.php
+++ b/app/Http/Controllers/Auth/RegisterController.php
@@ -91,6 +91,7 @@ class RegisterController extends Controller
/**
* Show the application registration form.
* @return Response
+ * @throws UserRegistrationException
*/
public function getRegister()
{
@@ -102,20 +103,13 @@ class RegisterController extends Controller
/**
* Handle a registration request for the application.
* @param Request|\Illuminate\Http\Request $request
- * @return Response
+ * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws UserRegistrationException
- * @throws \Illuminate\Validation\ValidationException
*/
public function postRegister(Request $request)
{
$this->checkRegistrationAllowed();
- $validator = $this->validator($request->all());
-
- if ($validator->fails()) {
- $this->throwValidationException(
- $request, $validator
- );
- }
+ $this->validator($request->all())->validate();
$userData = $request->all();
return $this->registerUser($userData);
@@ -141,7 +135,6 @@ class RegisterController extends Controller
* @param bool|false|SocialAccount $socialAccount
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws UserRegistrationException
- * @throws ConfirmationEmailException
*/
protected function registerUser(array $userData, $socialAccount = false)
{
@@ -239,6 +232,8 @@ class RegisterController extends Controller
* Redirect to the social site for authentication intended to register.
* @param $socialDriver
* @return mixed
+ * @throws UserRegistrationException
+ * @throws \BookStack\Exceptions\SocialDriverNotConfigured
*/
public function socialRegister($socialDriver)
{
@@ -272,8 +267,12 @@ class RegisterController extends Controller
}
$action = session()->pull('social-callback');
- if ($action == 'login') return $this->socialAuthService->handleLoginCallback($socialDriver);
- if ($action == 'register') return $this->socialRegisterCallback($socialDriver);
+ if ($action == 'login') {
+ return $this->socialAuthService->handleLoginCallback($socialDriver);
+ }
+ if ($action == 'register') {
+ return $this->socialRegisterCallback($socialDriver);
+ }
return redirect()->back();
}
@@ -291,7 +290,6 @@ class RegisterController extends Controller
* Register a new user after a registration callback.
* @param $socialDriver
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
- * @throws ConfirmationEmailException
* @throws UserRegistrationException
* @throws \BookStack\Exceptions\SocialDriverNotConfigured
*/
@@ -308,5 +306,4 @@ class RegisterController extends Controller
];
return $this->registerUser($userData, $socialAccount);
}
-
-}
\ No newline at end of file
+}
diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php
index eb678503d..56f1cf026 100644
--- a/app/Http/Controllers/Auth/ResetPasswordController.php
+++ b/app/Http/Controllers/Auth/ResetPasswordController.php
@@ -46,4 +46,4 @@ class ResetPasswordController extends Controller
return redirect($this->redirectPath())
->with('status', trans($response));
}
-}
\ No newline at end of file
+}
diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php
index e181aec89..2c3946239 100644
--- a/app/Http/Controllers/BookController.php
+++ b/app/Http/Controllers/BookController.php
@@ -36,17 +36,17 @@ class BookController extends Controller
*/
public function index()
{
- $books = $this->entityRepo->getAllPaginated('book', 20);
+ $books = $this->entityRepo->getAllPaginated('book', 18);
$recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false;
$popular = $this->entityRepo->getPopular('book', 4, 0);
$new = $this->entityRepo->getRecentlyCreated('book', 4, 0);
- $booksViewType = setting()->getUser($this->currentUser, 'books_view_type', 'list');
+ $booksViewType = setting()->getUser($this->currentUser, 'books_view_type', config('app.views.books', 'list'));
$this->setPageTitle(trans('entities.books'));
return view('books/index', [
'books' => $books,
'recents' => $recents,
'popular' => $popular,
- 'new' => $new,
+ 'new' => $new,
'booksViewType' => $booksViewType
]);
}
@@ -109,7 +109,7 @@ class BookController extends Controller
{
$book = $this->entityRepo->getBySlug('book', $slug);
$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]);
}
@@ -155,7 +155,7 @@ class BookController extends Controller
$book = $this->entityRepo->getBySlug('book', $bookSlug);
$this->checkOwnablePermission('book-update', $book);
$bookChildren = $this->entityRepo->getBookChildren($book, true);
- $books = $this->entityRepo->getAll('book', false);
+ $books = $this->entityRepo->getAll('book', false, 'update');
$this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()]));
return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books, 'bookChildren' => $bookChildren]);
}
@@ -190,42 +190,56 @@ class BookController extends Controller
}
// Sort pages and chapters
- $sortedBooks = [];
- $updatedModels = collect();
- $sortMap = json_decode($request->get('sort-tree'));
- $defaultBookId = $book->id;
+ $sortMap = collect(json_decode($request->get('sort-tree')));
+ $bookIdsInvolved = collect([$book->id]);
- // Loop through contents of provided map and update entities accordingly
- foreach ($sortMap as $bookChild) {
- $priority = $bookChild->sort;
- $id = intval($bookChild->id);
- $isPage = $bookChild->type == 'page';
- $bookId = $this->entityRepo->exists('book', $bookChild->book) ? intval($bookChild->book) : $defaultBookId;
- $chapterId = ($isPage && $bookChild->parentChapter === false) ? 0 : intval($bookChild->parentChapter);
- $model = $this->entityRepo->getById($isPage?'page':'chapter', $id);
+ // Load models into map
+ $sortMap->each(function ($mapItem) use ($bookIdsInvolved) {
+ $mapItem->type = ($mapItem->type === 'page' ? 'page' : 'chapter');
+ $mapItem->model = $this->entityRepo->getById($mapItem->type, $mapItem->id);
+ // Store source and target books
+ $bookIdsInvolved->push(intval($mapItem->model->book_id));
+ $bookIdsInvolved->push(intval($mapItem->book));
+ });
- // Update models only if there's a change in parent chain or ordering.
- if ($model->priority !== $priority || $model->book_id !== $bookId || ($isPage && $model->chapter_id !== $chapterId)) {
- $this->entityRepo->changeBook($isPage?'page':'chapter', $bookId, $model);
- $model->priority = $priority;
- if ($isPage) $model->chapter_id = $chapterId;
+ // Get the books involved in the sort
+ $bookIdsInvolved = $bookIdsInvolved->unique()->toArray();
+ $booksInvolved = $this->entityRepo->book->newQuery()->whereIn('id', $bookIdsInvolved)->get();
+ // Throw permission error if invalid ids or inaccessible books given.
+ if (count($bookIdsInvolved) !== count($booksInvolved)) {
+ $this->showPermissionError();
+ }
+ // Check permissions of involved books
+ $booksInvolved->each(function (Book $book) {
+ $this->checkOwnablePermission('book-update', $book);
+ });
+
+ // Perform the sort
+ $sortMap->each(function ($mapItem) {
+ $model = $mapItem->model;
+
+ $priorityChanged = intval($model->priority) !== intval($mapItem->sort);
+ $bookChanged = intval($model->book_id) !== intval($mapItem->book);
+ $chapterChanged = ($mapItem->type === 'page') && intval($model->chapter_id) !== $mapItem->parentChapter;
+
+ if ($bookChanged) {
+ $this->entityRepo->changeBook($mapItem->type, $mapItem->book, $model);
+ }
+ if ($chapterChanged) {
+ $model->chapter_id = intval($mapItem->parentChapter);
$model->save();
- $updatedModels->push($model);
}
-
- // Store involved books to be sorted later
- if (!in_array($bookId, $sortedBooks)) {
- $sortedBooks[] = $bookId;
+ if ($priorityChanged) {
+ $model->priority = intval($mapItem->sort);
+ $model->save();
}
- }
+ });
- // Add activity for books
- foreach ($sortedBooks as $bookId) {
- /** @var Book $updatedBook */
- $updatedBook = $this->entityRepo->getById('book', $bookId);
- $this->entityRepo->buildJointPermissionsForBook($updatedBook);
- Activity::add($updatedBook, 'book_sort', $updatedBook->id);
- }
+ // Rebuild permissions and add activity for involved books.
+ $booksInvolved->each(function (Book $book) {
+ $this->entityRepo->buildJointPermissionsForBook($book);
+ Activity::add($book, 'book_sort', $book->id);
+ });
return redirect($book->getUrl());
}
diff --git a/app/Http/Controllers/ChapterController.php b/app/Http/Controllers/ChapterController.php
index ceeb2a3ef..a4e0b6409 100644
--- a/app/Http/Controllers/ChapterController.php
+++ b/app/Http/Controllers/ChapterController.php
@@ -159,7 +159,8 @@ class ChapterController extends Controller
* @return mixed
* @throws \BookStack\Exceptions\NotFoundException
*/
- public function showMove($bookSlug, $chapterSlug) {
+ public function showMove($bookSlug, $chapterSlug)
+ {
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
$this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()]));
$this->checkOwnablePermission('chapter-update', $chapter);
@@ -177,7 +178,8 @@ class ChapterController extends Controller
* @return mixed
* @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);
$this->checkOwnablePermission('chapter-update', $chapter);
diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php
index 733d5416b..a51ff5d77 100644
--- a/app/Http/Controllers/Controller.php
+++ b/app/Http/Controllers/Controller.php
@@ -51,7 +51,9 @@ abstract class Controller extends BaseController
*/
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)
{
- if (userCan($permission, $ownable)) return true;
+ if (userCan($permission, $ownable)) {
+ return true;
+ }
return $this->showPermissionError();
}
@@ -113,7 +117,9 @@ abstract class Controller extends BaseController
protected function checkPermissionOr($permissionName, $callback)
{
$callbackResult = $callback();
- if ($callbackResult === false) $this->checkPermission($permissionName);
+ if ($callbackResult === false) {
+ $this->checkPermission($permissionName);
+ }
return true;
}
@@ -145,5 +151,4 @@ abstract class Controller extends BaseController
->withInput($request->input())
->withErrors($errors, $this->errorBag());
}
-
}
diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php
index 164becd4d..b2620588f 100644
--- a/app/Http/Controllers/HomeController.php
+++ b/app/Http/Controllers/HomeController.php
@@ -56,7 +56,8 @@ class HomeController extends Controller
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
* @throws \Exception
*/
- public function getTranslations() {
+ public function getTranslations()
+ {
$locale = app()->getLocale();
$cacheKey = 'GLOBAL_TRANSLATIONS_' . $locale;
if (cache()->has($cacheKey) && config('app.env') !== 'development') {
@@ -95,5 +96,4 @@ class HomeController extends Controller
{
return view('partials/custom-head-content');
}
-
}
diff --git a/app/Http/Controllers/ImageController.php b/app/Http/Controllers/ImageController.php
index d40f88255..a61f447eb 100644
--- a/app/Http/Controllers/ImageController.php
+++ b/app/Http/Controllers/ImageController.php
@@ -1,6 +1,7 @@
file($path);
+ }
+
/**
* Get all images for a specific type, Paginated
* @param string $type
@@ -47,14 +63,14 @@ class ImageController extends Controller
* @param Request $request
* @return mixed
*/
- public function searchByType($type, $page = 0, Request $request)
+ public function searchByType(Request $request, $type, $page = 0)
{
$this->validate($request, [
'term' => 'required|string'
]);
$searchTerm = $request->get('term');
- $imgData = $this->imageRepo->searchPaginatedByType($type, $page, 24, $searchTerm);
+ $imgData = $this->imageRepo->searchPaginatedByType($type, $searchTerm, $page, 24);
return response()->json($imgData);
}
@@ -76,17 +92,19 @@ class ImageController extends Controller
* @param Request $request
* @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, [
'page_id' => 'required|integer'
]);
$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');
- $imgData = $this->imageRepo->getGalleryFiltered($page, 24, strtolower($filter), $pageId);
+ $imgData = $this->imageRepo->getGalleryFiltered(strtolower($filter), $pageId, $page, 24);
return response()->json($imgData);
}
@@ -96,6 +114,7 @@ class ImageController extends Controller
* @param string $type
* @param Request $request
* @return \Illuminate\Http\JsonResponse
+ * @throws \Exception
*/
public function uploadByType($type, Request $request)
{
@@ -104,10 +123,14 @@ class ImageController extends Controller
'file' => 'is_image'
]);
+ if (!$this->imageRepo->isValidType($type)) {
+ return $this->jsonError(trans('errors.image_upload_type_error'));
+ }
+
$imageUpload = $request->file('file');
try {
- $uploadedTo = $request->filled('uploaded_to') ? $request->get('uploaded_to') : 0;
+ $uploadedTo = $request->get('uploaded_to', 0);
$image = $this->imageRepo->saveNew($imageUpload, $type, $uploadedTo);
} catch (ImageUploadException $e) {
return response($e->getMessage(), 500);
@@ -116,6 +139,73 @@ class ImageController extends Controller
return response()->json($image);
}
+ /**
+ * Upload a drawing to the system.
+ * @param Request $request
+ * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
+ */
+ public function uploadDrawing(Request $request)
+ {
+ $this->validate($request, [
+ 'image' => 'required|string',
+ 'uploaded_to' => 'required|integer'
+ ]);
+ $this->checkPermission('image-create-all');
+ $imageBase64Data = $request->get('image');
+
+ try {
+ $uploadedTo = $request->get('uploaded_to', 0);
+ $image = $this->imageRepo->saveDrawing($imageBase64Data, $uploadedTo);
+ } catch (ImageUploadException $e) {
+ return response($e->getMessage(), 500);
+ }
+
+ return response()->json($image);
+ }
+
+ /**
+ * Replace the data content of a drawing.
+ * @param string $id
+ * @param Request $request
+ * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
+ */
+ public function replaceDrawing(string $id, Request $request)
+ {
+ $this->validate($request, [
+ 'image' => 'required|string'
+ ]);
+ $this->checkPermission('image-create-all');
+
+ $imageBase64Data = $request->get('image');
+ $image = $this->imageRepo->getById($id);
+ $this->checkOwnablePermission('image-update', $image);
+
+ try {
+ $image = $this->imageRepo->replaceDrawingContent($image, $imageBase64Data);
+ } catch (ImageUploadException $e) {
+ return response($e->getMessage(), 500);
+ }
+
+ return response()->json($image);
+ }
+
+ /**
+ * Get the content of an image based64 encoded.
+ * @param $id
+ * @return \Illuminate\Http\JsonResponse|mixed
+ */
+ public function getBase64Image($id)
+ {
+ $image = $this->imageRepo->getById($id);
+ $imageData = $this->imageRepo->getImageData($image);
+ if ($imageData === null) {
+ return $this->jsonError("Image data could not be found");
+ }
+ return response()->json([
+ 'content' => base64_encode($imageData)
+ ]);
+ }
+
/**
* Generate a sized thumbnail for an image.
* @param $id
@@ -123,6 +213,8 @@ class ImageController extends Controller
* @param $height
* @param $crop
* @return \Illuminate\Http\JsonResponse
+ * @throws ImageUploadException
+ * @throws \Exception
*/
public function getThumbnail($id, $width, $height, $crop)
{
@@ -137,6 +229,8 @@ class ImageController extends Controller
* @param integer $imageId
* @param Request $request
* @return \Illuminate\Http\JsonResponse
+ * @throws ImageUploadException
+ * @throws \Exception
*/
public function update($imageId, Request $request)
{
@@ -173,6 +267,4 @@ class ImageController extends Controller
$this->imageRepo->destroyImage($image);
return response()->json(trans('components.images_deleted'));
}
-
-
}
diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php
index 13e928465..17bce7eba 100644
--- a/app/Http/Controllers/PageController.php
+++ b/app/Http/Controllers/PageController.php
@@ -145,6 +145,7 @@ class PageController extends Controller
* @param string $bookSlug
* @param string $pageSlug
* @return Response
+ * @throws NotFoundException
*/
public function show($bookSlug, $pageSlug)
{
@@ -152,7 +153,9 @@ class PageController extends Controller
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
} catch (NotFoundException $e) {
$page = $this->entityRepo->getPageByOldSlug($pageSlug, $bookSlug);
- if ($page === null) abort(404);
+ if ($page === null) {
+ throw $e;
+ }
return redirect($page->getUrl());
}
@@ -219,7 +222,9 @@ class PageController extends Controller
$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;
return view('pages/edit', [
@@ -603,5 +608,4 @@ class PageController extends Controller
session()->flash('success', trans('entities.pages_permissions_success'));
return redirect($page->getUrl());
}
-
}
diff --git a/app/Http/Controllers/PermissionController.php b/app/Http/Controllers/PermissionController.php
index cd064e7e8..c4c7fe972 100644
--- a/app/Http/Controllers/PermissionController.php
+++ b/app/Http/Controllers/PermissionController.php
@@ -67,7 +67,9 @@ class PermissionController extends Controller
{
$this->checkPermission('user-roles-manage');
$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]);
}
diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php
index 0faeb0dec..0827eeb71 100644
--- a/app/Http/Controllers/SearchController.php
+++ b/app/Http/Controllers/SearchController.php
@@ -104,7 +104,4 @@ class SearchController extends Controller
return view('search/entity-ajax-list', ['entities' => $entities]);
}
-
}
-
-
diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php
index 70a12631a..e0e351458 100644
--- a/app/Http/Controllers/SettingController.php
+++ b/app/Http/Controllers/SettingController.php
@@ -33,7 +33,9 @@ class SettingController extends Controller
// Cycles through posted settings and update them
foreach ($request->all() as $name => $value) {
- if (strpos($name, 'setting-') !== 0) continue;
+ if (strpos($name, 'setting-') !== 0) {
+ continue;
+ }
$key = str_replace('setting-', '', trim($name));
Setting::put($key, $value);
}
@@ -41,5 +43,4 @@ class SettingController extends Controller
session()->flash('success', trans('settings.settings_save_success'));
return redirect('/settings');
}
-
}
diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php
index 5cf7a0f8f..815d9e8d5 100644
--- a/app/Http/Controllers/TagController.php
+++ b/app/Http/Controllers/TagController.php
@@ -54,5 +54,4 @@ class TagController extends Controller
$suggestions = $this->tagRepo->getValueSuggestions($searchTerm, $tagName);
return response()->json($suggestions);
}
-
}
diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php
index fe5c7a243..d50baa86f 100644
--- a/app/Http/Controllers/UserController.php
+++ b/app/Http/Controllers/UserController.php
@@ -93,17 +93,7 @@ class UserController extends Controller
$user->roles()->sync($roles);
}
- // Get avatar from gravatar and save
- if (!config('services.disable_services')) {
- try {
- $avatar = \Images::saveUserGravatar($user);
- $user->avatar()->associate($avatar);
- $user->save();
- } catch (Exception $e) {
- \Log::error('Failed to save user gravatar image');
- }
-
- }
+ $this->userRepo->downloadGravatarToUserAvatar($user);
return redirect('/settings/users');
}
@@ -249,4 +239,27 @@ class UserController extends Controller
'assetCounts' => $assetCounts
]);
}
+
+ /**
+ * Update the user's preferred book-list display setting.
+ * @param $id
+ * @param Request $request
+ * @return \Illuminate\Http\RedirectResponse
+ */
+ public function switchBookView($id, Request $request)
+ {
+ $this->checkPermissionOr('users-manage', function () use ($id) {
+ return $this->currentUser->id == $id;
+ });
+
+ $viewType = $request->get('book_view_type');
+ if (!in_array($viewType, ['grid', 'list'])) {
+ $viewType = 'list';
+ }
+
+ $user = $this->user->findOrFail($id);
+ setting()->putUser($user, 'books_view_type', $viewType);
+
+ return redirect()->back(302, [], "/settings/users/$id");
+ }
}
diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php
index cd894de95..9d2871bbe 100644
--- a/app/Http/Kernel.php
+++ b/app/Http/Kernel.php
@@ -33,6 +33,14 @@ class Kernel extends HttpKernel
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\BookStack\Http\Middleware\Localization::class
],
+ 'web_errors' => [
+ \BookStack\Http\Middleware\EncryptCookies::class,
+ \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
+ \Illuminate\Session\Middleware\StartSession::class,
+ \Illuminate\View\Middleware\ShareErrorsFromSession::class,
+ \BookStack\Http\Middleware\VerifyCsrfToken::class,
+ \BookStack\Http\Middleware\Localization::class
+ ],
'api' => [
'throttle:60,1',
'bindings',
diff --git a/app/Http/Middleware/Localization.php b/app/Http/Middleware/Localization.php
index 14c87c377..466c1442b 100644
--- a/app/Http/Middleware/Localization.php
+++ b/app/Http/Middleware/Localization.php
@@ -19,7 +19,9 @@ class Localization
$locale = $defaultLang;
$availableLocales = config('app.locales');
foreach ($request->getLanguages() as $lang) {
- if (!in_array($lang, $availableLocales)) continue;
+ if (!in_array($lang, $availableLocales)) {
+ continue;
+ }
$locale = $lang;
break;
}
diff --git a/app/Model.php b/app/Model.php
index 9ec2b7362..498bacb20 100644
--- a/app/Model.php
+++ b/app/Model.php
@@ -15,5 +15,4 @@ class Model extends EloquentModel
{
return parent::getAttributeFromArray($key);
}
-
-}
\ No newline at end of file
+}
diff --git a/app/Notifications/ConfirmEmail.php b/app/Notifications/ConfirmEmail.php
index 27ac89c32..858b12166 100644
--- a/app/Notifications/ConfirmEmail.php
+++ b/app/Notifications/ConfirmEmail.php
@@ -49,5 +49,4 @@ class ConfirmEmail extends Notification implements ShouldQueue
->line(trans('auth.email_confirm_text'))
->action(trans('auth.email_confirm_action'), baseUrl('/register/confirm/' . $this->token));
}
-
}
diff --git a/app/Ownable.php b/app/Ownable.php
index f2cfe801b..fe58e05ed 100644
--- a/app/Ownable.php
+++ b/app/Ownable.php
@@ -1,6 +1,5 @@
textField} as text, {$htmlQuery}, book_id, priority, chapter_id, draft, created_by, updated_by, updated_at, created_at";
}
-
}
diff --git a/app/PageRevision.php b/app/PageRevision.php
index 0a9764729..ffcc4f9d2 100644
--- a/app/PageRevision.php
+++ b/app/PageRevision.php
@@ -1,6 +1,5 @@
page->getUrl() . '/revisions/' . $this->id;
- if ($path) return $url . '/' . trim($path, '/');
+ if ($path) {
+ return $url . '/' . trim($path, '/');
+ }
return $url;
}
@@ -58,5 +59,4 @@ class PageRevision extends Model
{
return $type === 'revision';
}
-
}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index ef3ee6c48..b06b2f3a2 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -15,12 +15,12 @@ class AppServiceProvider extends ServiceProvider
public function boot()
{
// 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'];
return in_array($value->getMimeType(), $imageMimes);
});
- \Blade::directive('icon', function($expression) {
+ \Blade::directive('icon', function ($expression) {
return "";
});
@@ -35,7 +35,7 @@ class AppServiceProvider extends ServiceProvider
*/
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'));
});
}
diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php
index 509b86182..d1fac56e6 100644
--- a/app/Providers/AuthServiceProvider.php
+++ b/app/Providers/AuthServiceProvider.php
@@ -25,7 +25,7 @@ class AuthServiceProvider extends ServiceProvider
*/
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]);
});
}
diff --git a/app/Providers/CustomFacadeProvider.php b/app/Providers/CustomFacadeProvider.php
index b2c7acf5e..a97512e8c 100644
--- a/app/Providers/CustomFacadeProvider.php
+++ b/app/Providers/CustomFacadeProvider.php
@@ -34,28 +34,28 @@ class CustomFacadeProvider extends ServiceProvider
*/
public function register()
{
- $this->app->bind('activity', function() {
+ $this->app->bind('activity', function () {
return new ActivityService(
$this->app->make(Activity::class),
$this->app->make(PermissionService::class)
);
});
- $this->app->bind('views', function() {
+ $this->app->bind('views', function () {
return new ViewService(
$this->app->make(View::class),
$this->app->make(PermissionService::class)
);
});
- $this->app->bind('setting', function() {
+ $this->app->bind('setting', function () {
return new SettingService(
$this->app->make(Setting::class),
$this->app->make(Repository::class)
);
});
- $this->app->bind('images', function() {
+ $this->app->bind('images', function () {
return new ImageService(
$this->app->make(ImageManager::class),
$this->app->make(Factory::class),
diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php
index 05f9c57c1..cc3e4d993 100644
--- a/app/Providers/EventServiceProvider.php
+++ b/app/Providers/EventServiceProvider.php
@@ -18,6 +18,8 @@ class EventServiceProvider extends ServiceProvider
'SocialiteProviders\Slack\SlackExtendSocialite@handle',
'SocialiteProviders\Azure\AzureExtendSocialite@handle',
'SocialiteProviders\Okta\OktaExtendSocialite@handle',
+ 'SocialiteProviders\GitLab\GitLabExtendSocialite@handle',
+ 'SocialiteProviders\Twitch\TwitchExtendSocialite@handle',
],
];
diff --git a/app/Providers/LdapUserProvider.php b/app/Providers/LdapUserProvider.php
index a15257aec..1dc789c3b 100644
--- a/app/Providers/LdapUserProvider.php
+++ b/app/Providers/LdapUserProvider.php
@@ -2,7 +2,6 @@
namespace BookStack\Providers;
-
use BookStack\Role;
use BookStack\Services\LdapService;
use BookStack\User;
@@ -102,7 +101,9 @@ class LdapUserProvider implements UserProvider
{
// Get user via LDAP
$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
$model = $this->createModel();
@@ -110,7 +111,9 @@ class LdapUserProvider implements UserProvider
->where('external_auth_id', $userDetails['uid'])
->first();
- if ($currentUser !== null) return $currentUser;
+ if ($currentUser !== null) {
+ return $currentUser;
+ }
$model->name = $userDetails['name'];
$model->external_auth_id = $userDetails['uid'];
diff --git a/app/Providers/PaginationServiceProvider.php b/app/Providers/PaginationServiceProvider.php
index ec41267a4..3a695c5e3 100644
--- a/app/Providers/PaginationServiceProvider.php
+++ b/app/Providers/PaginationServiceProvider.php
@@ -1,6 +1,5 @@
id;
$comment = $this->comment->newInstance($data);
@@ -81,7 +82,9 @@ class CommentRepo {
protected function getNextLocalId(Entity $entity)
{
$comments = $entity->comments(false)->orderBy('local_id', 'desc')->first();
- if ($comments === null) return 1;
+ if ($comments === null) {
+ return 1;
+ }
return $comments->local_id + 1;
}
-}
\ No newline at end of file
+}
diff --git a/app/Repos/EntityRepo.php b/app/Repos/EntityRepo.php
index c31ddfefe..64f7a0810 100644
--- a/app/Repos/EntityRepo.php
+++ b/app/Repos/EntityRepo.php
@@ -77,11 +77,15 @@ class EntityRepo
* @param SearchService $searchService
*/
public function __construct(
- Book $book, Chapter $chapter, Page $page, PageRevision $pageRevision,
- ViewService $viewService, PermissionService $permissionService,
- TagRepo $tagRepo, SearchService $searchService
- )
- {
+ Book $book,
+ Chapter $chapter,
+ Page $page,
+ PageRevision $pageRevision,
+ ViewService $viewService,
+ PermissionService $permissionService,
+ TagRepo $tagRepo,
+ SearchService $searchService
+ ) {
$this->book = $book;
$this->chapter = $chapter;
$this->page = $page;
@@ -113,9 +117,9 @@ class EntityRepo
* @param bool $allowDrafts
* @return \Illuminate\Database\Query\Builder
*/
- protected function entityQuery($type, $allowDrafts = false)
+ protected function entityQuery($type, $allowDrafts = false, $permission = 'view')
{
- $q = $this->permissionService->enforceEntityRestrictions($type, $this->getEntity($type), 'view');
+ $q = $this->permissionService->enforceEntityRestrictions($type, $this->getEntity($type), $permission);
if (strtolower($type) === 'page' && !$allowDrafts) {
$q = $q->where('draft', '=', false);
}
@@ -163,14 +167,16 @@ class EntityRepo
$q = $this->entityQuery($type)->where('slug', '=', $slug);
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')
->from($this->book->getTable())
->where('slug', '=', $bookSlug)->limit(1);
});
}
$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;
}
@@ -196,15 +202,18 @@ class EntityRepo
}
/**
- * Get all entities of a type limited by count unless count if false.
+ * Get all entities of a type with the given permission, limited by count unless count is false.
* @param string $type
* @param integer|bool $count
+ * @param string $permission
* @return Collection
*/
- public function getAll($type, $count = 20)
+ public function getAll($type, $count = 20, $permission = 'view')
{
- $q = $this->entityQuery($type)->orderBy('name', 'asc');
- if ($count !== false) $q = $q->take($count);
+ $q = $this->entityQuery($type, false, $permission)->orderBy('name', 'asc');
+ if ($count !== false) {
+ $q = $q->take($count);
+ }
return $q->get();
}
@@ -231,7 +240,9 @@ class EntityRepo
{
$query = $this->permissionService->enforceEntityRestrictions($type, $this->getEntity($type))
->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)) {
$additionalQuery($query);
}
@@ -250,7 +261,9 @@ class EntityRepo
{
$query = $this->permissionService->enforceEntityRestrictions($type, $this->getEntity($type))
->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)) {
$additionalQuery($query);
}
@@ -347,12 +360,16 @@ class EntityRepo
$parents[$key] = $entities[$index];
$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;
}
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;
if (!isset($parents[$parentKey])) {
$tree[] = $entity;
@@ -431,7 +448,9 @@ class EntityRepo
if (strtolower($type) === 'page' || strtolower($type) === 'chapter') {
$query = $query->where('book_id', '=', $bookId);
}
- if ($currentId) $query = $query->where('id', '!=', $currentId);
+ if ($currentId) {
+ $query = $query->where('id', '!=', $currentId);
+ }
return $query->count() > 0;
}
@@ -558,7 +577,9 @@ class EntityRepo
$slug = preg_replace('/[\+\/\\\?\@\}\{\.\,\=\[\]\#\&\!\*\'\;\:\$\%]/', '', mb_strtolower($name));
$slug = preg_replace('/\s{2,}/', ' ', $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;
}
@@ -599,7 +620,9 @@ class EntityRepo
public function savePageRevision(Page $page, $summary = null)
{
$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->slug = $page->slug;
$revision->book_slug = $page->book->slug;
@@ -627,7 +650,9 @@ class EntityRepo
*/
protected function formatHtml($htmlText)
{
- if ($htmlText == '') return $htmlText;
+ if ($htmlText == '') {
+ return $htmlText;
+ }
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8'));
@@ -641,7 +666,9 @@ class EntityRepo
foreach ($childNodes as $index => $childNode) {
/** @var \DOMElement $childNode */
- if (get_class($childNode) !== 'DOMElement') continue;
+ if (get_class($childNode) !== 'DOMElement') {
+ continue;
+ }
// Overwrite id if not a BookStack custom id
if ($childNode->hasAttribute('id')) {
@@ -688,12 +715,17 @@ class EntityRepo
$content = $page->html;
$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'];
foreach ($matches[1] as $index => $includeId) {
$splitInclude = explode('#', $includeId, 2);
$pageId = intval($splitInclude[0]);
- if (is_nan($pageId)) continue;
+ if (is_nan($pageId)) {
+ continue;
+ }
$matchedPage = $this->getById('page', $pageId, false, $ignorePermissions);
if ($matchedPage === null) {
@@ -714,8 +746,13 @@ class EntityRepo
continue;
}
$innerContent = '';
- foreach ($matchingElem->childNodes as $childNode) {
- $innerContent .= $doc->saveHTML($childNode);
+ $isTopLevel = in_array(strtolower($matchingElem->nodeName), $topLevelTags);
+ if ($isTopLevel) {
+ $innerContent .= $doc->saveHTML($matchingElem);
+ } else {
+ foreach ($matchingElem->childNodes as $childNode) {
+ $innerContent .= $doc->saveHTML($childNode);
+ }
}
$content = str_replace($matches[0][$index], trim($innerContent), $content);
}
@@ -748,7 +785,9 @@ class EntityRepo
$page->updated_by = user()->id;
$page->draft = true;
- if ($chapter) $page->chapter_id = $chapter->id;
+ if ($chapter) {
+ $page->chapter_id = $chapter->id;
+ }
$book->pages()->save($page);
$page = $this->page->find($page->id);
@@ -779,14 +818,18 @@ class EntityRepo
*/
public function getPageNav($pageContent)
{
- if ($pageContent == '') return [];
+ if ($pageContent == '') {
+ return [];
+ }
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML(mb_convert_encoding($pageContent, 'HTML-ENTITIES', 'UTF-8'));
$xPath = new DOMXPath($doc);
$headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6");
- if (is_null($headers)) return [];
+ if (is_null($headers)) {
+ return [];
+ }
$tree = collect([]);
foreach ($headers as $header) {
@@ -802,7 +845,7 @@ class EntityRepo
// Normalise headers if only smaller headers have been used
if (count($tree) > 0) {
$minLevel = $tree->pluck('level')->min();
- $tree = $tree->map(function($header) use ($minLevel) {
+ $tree = $tree->map(function ($header) use ($minLevel) {
$header['level'] -= ($minLevel - 2);
return $header;
});
@@ -838,7 +881,9 @@ class EntityRepo
$page->fill($input);
$page->html = $this->formatHtml($input['html']);
$page->text = $this->pageToPlainText($page);
- if (setting('app-editor') !== 'markdown') $page->markdown = '';
+ if (setting('app-editor') !== 'markdown') {
+ $page->markdown = '';
+ }
$page->updated_by = $userId;
$page->revision_count++;
$page->save();
@@ -900,7 +945,9 @@ class EntityRepo
public function getUserPageDraftMessage(PageRevision $draft)
{
$message = trans('entities.pages_editing_draft_notification', ['timeDiff' => $draft->updated_at->diffForHumans()]);
- if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) return $message;
+ if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) {
+ return $message;
+ }
return $message . "\n" . trans('entities.pages_draft_edited_notification');
}
@@ -996,7 +1043,9 @@ class EntityRepo
}
$draft->fill($data);
- if (setting('app-editor') !== 'markdown') $draft->markdown = '';
+ if (setting('app-editor') !== 'markdown') {
+ $draft->markdown = '';
+ }
$draft->save();
return $draft;
@@ -1103,17 +1152,4 @@ class EntityRepo
$page->delete();
}
-
}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/Repos/ImageRepo.php b/app/Repos/ImageRepo.php
index 8ddde7b0f..ec2fda1d3 100644
--- a/app/Repos/ImageRepo.php
+++ b/app/Repos/ImageRepo.php
@@ -1,12 +1,9 @@
image->where('type', '=', strtolower($type))->where('name', 'LIKE', '%' . $searchTerm . '%');
return $this->returnPaginated($images, $page, $pageSize);
@@ -104,13 +101,13 @@ class ImageRepo
/**
* Get gallery images with a particular filter criteria such as
* being within the current book or page.
- * @param int $pagination
- * @param int $pageSize
* @param $filter
* @param $pageId
+ * @param int $pageNum
+ * @param int $pageSize
* @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');
@@ -123,7 +120,7 @@ class ImageRepo
$images = $images->whereIn('uploaded_to', $validPageIds);
}
- return $this->returnPaginated($images, $pagination, $pageSize);
+ return $this->returnPaginated($images, $pageNum, $pageSize);
}
/**
@@ -132,6 +129,8 @@ class ImageRepo
* @param string $type
* @param int $uploadedTo
* @return Image
+ * @throws \BookStack\Exceptions\ImageUploadException
+ * @throws \Exception
*/
public function saveNew(UploadedFile $uploadFile, $type, $uploadedTo = 0)
{
@@ -140,11 +139,39 @@ class ImageRepo
return $image;
}
+ /**
+ * Save a drawing the the database;
+ * @param string $base64Uri
+ * @param int $uploadedTo
+ * @return Image
+ * @throws \BookStack\Exceptions\ImageUploadException
+ */
+ public function saveDrawing(string $base64Uri, int $uploadedTo)
+ {
+ $name = 'Drawing-' . user()->getShortName(40) . '-' . strval(time()) . '.png';
+ $image = $this->imageService->saveNewFromBase64Uri($base64Uri, $name, 'drawio', $uploadedTo);
+ return $image;
+ }
+
+ /**
+ * Replace the image content of a drawing.
+ * @param Image $image
+ * @param string $base64Uri
+ * @return Image
+ * @throws \BookStack\Exceptions\ImageUploadException
+ */
+ public function replaceDrawingContent(Image $image, string $base64Uri)
+ {
+ return $this->imageService->replaceImageDataFromBase64Uri($image, $base64Uri);
+ }
+
/**
* Update the details of an image via an array of properties.
* @param Image $image
* @param array $updateDetails
* @return Image
+ * @throws \BookStack\Exceptions\ImageUploadException
+ * @throws \Exception
*/
public function updateImageDetails(Image $image, $updateDetails)
{
@@ -170,6 +197,8 @@ class ImageRepo
/**
* Load thumbnails onto an image object.
* @param Image $image
+ * @throws \BookStack\Exceptions\ImageUploadException
+ * @throws \Exception
*/
private function loadThumbs(Image $image)
{
@@ -183,22 +212,46 @@ class ImageRepo
* Get the thumbnail for an image.
* If $keepRatio is true only the width will be used.
* Checks the cache then storage to avoid creating / accessing the filesystem on every check.
- *
* @param Image $image
* @param int $width
* @param int $height
* @param bool $keepRatio
* @return string
+ * @throws \BookStack\Exceptions\ImageUploadException
+ * @throws \Exception
*/
public function getThumbnail(Image $image, $width = 220, $height = 220, $keepRatio = false)
{
try {
return $this->imageService->getThumbnail($image, $width, $height, $keepRatio);
- } catch (FileNotFoundException $exception) {
- $image->delete();
- return [];
+ } catch (\Exception $exception) {
+ dd($exception);
+ return null;
}
}
+ /**
+ * Get the raw image data from an Image.
+ * @param Image $image
+ * @return null|string
+ */
+ public function getImageData(Image $image)
+ {
+ try {
+ return $this->imageService->getImageData($image);
+ } catch (\Exception $exception) {
+ return null;
+ }
+ }
-}
\ No newline at end of file
+ /**
+ * Check if the provided image type is valid.
+ * @param $type
+ * @return bool
+ */
+ public function isValidType($type)
+ {
+ $validTypes = ['drawing', 'gallery', 'cover', 'system', 'user'];
+ return in_array($type, $validTypes);
+ }
+}
diff --git a/app/Repos/PermissionsRepo.php b/app/Repos/PermissionsRepo.php
index aa58d1718..6f7ea1dc8 100644
--- a/app/Repos/PermissionsRepo.php
+++ b/app/Repos/PermissionsRepo.php
@@ -1,6 +1,5 @@
permissionService->deleteJointPermissionsForRole($role);
$role->delete();
}
-
-}
\ No newline at end of file
+}
diff --git a/app/Repos/TagRepo.php b/app/Repos/TagRepo.php
index 5edd6df3c..ab1805ab3 100644
--- a/app/Repos/TagRepo.php
+++ b/app/Repos/TagRepo.php
@@ -52,7 +52,9 @@ class TagRepo
public function getForEntity($entityType, $entityId)
{
$entity = $this->getEntity($entityType, $entityId);
- if ($entity === null) return collect();
+ if ($entity === null) {
+ return collect();
+ }
return $entity->tags;
}
@@ -95,7 +97,9 @@ class TagRepo
$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');
return $query->get(['value'])->pluck('value');
@@ -112,7 +116,9 @@ class TagRepo
$entity->tags()->delete();
$newTags = [];
foreach ($tags as $tag) {
- if (trim($tag['name']) === '') continue;
+ if (trim($tag['name']) === '') {
+ continue;
+ }
$newTags[] = $this->newInstanceFromInput($tag);
}
@@ -132,5 +138,4 @@ class TagRepo
$values = ['name' => $name, 'value' => $value];
return $this->tag->newInstance($values);
}
-
-}
\ No newline at end of file
+}
diff --git a/app/Repos/UserRepo.php b/app/Repos/UserRepo.php
index c3546a442..3cfd61d27 100644
--- a/app/Repos/UserRepo.php
+++ b/app/Repos/UserRepo.php
@@ -1,8 +1,12 @@
user->with('roles', 'avatar')->orderBy($sortData['sort'], $sortData['order']);
if ($sortData['search']) {
$term = '%' . $sortData['search'] . '%';
- $query->where(function($query) use ($term) {
+ $query->where(function ($query) use ($term) {
$query->where('name', 'like', $term)
->orWhere('email', 'like', $term);
});
@@ -83,16 +87,7 @@ class UserRepo
$this->attachDefaultRole($user);
// Get avatar from gravatar and save
- if (!config('services.disable_services')) {
- try {
- $avatar = \Images::saveUserGravatar($user);
- $user->avatar()->associate($avatar);
- $user->save();
- } catch (Exception $e) {
- $user->save();
- \Log::error('Failed to save user gravatar image');
- }
- }
+ $this->downloadGravatarToUserAvatar($user);
return $user;
}
@@ -104,10 +99,27 @@ class UserRepo
public function attachDefaultRole($user)
{
$roleId = setting('registration-role');
- if ($roleId === false) $roleId = $this->role->first()->id;
+ if ($roleId === false) {
+ $roleId = $this->role->first()->id;
+ }
$user->attachRoleId($roleId);
}
+ /**
+ * Assign a user to a system-level role.
+ * @param User $user
+ * @param $systemRoleName
+ * @throws NotFoundException
+ */
+ public function attachSystemRole(User $user, $systemRoleName)
+ {
+ $role = $this->role->newQuery()->where('system_name', '=', $systemRoleName)->first();
+ if ($role === null) {
+ throw new NotFoundException("Role '{$systemRoleName}' not found");
+ }
+ $user->attachRole($role);
+ }
+
/**
* Checks if the give user is the only admin.
* @param User $user
@@ -115,10 +127,14 @@ class UserRepo
*/
public function isOnlyAdmin(User $user)
{
- if (!$user->roles->pluck('name')->contains('admin')) return false;
+ if (!$user->hasSystemRole('admin')) {
+ return false;
+ }
- $adminRole = $this->role->getRole('admin');
- if ($adminRole->users->count() > 1) return false;
+ $adminRole = $this->role->getSystemRole('admin');
+ if ($adminRole->users->count() > 1) {
+ return false;
+ }
return true;
}
@@ -140,11 +156,18 @@ class UserRepo
/**
* Remove the given user from storage, Delete all related content.
* @param User $user
+ * @throws Exception
*/
public function destroy(User $user)
{
$user->socialAccounts()->delete();
$user->delete();
+
+ // Delete user profile images
+ $profileImages = $images = Image::where('type', '=', 'user')->where('created_by', '=', $user->id)->get();
+ foreach ($profileImages as $image) {
+ Images::destroyImage($image);
+ }
}
/**
@@ -156,7 +179,7 @@ class UserRepo
*/
public function getActivity(User $user, $count = 20, $page = 0)
{
- return \Activity::userActivity($user, $count, $page);
+ return Activity::userActivity($user, $count, $page);
}
/**
@@ -213,4 +236,27 @@ class UserRepo
return $this->role->where('system_name', '!=', 'admin')->get();
}
-}
\ No newline at end of file
+ /**
+ * Get a gravatar image for a user and set it as their avatar.
+ * Does not run if gravatar disabled in config.
+ * @param User $user
+ * @return bool
+ */
+ public function downloadGravatarToUserAvatar(User $user)
+ {
+ // Get avatar from gravatar and save
+ if (!config('services.gravatar')) {
+ return false;
+ }
+
+ try {
+ $avatar = Images::saveUserGravatar($user);
+ $user->avatar()->associate($avatar);
+ $user->save();
+ return true;
+ } catch (Exception $e) {
+ \Log::error('Failed to save user gravatar image');
+ return false;
+ }
+ }
+}
diff --git a/app/Role.php b/app/Role.php
index bf9685ee2..e86854e79 100644
--- a/app/Role.php
+++ b/app/Role.php
@@ -1,6 +1,5 @@
getRelationValue('permissions');
foreach ($permissions as $permission) {
- if ($permission->getRawAttribute('name') === $permissionName) return true;
+ if ($permission->getRawAttribute('name') === $permissionName) {
+ return true;
+ }
}
return false;
}
@@ -91,5 +92,4 @@ class Role extends Model
{
return static::where('hidden', '=', false)->orderBy('name')->get();
}
-
}
diff --git a/app/RolePermission.php b/app/RolePermission.php
index ded6f6394..366c16749 100644
--- a/app/RolePermission.php
+++ b/app/RolePermission.php
@@ -1,6 +1,5 @@
belongsToMany(Role::class, 'permission_role','permission_id', 'role_id');
+ return $this->belongsToMany(Role::class, 'permission_role', 'permission_id', 'role_id');
}
/**
diff --git a/app/SearchTerm.php b/app/SearchTerm.php
index 50df34021..ee6c72190 100644
--- a/app/SearchTerm.php
+++ b/app/SearchTerm.php
@@ -14,5 +14,4 @@ class SearchTerm extends Model
{
return $this->morphTo('entity');
}
-
}
diff --git a/app/Services/ActivityService.php b/app/Services/ActivityService.php
index 2368ba10a..3fc7e7ee0 100644
--- a/app/Services/ActivityService.php
+++ b/app/Services/ActivityService.php
@@ -170,5 +170,4 @@ class ActivityService
Session::flash('success', $message);
}
}
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/AttachmentService.php b/app/Services/AttachmentService.php
index 592d67e63..381e44749 100644
--- a/app/Services/AttachmentService.php
+++ b/app/Services/AttachmentService.php
@@ -8,15 +8,37 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
class AttachmentService extends UploadService
{
+ /**
+ * Get the storage that will be used for storing files.
+ * @return \Illuminate\Contracts\Filesystem\Filesystem
+ */
+ protected function getStorage()
+ {
+ if ($this->storageInstance !== null) {
+ return $this->storageInstance;
+ }
+
+ $storageType = config('filesystems.default');
+
+ // Override default location if set to local public to ensure not visible.
+ if ($storageType === 'local') {
+ $storageType = 'local_secure';
+ }
+
+ $this->storageInstance = $this->fileSystem->disk($storageType);
+
+ return $this->storageInstance;
+ }
+
/**
* Get an attachment from storage.
* @param Attachment $attachment
* @return string
+ * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function getAttachmentFromStorage(Attachment $attachment)
{
- $attachmentPath = $this->getStorageBasePath() . $attachment->path;
- return $this->getStorage()->get($attachmentPath);
+ return $this->getStorage()->get($attachment->path);
}
/**
@@ -92,16 +114,6 @@ class AttachmentService extends UploadService
]);
}
- /**
- * Get the file storage base path, amended for storage type.
- * This allows us to keep a generic path in the database.
- * @return string
- */
- private function getStorageBasePath()
- {
- return $this->isLocal() ? 'storage/' : '';
- }
-
/**
* Updates the file ordering for a listing of attached files.
* @param array $attachmentList
@@ -138,6 +150,7 @@ class AttachmentService extends UploadService
/**
* Delete a File from the database and storage.
* @param Attachment $attachment
+ * @throws Exception
*/
public function deleteFile(Attachment $attachment)
{
@@ -157,11 +170,10 @@ class AttachmentService extends UploadService
*/
protected function deleteFileInStorage(Attachment $attachment)
{
- $storedFilePath = $this->getStorageBasePath() . $attachment->path;
$storage = $this->getStorage();
- $dirPath = dirname($storedFilePath);
+ $dirPath = dirname($attachment->path);
- $storage->delete($storedFilePath);
+ $storage->delete($attachment->path);
if (count($storage->allFiles($dirPath)) === 0) {
$storage->deleteDirectory($dirPath);
}
@@ -179,23 +191,20 @@ class AttachmentService extends UploadService
$attachmentData = file_get_contents($uploadedFile->getRealPath());
$storage = $this->getStorage();
- $attachmentBasePath = 'uploads/files/' . Date('Y-m-M') . '/';
- $storageBasePath = $this->getStorageBasePath() . $attachmentBasePath;
+ $basePath = 'uploads/files/' . Date('Y-m-M') . '/';
$uploadFileName = $attachmentName;
- while ($storage->exists($storageBasePath . $uploadFileName)) {
+ while ($storage->exists($basePath . $uploadFileName)) {
$uploadFileName = str_random(3) . $uploadFileName;
}
- $attachmentPath = $attachmentBasePath . $uploadFileName;
- $attachmentStoragePath = $this->getStorageBasePath() . $attachmentPath;
-
+ $attachmentPath = $basePath . $uploadFileName;
try {
- $storage->put($attachmentStoragePath, $attachmentData);
+ $storage->put($attachmentPath, $attachmentData);
} catch (Exception $e) {
- throw new FileUploadException(trans('errors.path_not_writable', ['filePath' => $attachmentStoragePath]));
+ throw new FileUploadException(trans('errors.path_not_writable', ['filePath' => $attachmentPath]));
}
+
return $attachmentPath;
}
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/EmailConfirmationService.php b/app/Services/EmailConfirmationService.php
index 8eb52708c..9ee69ef1a 100644
--- a/app/Services/EmailConfirmationService.php
+++ b/app/Services/EmailConfirmationService.php
@@ -108,6 +108,4 @@ class EmailConfirmationService
}
return $token;
}
-
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/ExportService.php b/app/Services/ExportService.php
index 1e4e99428..ada2261e4 100644
--- a/app/Services/ExportService.php
+++ b/app/Services/ExportService.php
@@ -42,7 +42,7 @@ class ExportService
public function chapterToContainedHtml(Chapter $chapter)
{
$pages = $this->entityRepo->getChapterChildren($chapter);
- $pages->each(function($page) {
+ $pages->each(function ($page) {
$page->html = $this->entityRepo->renderPage($page);
});
$html = view('chapters/export', [
@@ -89,7 +89,7 @@ class ExportService
public function chapterToPdf(Chapter $chapter)
{
$pages = $this->entityRepo->getChapterChildren($chapter);
- $pages->each(function($page) {
+ $pages->each(function ($page) {
$page->html = $this->entityRepo->renderPage($page);
});
$html = view('chapters/export', [
@@ -163,7 +163,9 @@ class ExportService
$pathString = public_path(trim($relString, '/'));
}
- if ($isLocal && !file_exists($pathString)) continue;
+ if ($isLocal && !file_exists($pathString)) {
+ continue;
+ }
try {
if ($isLocal) {
$imageContent = file_get_contents($pathString);
@@ -173,7 +175,9 @@ class ExportService
$imageContent = curl_exec($ch);
$err = curl_error($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);
$newImageString = str_replace($srcString, $imageEncoded, $oldImgString);
@@ -257,17 +261,4 @@ class ExportService
}
return $text;
}
-
}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/Services/Facades/Activity.php b/app/Services/Facades/Activity.php
index ea04cfc47..d24e39dba 100644
--- a/app/Services/Facades/Activity.php
+++ b/app/Services/Facades/Activity.php
@@ -1,6 +1,5 @@
saveNew($imageName, $imageData, $type, $uploadedTo);
}
+ /**
+ * Save a new image from a uri-encoded base64 string of data.
+ * @param string $base64Uri
+ * @param string $name
+ * @param string $type
+ * @param int $uploadedTo
+ * @return Image
+ * @throws ImageUploadException
+ */
+ public function saveNewFromBase64Uri(string $base64Uri, string $name, string $type, $uploadedTo = 0)
+ {
+ $splitData = explode(';base64,', $base64Uri);
+ if (count($splitData) < 2) {
+ throw new ImageUploadException("Invalid base64 image data provided");
+ }
+ $data = base64_decode($splitData[1]);
+ return $this->saveNew($name, $data, $type, $uploadedTo);
+ }
+
+ /**
+ * Replace the data for an image via a Base64 encoded string.
+ * @param Image $image
+ * @param string $base64Uri
+ * @return Image
+ * @throws ImageUploadException
+ */
+ public function replaceImageDataFromBase64Uri(Image $image, string $base64Uri)
+ {
+ $splitData = explode(';base64,', $base64Uri);
+ if (count($splitData) < 2) {
+ throw new ImageUploadException("Invalid base64 image data provided");
+ }
+ $data = base64_decode($splitData[1]);
+ $storage = $this->getStorage();
+
+ try {
+ $storage->put($image->path, $data);
+ } catch (Exception $e) {
+ throw new ImageUploadException(trans('errors.path_not_writable', ['filePath' => $image->path]));
+ }
+
+ return $image;
+ }
/**
* Gets an image from url and saves it to the database.
@@ -59,7 +102,9 @@ class ImageService extends UploadService
{
$imageName = $imageName ? $imageName : basename($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);
}
@@ -78,12 +123,12 @@ class ImageService extends UploadService
$secureUploads = setting('app-secure-images');
$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') . '/';
- if ($this->isLocal()) $imagePath = '/public' . $imagePath;
-
while ($storage->exists($imagePath . $imageName)) {
$imageName = str_random(3) . $imageName;
}
@@ -96,8 +141,6 @@ class ImageService extends UploadService
throw new ImageUploadException(trans('errors.path_not_writable', ['filePath' => $fullPath]));
}
- if ($this->isLocal()) $fullPath = str_replace_first('/public', '', $fullPath);
-
$imageDetails = [
'name' => $imageName,
'path' => $fullPath,
@@ -112,8 +155,8 @@ class ImageService extends UploadService
$imageDetails['updated_by'] = $userId;
}
- $image = Image::forceCreate($imageDetails);
-
+ $image = (new Image());
+ $image->forceFill($imageDetails)->save();
return $image;
}
@@ -124,14 +167,13 @@ class ImageService extends UploadService
*/
protected function getPath(Image $image)
{
- return ($this->isLocal()) ? ('public/' . $image->path) : $image->path;
+ return $image->path;
}
/**
* Get the thumbnail for an image.
* If $keepRatio is true only the width will be used.
* Checks the cache then storage to avoid creating / accessing the filesystem on every check.
- *
* @param Image $image
* @param int $width
* @param int $height
@@ -151,7 +193,6 @@ class ImageService extends UploadService
}
$storage = $this->getStorage();
-
if ($storage->exists($thumbFilePath)) {
return $this->getPublicUrl($thumbFilePath);
}
@@ -161,9 +202,8 @@ class ImageService extends UploadService
} catch (Exception $e) {
if ($e instanceof \ErrorException || $e instanceof NotSupportedException) {
throw new ImageUploadException(trans('errors.cannot_create_thumbs'));
- } else {
- throw $e;
}
+ throw $e;
}
if ($keepRatio) {
@@ -183,10 +223,24 @@ class ImageService extends UploadService
return $this->getPublicUrl($thumbFilePath);
}
+ /**
+ * Get the raw data content from an image.
+ * @param Image $image
+ * @return string
+ * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
+ */
+ public function getImageData(Image $image)
+ {
+ $imagePath = $this->getPath($image);
+ $storage = $this->getStorage();
+ return $storage->get($imagePath);
+ }
+
/**
* Destroys an Image object along with its files and thumbnails.
* @param Image $image
* @return bool
+ * @throws Exception
*/
public function destroyImage(Image $image)
{
@@ -205,9 +259,13 @@ class ImageService extends UploadService
// Cleanup of empty folders
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();
return true;
@@ -252,14 +310,10 @@ class ImageService extends UploadService
$storageUrl = 'https://s3-' . $storageDetails['region'] . '.amazonaws.com/' . $storageDetails['bucket'];
}
}
-
$this->storageUrl = $storageUrl;
}
- if ($this->isLocal()) $filePath = str_replace_first('public/', '', $filePath);
-
- return ($this->storageUrl == false ? rtrim(baseUrl(''), '/') : rtrim($this->storageUrl, '/')) . $filePath;
+ $basePath = ($this->storageUrl == false) ? baseUrl('/') : $this->storageUrl;
+ return rtrim($basePath, '/') . $filePath;
}
-
-
}
diff --git a/app/Services/Ldap.php b/app/Services/Ldap.php
index 9c3bec327..29270daf5 100644
--- a/app/Services/Ldap.php
+++ b/app/Services/Ldap.php
@@ -1,6 +1,5 @@
config['follow_referrals'] ? 1 : 0;
$this->ldap->setOption($ldapConnection, LDAP_OPT_REFERRALS, $followReferrals);
$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];
return [
@@ -66,8 +67,12 @@ class LdapService
public function validateUserCredentials(Authenticatable $user, $username, $password)
{
$ldapUser = $this->getUserDetails($username);
- if ($ldapUser === null) return false;
- if ($ldapUser['uid'] !== $user->external_auth_id) return false;
+ if ($ldapUser === null) {
+ return false;
+ }
+ if ($ldapUser['uid'] !== $user->external_auth_id) {
+ return false;
+ }
$ldapConnection = $this->getConnection();
try {
@@ -97,7 +102,9 @@ class LdapService
$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()
{
- if ($this->ldapConnection !== null) return $this->ldapConnection;
+ if ($this->ldapConnection !== null) {
+ return $this->ldapConnection;
+ }
// Check LDAP extension in installed
if (!function_exists('ldap_connect') && config('app.env') !== 'testing') {
@@ -118,7 +127,9 @@ class LdapService
// Get port from server string and protocol if specified.
$ldapServer = explode(':', $this->config['server']);
$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];
$defaultPort = $ldapServer[0] === 'ldaps' ? 636 : 389;
$ldapConnection = $this->ldap->connect($hostName, count($ldapServer) > 2 ? intval($ldapServer[2]) : $defaultPort);
@@ -151,5 +162,4 @@ class LdapService
}
return strtr($filterString, $newAttrs);
}
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/PermissionService.php b/app/Services/PermissionService.php
index 4f8b4e0f9..331ed06c8 100644
--- a/app/Services/PermissionService.php
+++ b/app/Services/PermissionService.php
@@ -88,7 +88,9 @@ class PermissionService
}
$book = $this->book->find($bookId);
- if ($book === null) $book = false;
+ if ($book === null) {
+ $book = false;
+ }
if (isset($this->entityCache['books'])) {
$this->entityCache['books']->put($bookId, $book);
}
@@ -108,7 +110,9 @@ class PermissionService
}
$chapter = $this->chapter->find($chapterId);
- if ($chapter === null) $chapter = false;
+ if ($chapter === null) {
+ $chapter = false;
+ }
if (isset($this->entityCache['chapters'])) {
$this->entityCache['chapters']->put($chapterId, $chapter);
}
@@ -122,7 +126,9 @@ class PermissionService
*/
protected function getRoles()
{
- if ($this->userRoles !== false) return $this->userRoles;
+ if ($this->userRoles !== false) {
+ return $this->userRoles;
+ }
$roles = [];
@@ -161,9 +167,9 @@ class PermissionService
*/
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']);
- }, 'pages' => function($query) {
+ }, 'pages' => function ($query) {
$query->select(['id', 'restricted', 'created_by', 'book_id', 'chapter_id']);
}]);
}
@@ -174,7 +180,8 @@ class PermissionService
* @param array $roles
* @param bool $deleteOld
*/
- protected function buildJointPermissionsForBooks($books, $roles, $deleteOld = false) {
+ protected function buildJointPermissionsForBooks($books, $roles, $deleteOld = false)
+ {
$entities = clone $books;
/** @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);
}
@@ -261,7 +270,7 @@ class PermissionService
*/
protected function deleteManyJointPermissionsForRoles($roles)
{
- $roleIds = array_map(function($role) {
+ $roleIds = array_map(function ($role) {
return $role->id;
}, $roles);
$this->jointPermission->newQuery()->whereIn('role_id', $roleIds)->delete();
@@ -282,21 +291,22 @@ class PermissionService
*/
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) {
$query = $this->db->table('joint_permissions');
foreach ($entityChunk as $entity) {
- $query->orWhere(function(QueryBuilder $query) use ($entity) {
+ $query->orWhere(function (QueryBuilder $query) use ($entity) {
$query->where('entity_id', '=', $entity->id)
->where('entity_type', '=', $entity->getMorphClass());
});
}
$query->delete();
}
-
});
}
@@ -315,7 +325,7 @@ class PermissionService
$permissionFetch = $this->entityPermission->newQuery();
foreach ($entities as $entity) {
$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());
});
}
@@ -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) {
$this->db->table('joint_permissions')->insert($jointPermissionChunk);
}
@@ -362,8 +372,12 @@ class PermissionService
protected function getActions(Entity $entity)
{
$baseActions = ['view', 'update', 'delete'];
- if ($entity->isA('chapter') || $entity->isA('book')) $baseActions[] = 'page-create';
- if ($entity->isA('book')) $baseActions[] = 'chapter-create';
+ if ($entity->isA('chapter') || $entity->isA('book')) {
+ $baseActions[] = 'page-create';
+ }
+ if ($entity->isA('book')) {
+ $baseActions[] = 'chapter-create';
+ }
return $baseActions;
}
@@ -412,7 +426,10 @@ class PermissionService
}
}
- return $this->createJointPermissionDataArray($entity, $role, $action,
+ return $this->createJointPermissionDataArray(
+ $entity,
+ $role,
+ $action,
($hasExplicitAccessToParents || ($roleHasPermission && $hasPermissiveAccessToParents)),
($hasExplicitAccessToParents || ($roleHasPermissionOwn && $hasPermissiveAccessToParents))
);
@@ -426,7 +443,8 @@ class PermissionService
* @param $action
* @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;
return isset($entityMap[$key]) ? $entityMap[$key] : false;
}
@@ -545,11 +563,12 @@ class PermissionService
* @param bool $fetchPageContent
* @return QueryBuilder
*/
- 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) {
+ 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) {
$query->where('draft', '=', 0);
if (!$filterDrafts) {
- $query->orWhere(function($query) {
+ $query->orWhere(function ($query) {
$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(*)')
->whereRaw('jp.entity_id=U.id')->whereRaw('jp.entity_type=U.entity_type')
->where('jp.action', '=', 'view')->whereIn('jp.role_id', $this->getRoles())
- ->where(function($query) {
- $query->where('jp.has_permission', '=', 1)->orWhere(function($query) {
+ ->where(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);
});
});
@@ -715,5 +734,4 @@ class PermissionService
$this->userRoles = false;
$this->isAdminUser = null;
}
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/SearchService.php b/app/Services/SearchService.php
index a8784ded1..6786c5cf4 100644
--- a/app/Services/SearchService.php
+++ b/app/Services/SearchService.php
@@ -83,7 +83,9 @@ class SearchService
$total = 0;
foreach ($entityTypesToSearch as $entityType) {
- if (!in_array($entityType, $entityTypes)) continue;
+ if (!in_array($entityType, $entityTypes)) {
+ continue;
+ }
$search = $this->searchEntityTable($terms, $entityType, $page, $count);
$total += $this->searchEntityTable($terms, $entityType, $page, $count, true);
$results = $results->merge($search);
@@ -111,7 +113,9 @@ class SearchService
$results = collect();
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();
$results = $results->merge($search);
}
@@ -143,7 +147,9 @@ class SearchService
public function searchEntityTable($terms, $entityType = 'page', $page = 1, $count = 20, $getCount = false)
{
$query = $this->buildEntitySearchQuery($terms, $entityType);
- if ($getCount) return $query->count();
+ if ($getCount) {
+ return $query->count();
+ }
$query = $query->skip(($page-1) * $count)->take($count);
return $query->get();
@@ -164,12 +170,12 @@ class SearchService
if (count($terms['search']) > 0) {
$subQuery = $this->db->table('search_terms')->select('entity_id', 'entity_type', \DB::raw('SUM(score) as score'));
$subQuery->where('entity_type', '=', 'BookStack\\' . ucfirst($entityType));
- $subQuery->where(function(Builder $query) use ($terms) {
+ $subQuery->where(function (Builder $query) use ($terms) {
foreach ($terms['search'] as $inputTerm) {
$query->orWhere('term', 'like', $inputTerm .'%');
}
})->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');
})->selectRaw($entity->getTable().'.*, s.score')->orderBy('score', 'desc');
$entitySelect->mergeBindings($subQuery);
@@ -177,7 +183,7 @@ class SearchService
// Handle exact term matching
if (count($terms['exact']) > 0) {
- $entitySelect->where(function(\Illuminate\Database\Eloquent\Builder $query) use ($terms, $entity) {
+ $entitySelect->where(function (\Illuminate\Database\Eloquent\Builder $query) use ($terms, $entity) {
foreach ($terms['exact'] as $inputTerm) {
$query->where(function (\Illuminate\Database\Eloquent\Builder $query) use ($inputTerm, $entity) {
$query->where('name', 'like', '%'.$inputTerm .'%')
@@ -195,7 +201,9 @@ class SearchService
// Handle filters
foreach ($terms['filters'] as $filterTerm => $filterValue) {
$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');
@@ -234,7 +242,9 @@ class SearchService
// Parse standard terms
foreach (explode(' ', trim($searchString)) as $searchTerm) {
- if ($searchTerm !== '') $terms['search'][] = $searchTerm;
+ if ($searchTerm !== '') {
+ $terms['search'][] = $searchTerm;
+ }
}
// Split filter values out
@@ -267,15 +277,18 @@ class SearchService
* @param string $tagTerm
* @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);
- $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];
$tagOperator = count($tagSplit) > 2 ? $tagSplit[3] : '';
$tagValue = count($tagSplit) > 3 ? $tagSplit[4] : '';
$validOperator = in_array($tagOperator, $this->queryOperators);
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') {
// 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
@@ -323,7 +336,8 @@ class SearchService
* Index multiple Entities at once
* @param Entity[] $entities
*/
- protected function indexEntities($entities) {
+ protected function indexEntities($entities)
+ {
$terms = [];
foreach ($entities as $entity) {
$nameTerms = $this->generateTermArrayFromText($entity->name, 5);
@@ -386,7 +400,9 @@ class SearchService
$token = strtok($text, $splitChars);
while ($token !== false) {
- if (!isset($tokenMap[$token])) $tokenMap[$token] = 0;
+ if (!isset($tokenMap[$token])) {
+ $tokenMap[$token] = 0;
+ }
$tokenMap[$token]++;
$token = strtok($splitChars);
}
@@ -410,43 +426,63 @@ class SearchService
protected function filterUpdatedAfter(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
{
- try { $date = date_create($input);
- } catch (\Exception $e) {return;}
+ try {
+ $date = date_create($input);
+ } catch (\Exception $e) {
+ return;
+ }
$query->where('updated_at', '>=', $date);
}
protected function filterUpdatedBefore(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
{
- try { $date = date_create($input);
- } catch (\Exception $e) {return;}
+ try {
+ $date = date_create($input);
+ } catch (\Exception $e) {
+ return;
+ }
$query->where('updated_at', '<', $date);
}
protected function filterCreatedAfter(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
{
- try { $date = date_create($input);
- } catch (\Exception $e) {return;}
+ try {
+ $date = date_create($input);
+ } catch (\Exception $e) {
+ return;
+ }
$query->where('created_at', '>=', $date);
}
protected function filterCreatedBefore(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
{
- try { $date = date_create($input);
- } catch (\Exception $e) {return;}
+ try {
+ $date = date_create($input);
+ } catch (\Exception $e) {
+ return;
+ }
$query->where('created_at', '<', $date);
}
protected function filterCreatedBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
{
- if (!is_numeric($input) && $input !== 'me') return;
- if ($input === 'me') $input = user()->id;
+ if (!is_numeric($input) && $input !== 'me') {
+ return;
+ }
+ if ($input === 'me') {
+ $input = user()->id;
+ }
$query->where('created_by', '=', $input);
}
protected function filterUpdatedBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $input)
{
- if (!is_numeric($input) && $input !== 'me') return;
- if ($input === 'me') $input = user()->id;
+ if (!is_numeric($input) && $input !== 'me') {
+ return;
+ }
+ if ($input === 'me') {
+ $input = user()->id;
+ }
$query->where('updated_by', '=', $input);
}
@@ -455,7 +491,10 @@ class SearchService
$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)
{
@@ -469,14 +508,14 @@ class SearchService
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);
});
}
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);
});
}
@@ -484,7 +523,9 @@ class SearchService
protected function filterSortBy(\Illuminate\Database\Eloquent\Builder $query, Entity $model, $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');
}
-}
\ No newline at end of file
+}
diff --git a/app/Services/SettingService.php b/app/Services/SettingService.php
index 18a7c0d1b..7ec3ef93a 100644
--- a/app/Services/SettingService.php
+++ b/app/Services/SettingService.php
@@ -40,8 +40,12 @@ class SettingService
*/
public function get($key, $default = false)
{
- if ($default === false) $default = config('setting-defaults.' . $key, false);
- if (isset($this->localCache[$key])) return $this->localCache[$key];
+ if ($default === false) {
+ $default = config('setting-defaults.' . $key, false);
+ }
+ if (isset($this->localCache[$key])) {
+ return $this->localCache[$key];
+ }
$value = $this->getValueFromStore($key, $default);
$formatted = $this->formatValue($value, $default);
@@ -72,12 +76,16 @@ class SettingService
{
// Check for an overriding value
$overrideValue = $this->getOverrideValue($key);
- if ($overrideValue !== null) return $overrideValue;
+ if ($overrideValue !== null) {
+ return $overrideValue;
+ }
// Check the cache
$cacheKey = $this->cachePrefix . $key;
$cacheVal = $this->cache->get($cacheKey, null);
- if ($cacheVal !== null) return $cacheVal;
+ if ($cacheVal !== null) {
+ return $cacheVal;
+ }
// Check the database
$settingObject = $this->getSettingObjectByKey($key);
@@ -98,6 +106,9 @@ class SettingService
{
$cacheKey = $this->cachePrefix . $key;
$this->cache->forget($cacheKey);
+ if (isset($this->localCache[$key])) {
+ unset($this->localCache[$key]);
+ }
}
/**
@@ -109,11 +120,17 @@ class SettingService
protected function formatValue($value, $default)
{
// Change string booleans to actual booleans
- if ($value === 'true') $value = true;
- if ($value === 'false') $value = false;
+ if ($value === 'true') {
+ $value = true;
+ }
+ if ($value === 'false') {
+ $value = false;
+ }
// Set to default if empty
- if ($value === '') $value = $default;
+ if ($value === '') {
+ $value = $default;
+ }
return $value;
}
@@ -222,8 +239,9 @@ class SettingService
*/
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;
}
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/SocialAuthService.php b/app/Services/SocialAuthService.php
index d52464539..02361e59b 100644
--- a/app/Services/SocialAuthService.php
+++ b/app/Services/SocialAuthService.php
@@ -16,7 +16,7 @@ class SocialAuthService
protected $socialite;
protected $socialAccount;
- protected $validSocialDrivers = ['google', 'github', 'facebook', 'slack', 'twitter', 'azure', 'okta'];
+ protected $validSocialDrivers = ['google', 'github', 'facebook', 'slack', 'twitter', 'azure', 'okta', 'gitlab', 'twitch'];
/**
* SocialAuthService constructor.
@@ -150,8 +150,12 @@ class SocialAuthService
{
$driver = trim(strtolower($socialDriver));
- if (!in_array($driver, $this->validSocialDrivers)) 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)]));
+ if (!in_array($driver, $this->validSocialDrivers)) {
+ 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;
}
@@ -220,5 +224,4 @@ class SocialAuthService
session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => title_case($socialDriver)]));
return redirect(user()->getEditUrl());
}
-
-}
\ No newline at end of file
+}
diff --git a/app/Services/UploadService.php b/app/Services/UploadService.php
index 44d4bb4f7..cd0567559 100644
--- a/app/Services/UploadService.php
+++ b/app/Services/UploadService.php
@@ -32,7 +32,9 @@ class UploadService
*/
protected function getStorage()
{
- if ($this->storageInstance !== null) return $this->storageInstance;
+ if ($this->storageInstance !== null) {
+ return $this->storageInstance;
+ }
$storageType = config('filesystems.default');
$this->storageInstance = $this->fileSystem->disk($storageType);
@@ -40,7 +42,6 @@ class UploadService
return $this->storageInstance;
}
-
/**
* Check whether or not a folder is empty.
* @param $path
@@ -61,4 +62,4 @@ class UploadService
{
return strtolower(config('filesystems.default')) === 'local';
}
-}
\ No newline at end of file
+}
diff --git a/app/Services/ViewService.php b/app/Services/ViewService.php
index 770a9e39f..ddcf2eb7e 100644
--- a/app/Services/ViewService.php
+++ b/app/Services/ViewService.php
@@ -27,7 +27,9 @@ class ViewService
public function add(Entity $entity)
{
$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();
// Add view if model exists
if ($view) {
@@ -77,12 +79,16 @@ class ViewService
public function getUserRecentlyViewed($count = 10, $page = 0, $filterModel = false)
{
$user = user();
- if ($user === null || $user->isDefault()) return collect();
+ if ($user === null || $user->isDefault()) {
+ return collect();
+ }
$query = $this->permissionService
->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);
$viewables = $query->with('viewable')->orderBy('updated_at', 'desc')
@@ -97,5 +103,4 @@ class ViewService
{
$this->view->truncate();
}
-
-}
\ No newline at end of file
+}
diff --git a/app/SocialAccount.php b/app/SocialAccount.php
index e7c9b4cc5..fdba6a04f 100644
--- a/app/SocialAccount.php
+++ b/app/SocialAccount.php
@@ -1,6 +1,5 @@
morphTo('entity');
}
-}
\ No newline at end of file
+}
diff --git a/app/User.php b/app/User.php
index 8033557e4..d1e9b38a7 100644
--- a/app/User.php
+++ b/app/User.php
@@ -60,7 +60,9 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
*/
public function roles()
{
- if ($this->id === 0) return ;
+ if ($this->id === 0) {
+ return ;
+ }
return $this->belongsToMany(Role::class);
}
@@ -81,7 +83,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
*/
public function hasSystemRole($role)
{
- return $this->roles->pluck('system_name')->contains('admin');
+ return $this->roles->pluck('system_name')->contains($role);
}
/**
@@ -91,9 +93,11 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
*/
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');
- $permissions = $this->roles->map(function($role) {
+ $permissions = $this->roles->map(function ($role) {
return $role->permissions;
})->flatten()->unique();
$this->permissions = $permissions;
@@ -107,7 +111,9 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
*/
public function can($permissionName)
{
- if ($this->email === 'guest') return false;
+ if ($this->email === 'guest') {
+ return false;
+ }
return $this->permissions()->pluck('name')->contains($permissionName);
}
@@ -162,7 +168,9 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
{
$default = baseUrl('/user_avatar.png');
$imageId = $this->image_id;
- if ($imageId === 0 || $imageId === '0' || $imageId === null) return $default;
+ if ($imageId === 0 || $imageId === '0' || $imageId === null) {
+ return $default;
+ }
try {
$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)
{
- if (strlen($this->name) <= $chars) return $this->name;
+ if (strlen($this->name) <= $chars) {
+ return $this->name;
+ }
$splitName = explode(' ', $this->name);
- if (strlen($splitName[0]) <= $chars) return $splitName[0];
+ if (strlen($splitName[0]) <= $chars) {
+ return $splitName[0];
+ }
return '';
}
diff --git a/app/helpers.php b/app/helpers.php
index 153f1e49f..daa747e71 100644
--- a/app/helpers.php
+++ b/app/helpers.php
@@ -74,7 +74,9 @@ function userCan($permission, Ownable $ownable = null)
function setting($key = null, $default = false)
{
$settingService = resolve(\BookStack\Services\SettingService::class);
- if (is_null($key)) return $settingService;
+ if (is_null($key)) {
+ return $settingService;
+ }
return $settingService->get($key, $default);
}
@@ -87,7 +89,9 @@ function setting($key = null, $default = false)
function baseUrl($path, $forceAppDomain = false)
{
$isFullUrl = strpos($path, 'http') === 0;
- if ($isFullUrl && !$forceAppDomain) return $path;
+ if ($isFullUrl && !$forceAppDomain) {
+ return $path;
+ }
$path = trim($path, '/');
// 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);
}
-function icon($name, $attrs = []) {
+function icon($name, $attrs = [])
+{
$iconPath = resource_path('assets/icons/' . $name . '.svg');
$attrString = ' ';
foreach ($attrs as $attrName => $attr) {
@@ -159,11 +164,15 @@ function sortUrl($path, $data, $overrideData = [])
foreach ($queryData as $name => $value) {
$trimmedVal = trim($value);
- if ($trimmedVal === '') continue;
+ if ($trimmedVal === '') {
+ continue;
+ }
$queryStringSections[] = urlencode($name) . '=' . urlencode($trimmedVal);
}
- if (count($queryStringSections) === 0) return $path;
+ if (count($queryStringSections) === 0) {
+ return $path;
+ }
return baseUrl($path . '?' . implode('&', $queryStringSections));
-}
\ No newline at end of file
+}
diff --git a/composer.json b/composer.json
index 5b9802f52..5106ed0bb 100644
--- a/composer.json
+++ b/composer.json
@@ -18,7 +18,9 @@
"barryvdh/laravel-snappy": "^0.4.0",
"socialiteproviders/slack": "^3.0",
"socialiteproviders/microsoft-azure": "^3.0",
- "socialiteproviders/okta": "^1.0"
+ "socialiteproviders/okta": "^1.0",
+ "socialiteproviders/gitlab": "^3.0",
+ "socialiteproviders/twitch": "^3.0"
},
"require-dev": {
"filp/whoops": "~2.0",
@@ -29,7 +31,8 @@
"symfony/dom-crawler": "3.1.*",
"laravel/browser-kit-testing": "^2.0",
"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": {
"classmap": [
diff --git a/composer.lock b/composer.lock
index 057e6007a..9370bebff 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "content-hash": "7d60f09393b99551e9ffdb6622ed7ade",
+ "content-hash": "ed85d10e69b1071020178cb400a80e48",
"packages": [
{
"name": "aws/aws-sdk-php",
- "version": "3.45.3",
+ "version": "3.52.6",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
- "reference": "d0abb0b1194fa64973b135191f56df991bc5787c"
+ "reference": "c9af7657eddc0267cc7ac4f969c10d5c18459992"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d0abb0b1194fa64973b135191f56df991bc5787c",
- "reference": "d0abb0b1194fa64973b135191f56df991bc5787c",
+ "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/c9af7657eddc0267cc7ac4f969c10d5c18459992",
+ "reference": "c9af7657eddc0267cc7ac4f969c10d5c18459992",
"shasum": ""
},
"require": {
@@ -84,25 +84,25 @@
"s3",
"sdk"
],
- "time": "2017-12-08T21:36:50+00:00"
+ "time": "2018-02-09T22:53:37+00:00"
},
{
"name": "barryvdh/laravel-dompdf",
- "version": "v0.8.1",
+ "version": "v0.8.2",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-dompdf.git",
- "reference": "3b2235e589616331d68482d61b7763789a2600fe"
+ "reference": "7dcdecfa125c174d0abe723603633dc2756ea3af"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/3b2235e589616331d68482d61b7763789a2600fe",
- "reference": "3b2235e589616331d68482d61b7763789a2600fe",
+ "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/7dcdecfa125c174d0abe723603633dc2756ea3af",
+ "reference": "7dcdecfa125c174d0abe723603633dc2756ea3af",
"shasum": ""
},
"require": {
"dompdf/dompdf": "^0.8",
- "illuminate/support": "5.1.x|5.2.x|5.3.x|5.4.x|5.5.x",
+ "illuminate/support": "5.1.x|5.2.x|5.3.x|5.4.x|5.5.x|5.6.x",
"php": ">=5.5.9"
},
"type": "library",
@@ -140,32 +140,32 @@
"laravel",
"pdf"
],
- "time": "2017-07-29T19:01:17+00:00"
+ "time": "2018-02-07T17:43:25+00:00"
},
{
"name": "barryvdh/laravel-snappy",
- "version": "v0.4.0",
+ "version": "v0.4.1",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-snappy.git",
- "reference": "f08c7e5b4ddea585bfcd48ab4f40f920e58dd1cf"
+ "reference": "5f6e7f3ba15c867d1b8e2885d454110270616ebe"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/barryvdh/laravel-snappy/zipball/f08c7e5b4ddea585bfcd48ab4f40f920e58dd1cf",
- "reference": "f08c7e5b4ddea585bfcd48ab4f40f920e58dd1cf",
+ "url": "https://api.github.com/repos/barryvdh/laravel-snappy/zipball/5f6e7f3ba15c867d1b8e2885d454110270616ebe",
+ "reference": "5f6e7f3ba15c867d1b8e2885d454110270616ebe",
"shasum": ""
},
"require": {
- "illuminate/filesystem": "5.0.x|5.1.x|5.2.x|5.3.x|5.4.x|5.5.x",
- "illuminate/support": "5.0.x|5.1.x|5.2.x|5.3.x|5.4.x|5.5.x",
- "knplabs/knp-snappy": "*",
+ "illuminate/filesystem": "5.0.x|5.1.x|5.2.x|5.3.x|5.4.x|5.5.x|5.6.x",
+ "illuminate/support": "5.0.x|5.1.x|5.2.x|5.3.x|5.4.x|5.5.x|5.6.x",
+ "knplabs/knp-snappy": "^1",
"php": ">=5.4.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "0.3-dev"
+ "dev-master": "0.4-dev"
},
"laravel": {
"providers": [
@@ -201,7 +201,7 @@
"wkhtmltoimage",
"wkhtmltopdf"
],
- "time": "2017-08-14T06:48:50+00:00"
+ "time": "2018-02-08T15:58:26+00:00"
},
{
"name": "cogpowered/finediff",
@@ -898,16 +898,16 @@
},
{
"name": "knplabs/knp-snappy",
- "version": "v1.0.3",
+ "version": "v1.0.4",
"source": {
"type": "git",
"url": "https://github.com/KnpLabs/snappy.git",
- "reference": "68590ef3aa94425b1c0019cc28ce471729f51fcb"
+ "reference": "144c4ecd1ccaeda936bf832b93079efc490e6850"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/68590ef3aa94425b1c0019cc28ce471729f51fcb",
- "reference": "68590ef3aa94425b1c0019cc28ce471729f51fcb",
+ "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/144c4ecd1ccaeda936bf832b93079efc490e6850",
+ "reference": "144c4ecd1ccaeda936bf832b93079efc490e6850",
"shasum": ""
},
"require": {
@@ -960,20 +960,20 @@
"thumbnail",
"wkhtmltopdf"
],
- "time": "2017-12-03T23:18:18+00:00"
+ "time": "2018-01-22T19:40:51+00:00"
},
{
"name": "laravel/framework",
- "version": "v5.5.24",
+ "version": "v5.5.34",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
- "reference": "06135405bb1f736dac5e9529ed1541fc446c9c0f"
+ "reference": "1de7c0aec13eadbdddc2d1ba4019b064b2c6b966"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/framework/zipball/06135405bb1f736dac5e9529ed1541fc446c9c0f",
- "reference": "06135405bb1f736dac5e9529ed1541fc446c9c0f",
+ "url": "https://api.github.com/repos/laravel/framework/zipball/1de7c0aec13eadbdddc2d1ba4019b064b2c6b966",
+ "reference": "1de7c0aec13eadbdddc2d1ba4019b064b2c6b966",
"shasum": ""
},
"require": {
@@ -1053,6 +1053,7 @@
"guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~6.0).",
"laravel/tinker": "Required to use the tinker console command (~1.0).",
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).",
+ "league/flysystem-cached-adapter": "Required to use Flysystem caching (~1.0).",
"league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).",
"nexmo/client": "Required to use the Nexmo transport (~1.0).",
"pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).",
@@ -1093,7 +1094,7 @@
"framework",
"laravel"
],
- "time": "2017-12-07T01:28:21+00:00"
+ "time": "2018-02-06T15:36:55+00:00"
},
{
"name": "laravel/socialite",
@@ -1159,16 +1160,16 @@
},
{
"name": "league/flysystem",
- "version": "1.0.41",
+ "version": "1.0.42",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
- "reference": "f400aa98912c561ba625ea4065031b7a41e5a155"
+ "reference": "09eabc54e199950041aef258a85847676496fe8e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f400aa98912c561ba625ea4065031b7a41e5a155",
- "reference": "f400aa98912c561ba625ea4065031b7a41e5a155",
+ "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/09eabc54e199950041aef258a85847676496fe8e",
+ "reference": "09eabc54e199950041aef258a85847676496fe8e",
"shasum": ""
},
"require": {
@@ -1179,12 +1180,13 @@
},
"require-dev": {
"ext-fileinfo": "*",
- "mockery/mockery": "~0.9",
- "phpspec/phpspec": "^2.2",
- "phpunit/phpunit": "~4.8"
+ "phpspec/phpspec": "^3.4",
+ "phpunit/phpunit": "^5.7"
},
"suggest": {
"ext-fileinfo": "Required for MimeType",
+ "ext-ftp": "Allows you to use FTP server storage",
+ "ext-openssl": "Allows you to use FTPS server storage",
"league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2",
"league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3",
"league/flysystem-azure": "Allows you to use Windows Azure Blob storage",
@@ -1238,7 +1240,7 @@
"sftp",
"storage"
],
- "time": "2017-08-06T17:41:04+00:00"
+ "time": "2018-01-27T16:03:56+00:00"
},
{
"name": "league/flysystem-aws-s3-v3",
@@ -1951,16 +1953,16 @@
},
{
"name": "ramsey/uuid",
- "version": "3.7.1",
+ "version": "3.7.3",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
- "reference": "45cffe822057a09e05f7bd09ec5fb88eeecd2334"
+ "reference": "44abcdad877d9a46685a3a4d221e3b2c4b87cb76"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ramsey/uuid/zipball/45cffe822057a09e05f7bd09ec5fb88eeecd2334",
- "reference": "45cffe822057a09e05f7bd09ec5fb88eeecd2334",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/44abcdad877d9a46685a3a4d221e3b2c4b87cb76",
+ "reference": "44abcdad877d9a46685a3a4d221e3b2c4b87cb76",
"shasum": ""
},
"require": {
@@ -1971,17 +1973,15 @@
"rhumsaa/uuid": "self.version"
},
"require-dev": {
- "apigen/apigen": "^4.1",
- "codeception/aspect-mock": "^1.0 | ^2.0",
+ "codeception/aspect-mock": "^1.0 | ~2.0.0",
"doctrine/annotations": "~1.2.0",
"goaop/framework": "1.0.0-alpha.2 | ^1.0 | ^2.1",
"ircmaxell/random-lib": "^1.1",
"jakub-onderka/php-parallel-lint": "^0.9.0",
- "mockery/mockery": "^0.9.4",
+ "mockery/mockery": "^0.9.9",
"moontoast/math": "^1.1",
"php-mock/php-mock-phpunit": "^0.3|^1.1",
- "phpunit/phpunit": "^4.7|>=5.0 <5.4",
- "satooshi/php-coveralls": "^0.6.1",
+ "phpunit/phpunit": "^4.7|^5.0",
"squizlabs/php_codesniffer": "^2.3"
},
"suggest": {
@@ -2029,7 +2029,7 @@
"identifier",
"uuid"
],
- "time": "2017-09-22T20:46:04+00:00"
+ "time": "2018-01-20T00:28:24+00:00"
},
{
"name": "sabberworm/php-css-parser",
@@ -2076,17 +2076,54 @@
"time": "2016-07-19T19:14:21+00:00"
},
{
- "name": "socialiteproviders/manager",
- "version": "v3.3.0",
+ "name": "socialiteproviders/gitlab",
+ "version": "v3.0.1",
"source": {
"type": "git",
- "url": "https://github.com/SocialiteProviders/Manager.git",
- "reference": "ac108bce073135a55dfebf28ceaf1459669348e8"
+ "url": "https://github.com/SocialiteProviders/GitLab.git",
+ "reference": "c96dc004563a3caf157608fe9aa9e45c79065d00"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/SocialiteProviders/Manager/zipball/ac108bce073135a55dfebf28ceaf1459669348e8",
- "reference": "ac108bce073135a55dfebf28ceaf1459669348e8",
+ "url": "https://api.github.com/repos/SocialiteProviders/GitLab/zipball/c96dc004563a3caf157608fe9aa9e45c79065d00",
+ "reference": "c96dc004563a3caf157608fe9aa9e45c79065d00",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0",
+ "socialiteproviders/manager": "~3.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "SocialiteProviders\\GitLab\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christoffer Martinsen",
+ "email": "christoffermartinsen@gmail.com"
+ }
+ ],
+ "description": "GitLab OAuth2 Provider for Laravel Socialite",
+ "time": "2017-01-31T05:06:13+00:00"
+ },
+ {
+ "name": "socialiteproviders/manager",
+ "version": "v3.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/SocialiteProviders/Manager.git",
+ "reference": "1de3f3d874392da6f1a4c0bf30d843e9cd903ea7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/SocialiteProviders/Manager/zipball/1de3f3d874392da6f1a4c0bf30d843e9cd903ea7",
+ "reference": "1de3f3d874392da6f1a4c0bf30d843e9cd903ea7",
"shasum": ""
},
"require": {
@@ -2122,7 +2159,7 @@
}
],
"description": "Easily add new or override built-in providers in Laravel Socialite.",
- "time": "2017-09-21T07:21:55+00:00"
+ "time": "2017-11-20T08:42:57+00:00"
},
{
"name": "socialiteproviders/microsoft-azure",
@@ -2235,6 +2272,43 @@
"description": "Slack OAuth2 Provider for Laravel Socialite",
"time": "2017-04-10T05:10:48+00:00"
},
+ {
+ "name": "socialiteproviders/twitch",
+ "version": "v3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/SocialiteProviders/Twitch.git",
+ "reference": "a7ad148c0b42d0c607d8a034b6e47faf5fc85e93"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/SocialiteProviders/Twitch/zipball/a7ad148c0b42d0c607d8a034b6e47faf5fc85e93",
+ "reference": "a7ad148c0b42d0c607d8a034b6e47faf5fc85e93",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0",
+ "socialiteproviders/manager": "~3.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "SocialiteProviders\\Twitch\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Brian Faust",
+ "email": "hello@brianfaust.de"
+ }
+ ],
+ "description": "Twitch OAuth2 Provider for Laravel Socialite",
+ "time": "2017-01-25T09:48:29+00:00"
+ },
{
"name": "swiftmailer/swiftmailer",
"version": "v6.0.2",
@@ -2721,16 +2795,16 @@
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.6.0",
+ "version": "v1.7.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296"
+ "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
- "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
+ "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
"shasum": ""
},
"require": {
@@ -2742,7 +2816,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.6-dev"
+ "dev-master": "1.7-dev"
}
},
"autoload": {
@@ -2776,7 +2850,7 @@
"portable",
"shim"
],
- "time": "2017-10-11T12:05:26+00:00"
+ "time": "2018-01-30T19:27:44+00:00"
},
{
"name": "symfony/process",
@@ -3040,29 +3114,29 @@
},
{
"name": "tijsverkoyen/css-to-inline-styles",
- "version": "2.2.0",
+ "version": "2.2.1",
"source": {
"type": "git",
"url": "https://github.com/tijsverkoyen/CssToInlineStyles.git",
- "reference": "ab03919dfd85a74ae0372f8baf9f3c7d5c03b04b"
+ "reference": "0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/ab03919dfd85a74ae0372f8baf9f3c7d5c03b04b",
- "reference": "ab03919dfd85a74ae0372f8baf9f3c7d5c03b04b",
+ "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757",
+ "reference": "0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757",
"shasum": ""
},
"require": {
- "php": "^5.5 || ^7",
- "symfony/css-selector": "^2.7|~3.0"
+ "php": "^5.5 || ^7.0",
+ "symfony/css-selector": "^2.7 || ^3.0 || ^4.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.8|5.1.*"
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0.x-dev"
+ "dev-master": "2.2.x-dev"
}
},
"autoload": {
@@ -3083,7 +3157,7 @@
],
"description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.",
"homepage": "https://github.com/tijsverkoyen/CssToInlineStyles",
- "time": "2016-09-20T12:50:39+00:00"
+ "time": "2017-11-27T11:13:29+00:00"
},
{
"name": "vlucas/phpdotenv",
@@ -3139,26 +3213,26 @@
"packages-dev": [
{
"name": "barryvdh/laravel-debugbar",
- "version": "v3.1.0",
+ "version": "v3.1.1",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
- "reference": "01a859752094e00aa8548832312366753272f8af"
+ "reference": "f0018d359a2ad6968ad11b283283a925e017f3c9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/01a859752094e00aa8548832312366753272f8af",
- "reference": "01a859752094e00aa8548832312366753272f8af",
+ "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/f0018d359a2ad6968ad11b283283a925e017f3c9",
+ "reference": "f0018d359a2ad6968ad11b283283a925e017f3c9",
"shasum": ""
},
"require": {
- "illuminate/routing": "5.5.x",
- "illuminate/session": "5.5.x",
- "illuminate/support": "5.5.x",
- "maximebf/debugbar": "~1.14.0",
+ "illuminate/routing": "5.5.x|5.6.x",
+ "illuminate/session": "5.5.x|5.6.x",
+ "illuminate/support": "5.5.x|5.6.x",
+ "maximebf/debugbar": "~1.15.0",
"php": ">=7.0",
- "symfony/debug": "^3",
- "symfony/finder": "^3"
+ "symfony/debug": "^3|^4",
+ "symfony/finder": "^3|^4"
},
"require-dev": {
"illuminate/framework": "5.5.x"
@@ -3166,7 +3240,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.2-dev"
},
"laravel": {
"providers": [
@@ -3203,34 +3277,34 @@
"profiler",
"webprofiler"
],
- "time": "2017-09-18T13:32:46+00:00"
+ "time": "2018-02-07T08:29:09+00:00"
},
{
"name": "barryvdh/laravel-ide-helper",
- "version": "v2.4.1",
+ "version": "v2.4.3",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-ide-helper.git",
- "reference": "2b1273c45e2f8df7a625563e2283a17c14f02ae8"
+ "reference": "5c304db44fba8e9c4aa0c09739e59f7be7736fdd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/2b1273c45e2f8df7a625563e2283a17c14f02ae8",
- "reference": "2b1273c45e2f8df7a625563e2283a17c14f02ae8",
+ "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/5c304db44fba8e9c4aa0c09739e59f7be7736fdd",
+ "reference": "5c304db44fba8e9c4aa0c09739e59f7be7736fdd",
"shasum": ""
},
"require": {
"barryvdh/reflection-docblock": "^2.0.4",
- "illuminate/console": "^5.0,<5.6",
- "illuminate/filesystem": "^5.0,<5.6",
- "illuminate/support": "^5.0,<5.6",
+ "illuminate/console": "^5.0,<5.7",
+ "illuminate/filesystem": "^5.0,<5.7",
+ "illuminate/support": "^5.0,<5.7",
"php": ">=5.4.0",
"symfony/class-loader": "^2.3|^3.0"
},
"require-dev": {
"doctrine/dbal": "~2.3",
- "illuminate/config": "^5.0,<5.6",
- "illuminate/view": "^5.0,<5.6",
+ "illuminate/config": "^5.0,<5.7",
+ "illuminate/view": "^5.0,<5.7",
"phpunit/phpunit": "4.*",
"scrutinizer/ocular": "~1.1",
"squizlabs/php_codesniffer": "~2.3"
@@ -3276,7 +3350,7 @@
"phpstorm",
"sublime"
],
- "time": "2017-07-16T00:24:12+00:00"
+ "time": "2018-02-08T07:56:07+00:00"
},
{
"name": "barryvdh/reflection-docblock",
@@ -3590,22 +3664,22 @@
},
{
"name": "maximebf/debugbar",
- "version": "v1.14.1",
+ "version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/maximebf/php-debugbar.git",
- "reference": "64251a392344e3d22f3d21c3b7c531ba96eb01d2"
+ "reference": "30e7d60937ee5f1320975ca9bc7bcdd44d500f07"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/64251a392344e3d22f3d21c3b7c531ba96eb01d2",
- "reference": "64251a392344e3d22f3d21c3b7c531ba96eb01d2",
+ "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/30e7d60937ee5f1320975ca9bc7bcdd44d500f07",
+ "reference": "30e7d60937ee5f1320975ca9bc7bcdd44d500f07",
"shasum": ""
},
"require": {
"php": ">=5.3.0",
"psr/log": "^1.0",
- "symfony/var-dumper": "^2.6|^3.0"
+ "symfony/var-dumper": "^2.6|^3.0|^4.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0|^5.0"
@@ -3647,7 +3721,7 @@
"debug",
"debugbar"
],
- "time": "2017-09-13T12:19:36+00:00"
+ "time": "2017-12-15T11:13:46+00:00"
},
{
"name": "mockery/mockery",
@@ -3917,16 +3991,16 @@
},
{
"name": "phpdocumentor/reflection-docblock",
- "version": "4.2.0",
+ "version": "4.3.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "66465776cfc249844bde6d117abff1d22e06c2da"
+ "reference": "94fd0001232e47129dd3504189fa1c7225010d08"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/66465776cfc249844bde6d117abff1d22e06c2da",
- "reference": "66465776cfc249844bde6d117abff1d22e06c2da",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08",
+ "reference": "94fd0001232e47129dd3504189fa1c7225010d08",
"shasum": ""
},
"require": {
@@ -3964,7 +4038,7 @@
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
- "time": "2017-11-27T17:38:31+00:00"
+ "time": "2017-11-30T07:14:17+00:00"
},
{
"name": "phpdocumentor/type-resolver",
@@ -4327,16 +4401,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "6.5.3",
+ "version": "6.5.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "882e886cc928a0abd3c61282b2a64026237d14a4"
+ "reference": "3330ef26ade05359d006041316ed0fa9e8e3cefe"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/882e886cc928a0abd3c61282b2a64026237d14a4",
- "reference": "882e886cc928a0abd3c61282b2a64026237d14a4",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3330ef26ade05359d006041316ed0fa9e8e3cefe",
+ "reference": "3330ef26ade05359d006041316ed0fa9e8e3cefe",
"shasum": ""
},
"require": {
@@ -4354,7 +4428,7 @@
"phpunit/php-file-iterator": "^1.4.3",
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-timer": "^1.0.9",
- "phpunit/phpunit-mock-objects": "^5.0.4",
+ "phpunit/phpunit-mock-objects": "^5.0.5",
"sebastian/comparator": "^2.1",
"sebastian/diff": "^2.0",
"sebastian/environment": "^3.1",
@@ -4407,27 +4481,27 @@
"testing",
"xunit"
],
- "time": "2017-12-06T09:42:03+00:00"
+ "time": "2018-02-01T05:57:37+00:00"
},
{
"name": "phpunit/phpunit-mock-objects",
- "version": "5.0.4",
+ "version": "5.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
- "reference": "16b50f4167e5e85e81ca8a3dd105d0a5fd32009a"
+ "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/16b50f4167e5e85e81ca8a3dd105d0a5fd32009a",
- "reference": "16b50f4167e5e85e81ca8a3dd105d0a5fd32009a",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/33fd41a76e746b8fa96d00b49a23dadfa8334cdf",
+ "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.5",
"php": "^7.0",
"phpunit/php-text-template": "^1.2.1",
- "sebastian/exporter": "^3.0"
+ "sebastian/exporter": "^3.1"
},
"conflict": {
"phpunit/phpunit": "<6.0"
@@ -4466,7 +4540,7 @@
"mock",
"xunit"
],
- "time": "2017-12-02T05:31:19+00:00"
+ "time": "2018-01-06T05:45:45+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
@@ -4515,21 +4589,21 @@
},
{
"name": "sebastian/comparator",
- "version": "2.1.0",
+ "version": "2.1.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "1174d9018191e93cb9d719edec01257fc05f8158"
+ "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1174d9018191e93cb9d719edec01257fc05f8158",
- "reference": "1174d9018191e93cb9d719edec01257fc05f8158",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9",
+ "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9",
"shasum": ""
},
"require": {
"php": "^7.0",
- "sebastian/diff": "^2.0",
+ "sebastian/diff": "^2.0 || ^3.0",
"sebastian/exporter": "^3.1"
},
"require-dev": {
@@ -4575,7 +4649,7 @@
"compare",
"equality"
],
- "time": "2017-11-03T07:16:52+00:00"
+ "time": "2018-02-01T13:46:46+00:00"
},
{
"name": "sebastian/diff",
@@ -5027,6 +5101,57 @@
"homepage": "https://github.com/sebastianbergmann/version",
"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",
"version": "v3.3.6",
@@ -5181,16 +5306,16 @@
},
{
"name": "webmozart/assert",
- "version": "1.2.0",
+ "version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
- "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
+ "reference": "0df1908962e7a3071564e857d86874dad1ef204a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f",
- "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
+ "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
+ "reference": "0df1908962e7a3071564e857d86874dad1ef204a",
"shasum": ""
},
"require": {
@@ -5227,7 +5352,7 @@
"check",
"validate"
],
- "time": "2016-11-23T20:04:58+00:00"
+ "time": "2018-01-29T19:49:41+00:00"
}
],
"aliases": [],
diff --git a/config/app.php b/config/app.php
index 3be50b6c5..7e2e1487f 100755
--- a/config/app.php
+++ b/config/app.php
@@ -2,11 +2,14 @@
return [
-
'env' => env('APP_ENV', 'production'),
'editor' => env('APP_EDITOR', 'html'),
+ 'views' => [
+ 'books' => env('APP_VIEWS_BOOKS', 'list')
+ ],
+
/*
|--------------------------------------------------------------------------
| Application Debug Mode
@@ -58,7 +61,7 @@ return [
*/
'locale' => env('APP_LANG', 'en'),
- 'locales' => ['en', 'de', 'es', 'es_AR', 'fr', 'nl', 'pt_BR', 'sk', 'ja', 'pl', 'it', 'ru'],
+ 'locales' => ['en', 'de', 'es', 'es_AR', 'fr', 'nl', 'pt_BR', 'sk', 'sv', 'ja', 'pl', 'it', 'ru', 'zh_CN'],
/*
|--------------------------------------------------------------------------
diff --git a/config/filesystems.php b/config/filesystems.php
index 836f68d3d..b7ebf5b2d 100644
--- a/config/filesystems.php
+++ b/config/filesystems.php
@@ -56,7 +56,12 @@ return [
'local' => [
'driver' => 'local',
- 'root' => base_path(),
+ 'root' => public_path(),
+ ],
+
+ 'local_secure' => [
+ 'driver' => 'local',
+ 'root' => storage_path(),
],
'ftp' => [
diff --git a/config/services.php b/config/services.php
index ba9be69de..825b1f109 100644
--- a/config/services.php
+++ b/config/services.php
@@ -13,7 +13,13 @@ return [
| to have a conventional place to find your various credentials.
|
*/
+
+ // Single option to disable non-auth external services such as Gravatar and Draw.io
'disable_services' => env('DISABLE_EXTERNAL_SERVICES', false),
+ 'gravatar' => env('GRAVATAR', !env('DISABLE_EXTERNAL_SERVICES', false)),
+ 'drawio' => env('DRAWIO', !env('DISABLE_EXTERNAL_SERVICES', false)),
+
+
'callback_url' => env('APP_URL', false),
'mailgun' => [
@@ -86,7 +92,22 @@ return [
'redirect' => env('APP_URL') . '/login/service/okta/callback',
'base_url' => env('OKTA_BASE_URL'),
'name' => 'Okta',
- ],
+ ],
+
+ 'gitlab' => [
+ 'client_id' => env('GITLAB_APP_ID'),
+ 'client_secret' => env('GITLAB_APP_SECRET'),
+ 'redirect' => env('APP_URL') . '/login/service/gitlab/callback',
+ 'instance_uri' => env('GITLAB_BASE_URI'), // Needed only for self hosted instances
+ 'name' => 'GitLab',
+ ],
+
+ 'twitch' => [
+ 'client_id' => env('TWITCH_APP_ID'),
+ 'client_secret' => env('TWITCH_APP_SECRET'),
+ 'redirect' => env('APP_URL') . '/login/service/twitch/callback',
+ 'name' => 'Twitch',
+ ],
'ldap' => [
'server' => env('LDAP_SERVER', false),
diff --git a/config/view.php b/config/view.php
index e193ab61d..8dc2841e7 100644
--- a/config/view.php
+++ b/config/view.php
@@ -1,5 +1,10 @@
[
- realpath(base_path('resources/views')),
- ],
+ 'paths' => $viewPaths,
/*
|--------------------------------------------------------------------------
diff --git a/package.json b/package.json
index 23b01cf6e..42e892333 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
"babelify": "^7.3.0",
"browserify": "^14.3.0",
"envify": "^4.0.0",
- "gulp": "3.9.1",
+ "gulp": "^3.9.1",
"gulp-autoprefixer": "3.1.1",
"gulp-clean-css": "^3.0.4",
"gulp-livereload": "^3.8.1",
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 000000000..009791fc9
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,8 @@
+
+
{!! $book->searchSnippet !!}
@else{{ $book->getExcerpt(130) }}
@endif -