- - Email Confirmation-
- Thanks for joining {{ setting('app-name')}}.
|
-
diff --git a/.gitignore b/.gitignore
index 65c56ebbb..919b3e75d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,4 +10,6 @@ Homestead.yaml
/public/bower
/storage/images
_ide_helper.php
-/storage/debugbar
\ No newline at end of file
+/storage/debugbar
+.phpstorm.meta.php
+yarn.lock
diff --git a/app/Attachment.php b/app/Attachment.php
new file mode 100644
index 000000000..fe291bec2
--- /dev/null
+++ b/app/Attachment.php
@@ -0,0 +1,36 @@
+name, '.')) return $this->name;
+ return $this->name . '.' . $this->extension;
+ }
+
+ /**
+ * Get the page this file was uploaded to.
+ * @return Page
+ */
+ public function page()
+ {
+ return $this->belongsTo(Page::class, 'uploaded_to');
+ }
+
+ /**
+ * Get the url of this file.
+ * @return string
+ */
+ public function getUrl()
+ {
+ return baseUrl('/attachments/' . $this->id);
+ }
+
+}
diff --git a/app/Book.php b/app/Book.php
index aa2dee9c0..91f74ca64 100644
--- a/app/Book.php
+++ b/app/Book.php
@@ -13,9 +13,9 @@ class Book extends Entity
public function getUrl($path = false)
{
if ($path !== false) {
- return baseUrl('/books/' . $this->slug . '/' . trim($path, '/'));
+ return baseUrl('/books/' . urlencode($this->slug) . '/' . trim($path, '/'));
}
- return baseUrl('/books/' . $this->slug);
+ return baseUrl('/books/' . urlencode($this->slug));
}
/*
diff --git a/app/Chapter.php b/app/Chapter.php
index 8f0453172..cc5518b7a 100644
--- a/app/Chapter.php
+++ b/app/Chapter.php
@@ -32,9 +32,9 @@ class Chapter extends Entity
{
$bookSlug = $this->getAttribute('bookSlug') ? $this->getAttribute('bookSlug') : $this->book->slug;
if ($path !== false) {
- return baseUrl('/books/' . $bookSlug. '/chapter/' . $this->slug . '/' . trim($path, '/'));
+ return baseUrl('/books/' . urlencode($bookSlug) . '/chapter/' . urlencode($this->slug) . '/' . trim($path, '/'));
}
- return baseUrl('/books/' . $bookSlug. '/chapter/' . $this->slug);
+ return baseUrl('/books/' . urlencode($bookSlug) . '/chapter/' . urlencode($this->slug));
}
/**
diff --git a/app/EmailConfirmation.php b/app/EmailConfirmation.php
deleted file mode 100644
index e77b754bb..000000000
--- a/app/EmailConfirmation.php
+++ /dev/null
@@ -1,16 +0,0 @@
-belongsTo(User::class);
- }
-
-}
diff --git a/app/Entity.php b/app/Entity.php
index 2c447814f..186059f00 100644
--- a/app/Entity.php
+++ b/app/Entity.php
@@ -162,18 +162,21 @@ class Entity extends Ownable
$exactTerms = [];
$fuzzyTerms = [];
$search = static::newQuery();
+
foreach ($terms as $key => $term) {
- $safeTerm = htmlentities($term, ENT_QUOTES);
- $safeTerm = preg_replace('/[+\-><\(\)~*\"@]+/', ' ', $safeTerm);
- if (preg_match('/".*?"/', $safeTerm) || is_numeric($safeTerm)) {
- $safeTerm = preg_replace('/^"(.*?)"$/', '$1', $term);
- $exactTerms[] = '%' . $safeTerm . '%';
+ $term = htmlentities($term, ENT_QUOTES);
+ $term = preg_replace('/[+\-><\(\)~*\"@]+/', ' ', $term);
+ if (preg_match('/".*?"/', $term) || is_numeric($term)) {
+ $term = str_replace('"', '', $term);
+ $exactTerms[] = '%' . $term . '%';
} else {
- $safeTerm = '' . $safeTerm . '*';
- if (trim($safeTerm) !== '*') $fuzzyTerms[] = $safeTerm;
+ $term = '' . $term . '*';
+ if ($term !== '*') $fuzzyTerms[] = $term;
}
}
- $isFuzzy = count($exactTerms) === 0 || count($fuzzyTerms) > 0;
+
+ $isFuzzy = count($exactTerms) === 0 && count($fuzzyTerms) > 0;
+
// Perform fulltext search if relevant terms exist.
if ($isFuzzy) {
@@ -193,6 +196,7 @@ class Entity extends Ownable
}
});
}
+
$orderBy = $isFuzzy ? 'title_relevance' : 'updated_at';
// Add additional where terms
diff --git a/app/Events/Event.php b/app/Events/Event.php
deleted file mode 100644
index dfe173828..000000000
--- a/app/Events/Event.php
+++ /dev/null
@@ -1,8 +0,0 @@
-getPrevious());
return $message;
}
+
+ /**
+ * Convert an authentication exception into an unauthenticated response.
+ *
+ * @param \Illuminate\Http\Request $request
+ * @param \Illuminate\Auth\AuthenticationException $exception
+ * @return \Illuminate\Http\Response
+ */
+ protected function unauthenticated($request, AuthenticationException $exception)
+ {
+ if ($request->expectsJson()) {
+ return response()->json(['error' => 'Unauthenticated.'], 401);
+ }
+
+ return redirect()->guest('login');
+ }
}
diff --git a/app/Http/Controllers/AttachmentController.php b/app/Http/Controllers/AttachmentController.php
new file mode 100644
index 000000000..62be0b852
--- /dev/null
+++ b/app/Http/Controllers/AttachmentController.php
@@ -0,0 +1,215 @@
+attachmentService = $attachmentService;
+ $this->attachment = $attachment;
+ $this->pageRepo = $pageRepo;
+ parent::__construct();
+ }
+
+
+ /**
+ * Endpoint at which attachments are uploaded to.
+ * @param Request $request
+ * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
+ */
+ public function upload(Request $request)
+ {
+ $this->validate($request, [
+ 'uploaded_to' => 'required|integer|exists:pages,id',
+ 'file' => 'required|file'
+ ]);
+
+ $pageId = $request->get('uploaded_to');
+ $page = $this->pageRepo->getById($pageId, true);
+
+ $this->checkPermission('attachment-create-all');
+ $this->checkOwnablePermission('page-update', $page);
+
+ $uploadedFile = $request->file('file');
+
+ try {
+ $attachment = $this->attachmentService->saveNewUpload($uploadedFile, $pageId);
+ } catch (FileUploadException $e) {
+ return response($e->getMessage(), 500);
+ }
+
+ return response()->json($attachment);
+ }
+
+ /**
+ * Update an uploaded attachment.
+ * @param int $attachmentId
+ * @param Request $request
+ * @return mixed
+ */
+ public function uploadUpdate($attachmentId, Request $request)
+ {
+ $this->validate($request, [
+ 'uploaded_to' => 'required|integer|exists:pages,id',
+ 'file' => 'required|file'
+ ]);
+
+ $pageId = $request->get('uploaded_to');
+ $page = $this->pageRepo->getById($pageId, true);
+ $attachment = $this->attachment->findOrFail($attachmentId);
+
+ $this->checkOwnablePermission('page-update', $page);
+ $this->checkOwnablePermission('attachment-create', $attachment);
+
+ if (intval($pageId) !== intval($attachment->uploaded_to)) {
+ return $this->jsonError('Page mismatch during attached file update');
+ }
+
+ $uploadedFile = $request->file('file');
+
+ try {
+ $attachment = $this->attachmentService->saveUpdatedUpload($uploadedFile, $attachment);
+ } catch (FileUploadException $e) {
+ return response($e->getMessage(), 500);
+ }
+
+ return response()->json($attachment);
+ }
+
+ /**
+ * Update the details of an existing file.
+ * @param $attachmentId
+ * @param Request $request
+ * @return Attachment|mixed
+ */
+ public function update($attachmentId, Request $request)
+ {
+ $this->validate($request, [
+ 'uploaded_to' => 'required|integer|exists:pages,id',
+ 'name' => 'required|string|min:1|max:255',
+ 'link' => 'url|min:1|max:255'
+ ]);
+
+ $pageId = $request->get('uploaded_to');
+ $page = $this->pageRepo->getById($pageId, true);
+ $attachment = $this->attachment->findOrFail($attachmentId);
+
+ $this->checkOwnablePermission('page-update', $page);
+ $this->checkOwnablePermission('attachment-create', $attachment);
+
+ if (intval($pageId) !== intval($attachment->uploaded_to)) {
+ return $this->jsonError('Page mismatch during attachment update');
+ }
+
+ $attachment = $this->attachmentService->updateFile($attachment, $request->all());
+ return $attachment;
+ }
+
+ /**
+ * Attach a link to a page.
+ * @param Request $request
+ * @return mixed
+ */
+ public function attachLink(Request $request)
+ {
+ $this->validate($request, [
+ 'uploaded_to' => 'required|integer|exists:pages,id',
+ 'name' => 'required|string|min:1|max:255',
+ 'link' => 'required|url|min:1|max:255'
+ ]);
+
+ $pageId = $request->get('uploaded_to');
+ $page = $this->pageRepo->getById($pageId, true);
+
+ $this->checkPermission('attachment-create-all');
+ $this->checkOwnablePermission('page-update', $page);
+
+ $attachmentName = $request->get('name');
+ $link = $request->get('link');
+ $attachment = $this->attachmentService->saveNewFromLink($attachmentName, $link, $pageId);
+
+ return response()->json($attachment);
+ }
+
+ /**
+ * Get the attachments for a specific page.
+ * @param $pageId
+ * @return mixed
+ */
+ public function listForPage($pageId)
+ {
+ $page = $this->pageRepo->getById($pageId, true);
+ $this->checkOwnablePermission('page-view', $page);
+ return response()->json($page->attachments);
+ }
+
+ /**
+ * Update the attachment sorting.
+ * @param $pageId
+ * @param Request $request
+ * @return mixed
+ */
+ public function sortForPage($pageId, Request $request)
+ {
+ $this->validate($request, [
+ 'files' => 'required|array',
+ 'files.*.id' => 'required|integer',
+ ]);
+ $page = $this->pageRepo->getById($pageId);
+ $this->checkOwnablePermission('page-update', $page);
+
+ $attachments = $request->get('files');
+ $this->attachmentService->updateFileOrderWithinPage($attachments, $pageId);
+ return response()->json(['message' => 'Attachment order updated']);
+ }
+
+ /**
+ * Get an attachment from storage.
+ * @param $attachmentId
+ * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Symfony\Component\HttpFoundation\Response
+ */
+ public function get($attachmentId)
+ {
+ $attachment = $this->attachment->findOrFail($attachmentId);
+ $page = $this->pageRepo->getById($attachment->uploaded_to);
+ $this->checkOwnablePermission('page-view', $page);
+
+ if ($attachment->external) {
+ return redirect($attachment->path);
+ }
+
+ $attachmentContents = $this->attachmentService->getAttachmentFromStorage($attachment);
+ return response($attachmentContents, 200, [
+ 'Content-Type' => 'application/octet-stream',
+ 'Content-Disposition' => 'attachment; filename="'. $attachment->getFileName() .'"'
+ ]);
+ }
+
+ /**
+ * Delete a specific attachment in the system.
+ * @param $attachmentId
+ * @return mixed
+ */
+ public function delete($attachmentId)
+ {
+ $attachment = $this->attachment->findOrFail($attachmentId);
+ $this->checkOwnablePermission('attachment-delete', $attachment);
+ $this->attachmentService->deleteFile($attachment);
+ return response()->json(['message' => 'Attachment deleted']);
+ }
+}
diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php
new file mode 100644
index 000000000..45e40e6fe
--- /dev/null
+++ b/app/Http/Controllers/Auth/ForgotPasswordController.php
@@ -0,0 +1,68 @@
+middleware('guest');
+ parent::__construct();
+ }
+
+
+ /**
+ * Send a reset link to the given user.
+ *
+ * @param \Illuminate\Http\Request $request
+ * @return \Illuminate\Http\RedirectResponse
+ */
+ public function sendResetLinkEmail(Request $request)
+ {
+ $this->validate($request, ['email' => 'required|email']);
+
+ // We will send the password reset link to this user. Once we have attempted
+ // to send the link, we will examine the response then see the message we
+ // need to show to the user. Finally, we'll send out a proper response.
+ $response = $this->broker()->sendResetLink(
+ $request->only('email')
+ );
+
+ if ($response === Password::RESET_LINK_SENT) {
+ $message = 'A password reset link has been sent to ' . $request->get('email') . '.';
+ session()->flash('success', $message);
+ return back()->with('status', trans($response));
+ }
+
+ // If an error was returned by the password broker, we will get this message
+ // translated so we can notify a user of the problem. We'll redirect back
+ // to where the users came from so they can attempt this process again.
+ return back()->withErrors(
+ ['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
new file mode 100644
index 000000000..0de4a8282
--- /dev/null
+++ b/app/Http/Controllers/Auth/LoginController.php
@@ -0,0 +1,123 @@
+middleware('guest', ['only' => ['getLogin', 'postLogin']]);
+ $this->socialAuthService = $socialAuthService;
+ $this->userRepo = $userRepo;
+ $this->redirectPath = baseUrl('/');
+ $this->redirectAfterLogout = baseUrl('/login');
+ parent::__construct();
+ }
+
+ public function username()
+ {
+ return config('auth.method') === 'standard' ? 'email' : 'username';
+ }
+
+ /**
+ * Overrides the action when a user is authenticated.
+ * If the user authenticated but does not exist in the user table we create them.
+ * @param Request $request
+ * @param Authenticatable $user
+ * @return \Illuminate\Http\RedirectResponse
+ * @throws AuthException
+ */
+ 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 && $user->email === null && !$request->has('email')) {
+ $request->flash();
+ session()->flash('request-email', true);
+ return redirect('/login');
+ }
+
+ if (!$user->exists && $user->email === null && $request->has('email')) {
+ $user->email = $request->get('email');
+ }
+
+ if (!$user->exists) {
+
+ // Check for users with same email already
+ $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0;
+ if ($alreadyUser) {
+ throw new AuthException('A user with the email ' . $user->email . ' already exists but with different credentials.');
+ }
+
+ $user->save();
+ $this->userRepo->attachDefaultRole($user);
+ auth()->login($user);
+ }
+
+ $path = session()->pull('url.intended', '/');
+ $path = baseUrl($path, true);
+ return redirect($path);
+ }
+
+ /**
+ * Show the application login form.
+ * @return \Illuminate\Http\Response
+ */
+ public function getLogin()
+ {
+ $socialDrivers = $this->socialAuthService->getActiveDrivers();
+ $authMethod = config('auth.method');
+ return view('auth/login', ['socialDrivers' => $socialDrivers, 'authMethod' => $authMethod]);
+ }
+
+ /**
+ * Redirect to the relevant social site.
+ * @param $socialDriver
+ * @return \Symfony\Component\HttpFoundation\RedirectResponse
+ */
+ public function getSocialLogin($socialDriver)
+ {
+ session()->put('social-callback', 'login');
+ return $this->socialAuthService->startLogIn($socialDriver);
+ }
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/Auth/PasswordController.php b/app/Http/Controllers/Auth/PasswordController.php
deleted file mode 100644
index 4dc6583ea..000000000
--- a/app/Http/Controllers/Auth/PasswordController.php
+++ /dev/null
@@ -1,76 +0,0 @@
-middleware('guest');
- }
-
-
- /**
- * Send a reset link to the given user.
- *
- * @param \Illuminate\Http\Request $request
- * @return \Illuminate\Http\Response
- */
- public function sendResetLinkEmail(Request $request)
- {
- $this->validate($request, ['email' => 'required|email']);
-
- $broker = $this->getBroker();
-
- $response = Password::broker($broker)->sendResetLink(
- $request->only('email'), $this->resetEmailBuilder()
- );
-
- switch ($response) {
- case Password::RESET_LINK_SENT:
- $message = 'A password reset link has been sent to ' . $request->get('email') . '.';
- session()->flash('success', $message);
- return $this->getSendResetLinkEmailSuccessResponse($response);
-
- case Password::INVALID_USER:
- default:
- return $this->getSendResetLinkEmailFailureResponse($response);
- }
- }
-
- /**
- * Get the response for after a successful password reset.
- *
- * @param string $response
- * @return \Symfony\Component\HttpFoundation\Response
- */
- protected function getResetSuccessResponse($response)
- {
- $message = 'Your password has been successfully reset.';
- session()->flash('success', $message);
- return redirect($this->redirectPath())->with('status', trans($response));
- }
-}
diff --git a/app/Http/Controllers/Auth/AuthController.php b/app/Http/Controllers/Auth/RegisterController.php
similarity index 66%
rename from app/Http/Controllers/Auth/AuthController.php
rename to app/Http/Controllers/Auth/RegisterController.php
index f2d3b2741..6bba6de04 100644
--- a/app/Http/Controllers/Auth/AuthController.php
+++ b/app/Http/Controllers/Auth/RegisterController.php
@@ -1,62 +1,68 @@
-middleware('guest', ['only' => ['getLogin', 'postLogin', 'getRegister', 'postRegister']]);
+ $this->middleware('guest');
$this->socialAuthService = $socialAuthService;
$this->emailConfirmationService = $emailConfirmationService;
$this->userRepo = $userRepo;
+ $this->redirectTo = baseUrl('/');
$this->redirectPath = baseUrl('/');
- $this->redirectAfterLogout = baseUrl('/login');
- $this->username = config('auth.method') === 'standard' ? 'email' : 'username';
parent::__construct();
}
/**
* Get a validator for an incoming registration request.
+ *
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
@@ -69,6 +75,10 @@ class AuthController extends Controller
]);
}
+ /**
+ * Check whether or not registrations are allowed in the app settings.
+ * @throws UserRegistrationException
+ */
protected function checkRegistrationAllowed()
{
if (!setting('registration-enabled')) {
@@ -78,7 +88,7 @@ class AuthController extends Controller
/**
* Show the application registration form.
- * @return \Illuminate\Http\Response
+ * @return Response
*/
public function getRegister()
{
@@ -89,9 +99,10 @@ class AuthController extends Controller
/**
* Handle a registration request for the application.
- * @param \Illuminate\Http\Request $request
- * @return \Illuminate\Http\Response
+ * @param Request|\Illuminate\Http\Request $request
+ * @return Response
* @throws UserRegistrationException
+ * @throws \Illuminate\Foundation\Validation\ValidationException
*/
public function postRegister(Request $request)
{
@@ -108,66 +119,18 @@ class AuthController extends Controller
return $this->registerUser($userData);
}
-
/**
- * Overrides the action when a user is authenticated.
- * If the user authenticated but does not exist in the user table we create them.
- * @param Request $request
- * @param Authenticatable $user
- * @return \Illuminate\Http\RedirectResponse
- * @throws AuthException
+ * Create a new user instance after a valid registration.
+ * @param array $data
+ * @return User
*/
- protected function authenticated(Request $request, Authenticatable $user)
+ protected function create(array $data)
{
- // Explicitly log them out for now if they do no exist.
- if (!$user->exists) auth()->logout($user);
-
- if (!$user->exists && $user->email === null && !$request->has('email')) {
- $request->flash();
- session()->flash('request-email', true);
- return redirect('/login');
- }
-
- if (!$user->exists && $user->email === null && $request->has('email')) {
- $user->email = $request->get('email');
- }
-
- if (!$user->exists) {
-
- // Check for users with same email already
- $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0;
- if ($alreadyUser) {
- throw new AuthException('A user with the email ' . $user->email . ' already exists but with different credentials.');
- }
-
- $user->save();
- $this->userRepo->attachDefaultRole($user);
- auth()->login($user);
- }
-
- $path = session()->pull('url.intended', '/');
- $path = baseUrl($path, true);
- return redirect($path);
- }
-
- /**
- * Register a new user after a registration callback.
- * @param $socialDriver
- * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
- * @throws UserRegistrationException
- */
- protected function socialRegisterCallback($socialDriver)
- {
- $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver);
- $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser);
-
- // Create an array of the user data to create a new user instance
- $userData = [
- 'name' => $socialUser->getName(),
- 'email' => $socialUser->getEmail(),
- 'password' => str_random(30)
- ];
- return $this->registerUser($userData, $socialAccount);
+ return User::create([
+ 'name' => $data['name'],
+ 'email' => $data['email'],
+ 'password' => bcrypt($data['password']),
+ ]);
}
/**
@@ -176,7 +139,7 @@ class AuthController extends Controller
* @param bool|false|SocialAccount $socialAccount
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws UserRegistrationException
- * @throws \BookStack\Exceptions\ConfirmationEmailException
+ * @throws ConfirmationEmailException
*/
protected function registerUser(array $userData, $socialAccount = false)
{
@@ -195,7 +158,13 @@ class AuthController extends Controller
if (setting('registration-confirmation') || setting('registration-restrict')) {
$newUser->save();
- $this->emailConfirmationService->sendConfirmation($newUser);
+
+ try {
+ $this->emailConfirmationService->sendConfirmation($newUser);
+ } catch (Exception $e) {
+ session()->flash('error', trans('auth.email_confirm_send_error'));
+ }
+
return redirect('/register/confirm');
}
@@ -213,18 +182,6 @@ class AuthController extends Controller
return view('auth/register-confirm');
}
- /**
- * View the confirmation email as a standard web page.
- * @param $token
- * @return \Illuminate\View\View
- * @throws UserRegistrationException
- */
- public function viewConfirmEmail($token)
- {
- $confirmation = $this->emailConfirmationService->getEmailConfirmationFromToken($token);
- return view('emails/email-confirmation', ['token' => $confirmation->token]);
- }
-
/**
* Confirms an email via a token and logs the user into the system.
* @param $token
@@ -237,8 +194,8 @@ class AuthController extends Controller
$user = $confirmation->user;
$user->email_confirmed = true;
$user->save();
- auth()->login($confirmation->user);
- session()->flash('success', 'Your email has been confirmed!');
+ auth()->login($user);
+ session()->flash('success', trans('auth.email_confirm_success'));
$this->emailConfirmationService->deleteConfirmationsByUser($user);
return redirect($this->redirectPath);
}
@@ -264,33 +221,19 @@ class AuthController extends Controller
'email' => 'required|email|exists:users,email'
]);
$user = $this->userRepo->getByEmail($request->get('email'));
+
+ try {
+ $this->emailConfirmationService->sendConfirmation($user);
+ } catch (Exception $e) {
+ session()->flash('error', trans('auth.email_confirm_send_error'));
+ return redirect('/register/confirm');
+ }
+
$this->emailConfirmationService->sendConfirmation($user);
- session()->flash('success', 'Confirmation email resent, Please check your inbox.');
+ session()->flash('success', trans('auth.email_confirm_resent'));
return redirect('/register/confirm');
}
- /**
- * Show the application login form.
- * @return \Illuminate\Http\Response
- */
- public function getLogin()
- {
- $socialDrivers = $this->socialAuthService->getActiveDrivers();
- $authMethod = config('auth.method');
- return view('auth/login', ['socialDrivers' => $socialDrivers, 'authMethod' => $authMethod]);
- }
-
- /**
- * Redirect to the relevant social site.
- * @param $socialDriver
- * @return \Symfony\Component\HttpFoundation\RedirectResponse
- */
- public function getSocialLogin($socialDriver)
- {
- session()->put('social-callback', 'login');
- return $this->socialAuthService->startLogIn($socialDriver);
- }
-
/**
* Redirect to the social site for authentication intended to register.
* @param $socialDriver
@@ -334,4 +277,25 @@ class AuthController extends Controller
return $this->socialAuthService->detachSocialAccount($socialDriver);
}
-}
+ /**
+ * Register a new user after a registration callback.
+ * @param $socialDriver
+ * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
+ * @throws UserRegistrationException
+ */
+ protected function socialRegisterCallback($socialDriver)
+ {
+ $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver);
+ $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser);
+
+ // Create an array of the user data to create a new user instance
+ $userData = [
+ 'name' => $socialUser->getName(),
+ 'email' => $socialUser->getEmail(),
+ 'password' => str_random(30)
+ ];
+ 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
new file mode 100644
index 000000000..bd64793f9
--- /dev/null
+++ b/app/Http/Controllers/Auth/ResetPasswordController.php
@@ -0,0 +1,49 @@
+middleware('guest');
+ parent::__construct();
+ }
+
+ /**
+ * Get the response for a successful password reset.
+ *
+ * @param string $response
+ * @return \Illuminate\Http\Response
+ */
+ protected function sendResetResponse($response)
+ {
+ $message = 'Your password has been successfully reset.';
+ session()->flash('success', $message);
+ return redirect($this->redirectPath())
+ ->with('status', trans($response));
+ }
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/ChapterController.php b/app/Http/Controllers/ChapterController.php
index 03ec2c110..a3fb600fd 100644
--- a/app/Http/Controllers/ChapterController.php
+++ b/app/Http/Controllers/ChapterController.php
@@ -115,9 +115,11 @@ class ChapterController extends Controller
$book = $this->bookRepo->getBySlug($bookSlug);
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
$this->checkOwnablePermission('chapter-update', $chapter);
+ if ($chapter->name !== $request->get('name')) {
+ $chapter->slug = $this->chapterRepo->findSuitableSlug($request->get('name'), $book->id, $chapter->id);
+ }
$chapter->fill($request->all());
- $chapter->slug = $this->chapterRepo->findSuitableSlug($chapter->name, $book->id, $chapter->id);
- $chapter->updated_by = auth()->user()->id;
+ $chapter->updated_by = user()->id;
$chapter->save();
Activity::add($chapter, 'chapter_update', $book->id);
return redirect($chapter->getUrl());
diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php
index 26eeb3002..2b6c88fe0 100644
--- a/app/Http/Controllers/Controller.php
+++ b/app/Http/Controllers/Controller.php
@@ -3,13 +3,11 @@
namespace BookStack\Http\Controllers;
use BookStack\Ownable;
-use HttpRequestException;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Http\Exception\HttpResponseException;
+use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
-use Illuminate\Support\Facades\Auth;
-use Illuminate\Support\Facades\Session;
use BookStack\User;
abstract class Controller extends BaseController
@@ -30,17 +28,21 @@ abstract class Controller extends BaseController
*/
public function __construct()
{
- // Get a user instance for the current user
- $user = auth()->user();
- if (!$user) $user = User::getDefault();
+ $this->middleware(function ($request, $next) {
- // Share variables with views
- view()->share('signedIn', auth()->check());
- view()->share('currentUser', $user);
+ // Get a user instance for the current user
+ $user = user();
- // Share variables with controllers
- $this->currentUser = $user;
- $this->signedIn = auth()->check();
+ // Share variables with controllers
+ $this->currentUser = $user;
+ $this->signedIn = auth()->check();
+
+ // Share variables with views
+ view()->share('signedIn', $this->signedIn);
+ view()->share('currentUser', $user);
+
+ return $next($request);
+ });
}
/**
@@ -67,8 +69,13 @@ abstract class Controller extends BaseController
*/
protected function showPermissionError()
{
- Session::flash('error', trans('errors.permission'));
- $response = request()->wantsJson() ? response()->json(['error' => trans('errors.permissionJson')], 403) : redirect('/');
+ if (request()->wantsJson()) {
+ $response = response()->json(['error' => trans('errors.permissionJson')], 403);
+ } else {
+ $response = redirect('/');
+ session()->flash('error', trans('errors.permission'));
+ }
+
throw new HttpResponseException($response);
}
@@ -79,7 +86,7 @@ abstract class Controller extends BaseController
*/
protected function checkPermission($permissionName)
{
- if (!$this->currentUser || !$this->currentUser->can($permissionName)) {
+ if (!user() || !user()->can($permissionName)) {
$this->showPermissionError();
}
return true;
@@ -121,4 +128,22 @@ abstract class Controller extends BaseController
return response()->json(['message' => $messageText], $statusCode);
}
+ /**
+ * Create the response for when a request fails validation.
+ *
+ * @param \Illuminate\Http\Request $request
+ * @param array $errors
+ * @return \Symfony\Component\HttpFoundation\Response
+ */
+ protected function buildFailedValidationResponse(Request $request, array $errors)
+ {
+ if ($request->expectsJson()) {
+ return response()->json(['validation' => $errors], 422);
+ }
+
+ return redirect()->to($this->getRedirectUrl())
+ ->withInput($request->input())
+ ->withErrors($errors, $this->errorBag());
+ }
+
}
diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php
index 1509ace95..c2d8e257c 100644
--- a/app/Http/Controllers/PageController.php
+++ b/app/Http/Controllers/PageController.php
@@ -12,6 +12,7 @@ use BookStack\Repos\ChapterRepo;
use BookStack\Repos\PageRepo;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Views;
+use GatherContent\Htmldiff\Htmldiff;
class PageController extends Controller
{
@@ -42,27 +43,60 @@ class PageController extends Controller
/**
* Show the form for creating a new page.
- * @param $bookSlug
- * @param bool $chapterSlug
+ * @param string $bookSlug
+ * @param string $chapterSlug
* @return Response
* @internal param bool $pageSlug
*/
- public function create($bookSlug, $chapterSlug = false)
+ public function create($bookSlug, $chapterSlug = null)
{
$book = $this->bookRepo->getBySlug($bookSlug);
$chapter = $chapterSlug ? $this->chapterRepo->getBySlug($chapterSlug, $book->id) : null;
$parent = $chapter ? $chapter : $book;
$this->checkOwnablePermission('page-create', $parent);
- $this->setPageTitle('Create New Page');
- $draft = $this->pageRepo->getDraftPage($book, $chapter);
- return redirect($draft->getUrl());
+ // Redirect to draft edit screen if signed in
+ if ($this->signedIn) {
+ $draft = $this->pageRepo->getDraftPage($book, $chapter);
+ return redirect($draft->getUrl());
+ }
+
+ // Otherwise show edit view
+ $this->setPageTitle('Create New Page');
+ return view('pages/guest-create', ['parent' => $parent]);
+ }
+
+ /**
+ * Create a new page as a guest user.
+ * @param Request $request
+ * @param string $bookSlug
+ * @param string|null $chapterSlug
+ * @return mixed
+ * @throws NotFoundException
+ */
+ public function createAsGuest(Request $request, $bookSlug, $chapterSlug = null)
+ {
+ $this->validate($request, [
+ 'name' => 'required|string|max:255'
+ ]);
+
+ $book = $this->bookRepo->getBySlug($bookSlug);
+ $chapter = $chapterSlug ? $this->chapterRepo->getBySlug($chapterSlug, $book->id) : null;
+ $parent = $chapter ? $chapter : $book;
+ $this->checkOwnablePermission('page-create', $parent);
+
+ $page = $this->pageRepo->getDraftPage($book, $chapter);
+ $this->pageRepo->publishDraft($page, [
+ 'name' => $request->get('name'),
+ 'html' => ''
+ ]);
+ return redirect($page->getUrl('/edit'));
}
/**
* Show form to continue editing a draft page.
- * @param $bookSlug
- * @param $pageId
+ * @param string $bookSlug
+ * @param int $pageId
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function editDraft($bookSlug, $pageId)
@@ -72,7 +106,13 @@ class PageController extends Controller
$this->checkOwnablePermission('page-create', $book);
$this->setPageTitle('Edit Page Draft');
- return view('pages/edit', ['page' => $draft, 'book' => $book, 'isDraft' => true]);
+ $draftsEnabled = $this->signedIn;
+ return view('pages/edit', [
+ 'page' => $draft,
+ 'book' => $book,
+ 'isDraft' => true,
+ 'draftsEnabled' => $draftsEnabled
+ ]);
}
/**
@@ -112,8 +152,8 @@ class PageController extends Controller
* Display the specified page.
* If the page is not found via the slug the
* revisions are searched for a match.
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @return Response
*/
public function show($bookSlug, $pageSlug)
@@ -131,14 +171,17 @@ class PageController extends Controller
$this->checkOwnablePermission('page-view', $page);
$sidebarTree = $this->bookRepo->getChildren($book);
+ $pageNav = $this->pageRepo->getPageNav($page);
+
Views::add($page);
$this->setPageTitle($page->getShortName());
- return view('pages/show', ['page' => $page, 'book' => $book, 'current' => $page, 'sidebarTree' => $sidebarTree]);
+ return view('pages/show', ['page' => $page, 'book' => $book,
+ 'current' => $page, 'sidebarTree' => $sidebarTree, 'pageNav' => $pageNav]);
}
/**
* Get page from an ajax request.
- * @param $pageId
+ * @param int $pageId
* @return \Illuminate\Http\JsonResponse
*/
public function getPageAjax($pageId)
@@ -149,8 +192,8 @@ class PageController extends Controller
/**
* Show the form for editing the specified page.
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @return Response
*/
public function edit($bookSlug, $pageSlug)
@@ -179,14 +222,20 @@ class PageController extends Controller
if (count($warnings) > 0) session()->flash('warning', implode("\n", $warnings));
- return view('pages/edit', ['page' => $page, 'book' => $book, 'current' => $page]);
+ $draftsEnabled = $this->signedIn;
+ return view('pages/edit', [
+ 'page' => $page,
+ 'book' => $book,
+ 'current' => $page,
+ 'draftsEnabled' => $draftsEnabled
+ ]);
}
/**
* Update the specified page in storage.
* @param Request $request
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @return Response
*/
public function update(Request $request, $bookSlug, $pageSlug)
@@ -205,13 +254,21 @@ class PageController extends Controller
/**
* Save a draft update as a revision.
* @param Request $request
- * @param $pageId
+ * @param int $pageId
* @return \Illuminate\Http\JsonResponse
*/
public function saveDraft(Request $request, $pageId)
{
$page = $this->pageRepo->getById($pageId, true);
$this->checkOwnablePermission('page-update', $page);
+
+ if (!$this->signedIn) {
+ return response()->json([
+ 'status' => 'error',
+ 'message' => 'Guests cannot save drafts',
+ ], 500);
+ }
+
if ($page->draft) {
$draft = $this->pageRepo->updateDraftPage($page, $request->only(['name', 'html', 'markdown']));
} else {
@@ -230,7 +287,7 @@ class PageController extends Controller
/**
* Redirect from a special link url which
* uses the page id rather than the name.
- * @param $pageId
+ * @param int $pageId
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function redirectFromLink($pageId)
@@ -241,8 +298,8 @@ class PageController extends Controller
/**
* Show the deletion page for the specified page.
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @return \Illuminate\View\View
*/
public function showDelete($bookSlug, $pageSlug)
@@ -257,8 +314,8 @@ class PageController extends Controller
/**
* Show the deletion page for the specified page.
- * @param $bookSlug
- * @param $pageId
+ * @param string $bookSlug
+ * @param int $pageId
* @return \Illuminate\View\View
* @throws NotFoundException
*/
@@ -273,8 +330,8 @@ class PageController extends Controller
/**
* Remove the specified page from storage.
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @return Response
* @internal param int $id
*/
@@ -291,8 +348,8 @@ class PageController extends Controller
/**
* Remove the specified draft page from storage.
- * @param $bookSlug
- * @param $pageId
+ * @param string $bookSlug
+ * @param int $pageId
* @return Response
* @throws NotFoundException
*/
@@ -308,8 +365,8 @@ class PageController extends Controller
/**
* Shows the last revisions for this page.
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @return \Illuminate\View\View
*/
public function showRevisions($bookSlug, $pageSlug)
@@ -322,9 +379,9 @@ class PageController extends Controller
/**
* Shows a preview of a single revision
- * @param $bookSlug
- * @param $pageSlug
- * @param $revisionId
+ * @param string $bookSlug
+ * @param string $pageSlug
+ * @param int $revisionId
* @return \Illuminate\View\View
*/
public function showRevision($bookSlug, $pageSlug, $revisionId)
@@ -332,16 +389,48 @@ class PageController extends Controller
$book = $this->bookRepo->getBySlug($bookSlug);
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
$revision = $this->pageRepo->getRevisionById($revisionId);
+
$page->fill($revision->toArray());
$this->setPageTitle('Page Revision For ' . $page->getShortName());
- return view('pages/revision', ['page' => $page, 'book' => $book]);
+
+ return view('pages/revision', [
+ 'page' => $page,
+ 'book' => $book,
+ ]);
+ }
+
+ /**
+ * Shows the changes of a single revision
+ * @param string $bookSlug
+ * @param string $pageSlug
+ * @param int $revisionId
+ * @return \Illuminate\View\View
+ */
+ public function showRevisionChanges($bookSlug, $pageSlug, $revisionId)
+ {
+ $book = $this->bookRepo->getBySlug($bookSlug);
+ $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
+ $revision = $this->pageRepo->getRevisionById($revisionId);
+
+ $prev = $revision->getPrevious();
+ $prevContent = ($prev === null) ? '' : $prev->html;
+ $diff = (new Htmldiff)->diff($prevContent, $revision->html);
+
+ $page->fill($revision->toArray());
+ $this->setPageTitle('Page Revision For ' . $page->getShortName());
+
+ return view('pages/revision', [
+ 'page' => $page,
+ 'book' => $book,
+ 'diff' => $diff,
+ ]);
}
/**
* Restores a page using the content of the specified revision.
- * @param $bookSlug
- * @param $pageSlug
- * @param $revisionId
+ * @param string $bookSlug
+ * @param string $pageSlug
+ * @param int $revisionId
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function restoreRevision($bookSlug, $pageSlug, $revisionId)
@@ -357,8 +446,8 @@ class PageController extends Controller
/**
* Exports a page to pdf format using barryvdh/laravel-dompdf wrapper.
* https://github.com/barryvdh/laravel-dompdf
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @return \Illuminate\Http\Response
*/
public function exportPdf($bookSlug, $pageSlug)
@@ -374,8 +463,8 @@ class PageController extends Controller
/**
* Export a page to a self-contained HTML file.
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @return \Illuminate\Http\Response
*/
public function exportHtml($bookSlug, $pageSlug)
@@ -391,8 +480,8 @@ class PageController extends Controller
/**
* Export a page to a simple plaintext .txt file.
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @return \Illuminate\Http\Response
*/
public function exportPlainText($bookSlug, $pageSlug)
@@ -434,8 +523,8 @@ class PageController extends Controller
/**
* Show the Restrictions view.
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function showRestrict($bookSlug, $pageSlug)
@@ -452,8 +541,8 @@ class PageController extends Controller
/**
* Show the view to choose a new parent to move a page into.
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @return mixed
* @throws NotFoundException
*/
@@ -470,8 +559,8 @@ class PageController extends Controller
/**
* Does the action of moving the location of a page
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @param Request $request
* @return mixed
* @throws NotFoundException
@@ -513,8 +602,8 @@ class PageController extends Controller
/**
* Set the permissions for this page.
- * @param $bookSlug
- * @param $pageSlug
+ * @param string $bookSlug
+ * @param string $pageSlug
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php
index 61ce55fa9..65135eda3 100644
--- a/app/Http/Controllers/SettingController.php
+++ b/app/Http/Controllers/SettingController.php
@@ -17,10 +17,7 @@ class SettingController extends Controller
$this->setPageTitle('Settings');
// Get application version
- $version = false;
- if (function_exists('exec')) {
- $version = exec('git describe --always --tags ');
- }
+ $version = trim(file_get_contents(base_path('version')));
return view('settings/index', ['version' => $version]);
}
diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php
index 053d9ebd5..18ef1a671 100644
--- a/app/Http/Controllers/UserController.php
+++ b/app/Http/Controllers/UserController.php
@@ -3,6 +3,7 @@
namespace BookStack\Http\Controllers;
use BookStack\Activity;
+use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@@ -56,7 +57,7 @@ class UserController extends Controller
{
$this->checkPermission('users-manage');
$authMethod = config('auth.method');
- $roles = $this->userRepo->getAssignableRoles();
+ $roles = $this->userRepo->getAllRoles();
return view('users/create', ['authMethod' => $authMethod, 'roles' => $roles]);
}
@@ -100,9 +101,14 @@ class UserController extends Controller
// Get avatar from gravatar and save
if (!config('services.disable_services')) {
- $avatar = \Images::saveUserGravatar($user);
- $user->avatar()->associate($avatar);
- $user->save();
+ try {
+ $avatar = \Images::saveUserGravatar($user);
+ $user->avatar()->associate($avatar);
+ $user->save();
+ } catch (Exception $e) {
+ \Log::error('Failed to save user gravatar image');
+ }
+
}
return redirect('/settings/users');
@@ -120,12 +126,13 @@ class UserController extends Controller
return $this->currentUser->id == $id;
});
- $authMethod = config('auth.method');
-
$user = $this->user->findOrFail($id);
+
+ $authMethod = ($user->system_name) ? 'system' : config('auth.method');
+
$activeSocialDrivers = $socialAuthService->getActiveDrivers();
$this->setPageTitle('User Profile');
- $roles = $this->userRepo->getAssignableRoles();
+ $roles = $this->userRepo->getAllRoles();
return view('users/edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]);
}
@@ -180,7 +187,7 @@ class UserController extends Controller
/**
* Show the user delete page.
- * @param $id
+ * @param int $id
* @return \Illuminate\View\View
*/
public function delete($id)
@@ -213,6 +220,11 @@ class UserController extends Controller
return redirect($user->getEditUrl());
}
+ if ($user->system_name === 'public') {
+ session()->flash('error', 'You cannot delete the guest user');
+ return redirect($user->getEditUrl());
+ }
+
$this->userRepo->destroy($user);
session()->flash('success', 'User successfully removed');
diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php
index a1f2a581f..f1d95f5c0 100644
--- a/app/Http/Kernel.php
+++ b/app/Http/Kernel.php
@@ -9,15 +9,32 @@ class Kernel extends HttpKernel
/**
* The application's global HTTP middleware stack.
*
+ * These middleware are run during every request to your application.
+ *
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
- \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,
+ ];
+
+ /**
+ * The application's route middleware groups.
+ *
+ * @var array
+ */
+ protected $middlewareGroups = [
+ 'web' => [
+ \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,
+ \Illuminate\Routing\Middleware\SubstituteBindings::class,
+ ],
+ 'api' => [
+ 'throttle:60,1',
+ 'bindings',
+ ],
];
/**
@@ -26,6 +43,7 @@ class Kernel extends HttpKernel
* @var array
*/
protected $routeMiddleware = [
+ 'can' => \Illuminate\Auth\Middleware\Authorize::class,
'auth' => \BookStack\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \BookStack\Http\Middleware\RedirectIfAuthenticated::class,
diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php
index 372f30bf6..8461ed0ba 100644
--- a/app/Http/Middleware/Authenticate.php
+++ b/app/Http/Middleware/Authenticate.php
@@ -33,7 +33,7 @@ class Authenticate
public function handle($request, Closure $next)
{
if ($this->auth->check() && setting('registration-confirmation') && !$this->auth->user()->email_confirmed) {
- return redirect()->guest(baseUrl('/register/confirm/awaiting'));
+ return redirect(baseUrl('/register/confirm/awaiting'));
}
if ($this->auth->guest() && !setting('app-public')) {
diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php
index ab8ce4d3a..2b3c64695 100644
--- a/app/Http/Middleware/RedirectIfAuthenticated.php
+++ b/app/Http/Middleware/RedirectIfAuthenticated.php
@@ -34,7 +34,8 @@ class RedirectIfAuthenticated
*/
public function handle($request, Closure $next)
{
- if ($this->auth->check()) {
+ $requireConfirmation = setting('registration-confirmation');
+ if ($this->auth->check() && (!$requireConfirmation || ($requireConfirmation && $this->auth->user()->email_confirmed))) {
return redirect('/');
}
diff --git a/app/Jobs/Job.php b/app/Jobs/Job.php
deleted file mode 100644
index 780af746b..000000000
--- a/app/Jobs/Job.php
+++ /dev/null
@@ -1,21 +0,0 @@
-token = $token;
+ }
+
+ /**
+ * Get the notification's delivery channels.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function via($notifiable)
+ {
+ return ['mail'];
+ }
+
+ /**
+ * Get the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable)
+ {
+ $appName = ['appName' => setting('app-name')];
+ return (new MailMessage)
+ ->subject(trans('auth.email_confirm_subject', $appName))
+ ->greeting(trans('auth.email_confirm_greeting', $appName))
+ ->line(trans('auth.email_confirm_text'))
+ ->action(trans('auth.email_confirm_action'), baseUrl('/register/confirm/' . $this->token));
+ }
+
+}
diff --git a/app/Notifications/ResetPassword.php b/app/Notifications/ResetPassword.php
new file mode 100644
index 000000000..646030a10
--- /dev/null
+++ b/app/Notifications/ResetPassword.php
@@ -0,0 +1,50 @@
+token = $token;
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ return ['mail'];
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail()
+ {
+ return (new MailMessage)
+ ->line('You are receiving this email because we received a password reset request for your account.')
+ ->action('Reset Password', baseUrl('password/reset/' . $this->token))
+ ->line('If you did not request a password reset, no further action is required.');
+ }
+}
diff --git a/app/Page.php b/app/Page.php
index 1961a4f7f..3ee9e90f4 100644
--- a/app/Page.php
+++ b/app/Page.php
@@ -54,6 +54,15 @@ class Page extends Entity
return $this->hasMany(PageRevision::class)->where('type', '=', 'version')->orderBy('created_at', 'desc');
}
+ /**
+ * Get the attachments assigned to this page.
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
+ */
+ public function attachments()
+ {
+ return $this->hasMany(Attachment::class, 'uploaded_to')->orderBy('order', 'asc');
+ }
+
/**
* Get the url for this page.
* @param string|bool $path
@@ -63,13 +72,13 @@ class Page extends Entity
{
$bookSlug = $this->getAttribute('bookSlug') ? $this->getAttribute('bookSlug') : $this->book->slug;
$midText = $this->draft ? '/draft/' : '/page/';
- $idComponent = $this->draft ? $this->id : $this->slug;
+ $idComponent = $this->draft ? $this->id : urlencode($this->slug);
if ($path !== false) {
- return baseUrl('/books/' . $bookSlug . $midText . $idComponent . '/' . trim($path, '/'));
+ return baseUrl('/books/' . urlencode($bookSlug) . $midText . $idComponent . '/' . trim($path, '/'));
}
- return baseUrl('/books/' . $bookSlug . $midText . $idComponent);
+ return baseUrl('/books/' . urlencode($bookSlug) . $midText . $idComponent);
}
/**
diff --git a/app/PageRevision.php b/app/PageRevision.php
index 1ffd63dbd..ff469f0ed 100644
--- a/app/PageRevision.php
+++ b/app/PageRevision.php
@@ -25,11 +25,26 @@ class PageRevision extends Model
/**
* Get the url for this revision.
+ * @param null|string $path
* @return string
*/
- public function getUrl()
+ public function getUrl($path = null)
{
- return $this->page->getUrl() . '/revisions/' . $this->id;
+ $url = $this->page->getUrl() . '/revisions/' . $this->id;
+ if ($path) return $url . '/' . trim($path, '/');
+ return $url;
+ }
+
+ /**
+ * Get the previous revision for the same page if existing
+ * @return \BookStack\PageRevision|null
+ */
+ public function getPrevious()
+ {
+ if ($id = static::where('page_id', '=', $this->page_id)->where('id', '<', $this->id)->max('id')) {
+ return static::find($id);
+ }
+ return null;
}
}
diff --git a/app/Providers/BroadcastServiceProvider.php b/app/Providers/BroadcastServiceProvider.php
new file mode 100644
index 000000000..11e3cc6d2
--- /dev/null
+++ b/app/Providers/BroadcastServiceProvider.php
@@ -0,0 +1,26 @@
+id === (int) $userId;
+// });
+ }
+}
diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php
index f754b87a9..3802f20c0 100644
--- a/app/Providers/EventServiceProvider.php
+++ b/app/Providers/EventServiceProvider.php
@@ -21,13 +21,10 @@ class EventServiceProvider extends ServiceProvider
/**
* Register any other events for your application.
*
- * @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
- public function boot(DispatcherContract $events)
+ public function boot()
{
- parent::boot($events);
-
- //
+ parent::boot();
}
}
diff --git a/app/Providers/PaginationServiceProvider.php b/app/Providers/PaginationServiceProvider.php
index a0e97f70d..ec41267a4 100644
--- a/app/Providers/PaginationServiceProvider.php
+++ b/app/Providers/PaginationServiceProvider.php
@@ -1,11 +1,12 @@
app['view'];
+ });
+
Paginator::currentPathResolver(function () {
return baseUrl($this->app['request']->path());
});
diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php
index 2d9cd3b85..88ab23526 100644
--- a/app/Providers/RouteServiceProvider.php
+++ b/app/Providers/RouteServiceProvider.php
@@ -4,6 +4,7 @@ namespace BookStack\Providers;
use Illuminate\Routing\Router;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
+use Route;
class RouteServiceProvider extends ServiceProvider
{
@@ -19,26 +20,54 @@ class RouteServiceProvider extends ServiceProvider
/**
* Define your route model bindings, pattern filters, etc.
*
- * @param \Illuminate\Routing\Router $router
* @return void
*/
- public function boot(Router $router)
+ public function boot()
{
- //
-
- parent::boot($router);
+ parent::boot();
}
/**
* Define the routes for the application.
*
- * @param \Illuminate\Routing\Router $router
* @return void
*/
- public function map(Router $router)
+ public function map()
{
- $router->group(['namespace' => $this->namespace], function ($router) {
- require app_path('Http/routes.php');
+ $this->mapWebRoutes();
+// $this->mapApiRoutes();
+ }
+ /**
+ * Define the "web" routes for the application.
+ *
+ * These routes all receive session state, CSRF protection, etc.
+ *
+ * @return void
+ */
+ protected function mapWebRoutes()
+ {
+ Route::group([
+ 'middleware' => 'web',
+ 'namespace' => $this->namespace,
+ ], function ($router) {
+ require base_path('routes/web.php');
+ });
+ }
+ /**
+ * Define the "api" routes for the application.
+ *
+ * These routes are typically stateless.
+ *
+ * @return void
+ */
+ protected function mapApiRoutes()
+ {
+ Route::group([
+ 'middleware' => 'api',
+ 'namespace' => $this->namespace,
+ 'prefix' => 'api',
+ ], function ($router) {
+ require base_path('routes/api.php');
});
}
}
diff --git a/app/Repos/BookRepo.php b/app/Repos/BookRepo.php
index fdc4dd8d4..7bb91f472 100644
--- a/app/Repos/BookRepo.php
+++ b/app/Repos/BookRepo.php
@@ -132,8 +132,8 @@ class BookRepo extends EntityRepo
{
$book = $this->book->newInstance($input);
$book->slug = $this->findSuitableSlug($book->name);
- $book->created_by = auth()->user()->id;
- $book->updated_by = auth()->user()->id;
+ $book->created_by = user()->id;
+ $book->updated_by = user()->id;
$book->save();
$this->permissionService->buildJointPermissionsForEntity($book);
return $book;
@@ -147,9 +147,11 @@ class BookRepo extends EntityRepo
*/
public function updateFromInput(Book $book, $input)
{
+ if ($book->name !== $input['name']) {
+ $book->slug = $this->findSuitableSlug($input['name'], $book->id);
+ }
$book->fill($input);
- $book->slug = $this->findSuitableSlug($book->name, $book->id);
- $book->updated_by = auth()->user()->id;
+ $book->updated_by = user()->id;
$book->save();
$this->permissionService->buildJointPermissionsForEntity($book);
return $book;
@@ -208,8 +210,7 @@ class BookRepo extends EntityRepo
*/
public function findSuitableSlug($name, $currentId = false)
{
- $slug = Str::slug($name);
- if ($slug === "") $slug = substr(md5(rand(1, 500)), 0, 5);
+ $slug = $this->nameToSlug($name);
while ($this->doesSlugExist($slug, $currentId)) {
$slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
}
diff --git a/app/Repos/ChapterRepo.php b/app/Repos/ChapterRepo.php
index c12a9f0f2..4c13b9aaf 100644
--- a/app/Repos/ChapterRepo.php
+++ b/app/Repos/ChapterRepo.php
@@ -98,8 +98,8 @@ class ChapterRepo extends EntityRepo
{
$chapter = $this->chapter->newInstance($input);
$chapter->slug = $this->findSuitableSlug($chapter->name, $book->id);
- $chapter->created_by = auth()->user()->id;
- $chapter->updated_by = auth()->user()->id;
+ $chapter->created_by = user()->id;
+ $chapter->updated_by = user()->id;
$chapter = $book->chapters()->save($chapter);
$this->permissionService->buildJointPermissionsForEntity($chapter);
return $chapter;
@@ -150,8 +150,7 @@ class ChapterRepo extends EntityRepo
*/
public function findSuitableSlug($name, $bookId, $currentId = false)
{
- $slug = Str::slug($name);
- if ($slug === "") $slug = substr(md5(rand(1, 500)), 0, 5);
+ $slug = $this->nameToSlug($name);
while ($this->doesSlugExist($slug, $bookId, $currentId)) {
$slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
}
diff --git a/app/Repos/EntityRepo.php b/app/Repos/EntityRepo.php
index c94601738..7ecfb758c 100644
--- a/app/Repos/EntityRepo.php
+++ b/app/Repos/EntityRepo.php
@@ -132,9 +132,8 @@ class EntityRepo
*/
public function getUserDraftPages($count = 20, $page = 0)
{
- $user = auth()->user();
return $this->page->where('draft', '=', true)
- ->where('created_by', '=', $user->id)
+ ->where('created_by', '=', user()->id)
->orderBy('updated_at', 'desc')
->skip($count * $page)->take($count)->get();
}
@@ -270,6 +269,19 @@ class EntityRepo
$this->permissionService->buildJointPermissionsForEntities($collection);
}
+ /**
+ * Format a name as a url slug.
+ * @param $name
+ * @return string
+ */
+ protected function nameToSlug($name)
+ {
+ $slug = str_replace(' ', '-', strtolower($name));
+ $slug = preg_replace('/[\+\/\\\?\@\}\{\.\,\=\[\]\#\&\!\*\'\;\:\$\%]/', '', $slug);
+ if ($slug === "") $slug = substr(md5(rand(1, 500)), 0, 5);
+ return $slug;
+ }
+
}
diff --git a/app/Repos/ImageRepo.php b/app/Repos/ImageRepo.php
index 435b8bbd7..8ddde7b0f 100644
--- a/app/Repos/ImageRepo.php
+++ b/app/Repos/ImageRepo.php
@@ -5,6 +5,7 @@ use BookStack\Image;
use BookStack\Page;
use BookStack\Services\ImageService;
use BookStack\Services\PermissionService;
+use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Setting;
use Symfony\Component\HttpFoundation\File\UploadedFile;
@@ -191,7 +192,12 @@ class ImageRepo
*/
public function getThumbnail(Image $image, $width = 220, $height = 220, $keepRatio = false)
{
- return $this->imageService->getThumbnail($image, $width, $height, $keepRatio);
+ try {
+ return $this->imageService->getThumbnail($image, $width, $height, $keepRatio);
+ } catch (FileNotFoundException $exception) {
+ $image->delete();
+ return [];
+ }
}
diff --git a/app/Repos/PageRepo.php b/app/Repos/PageRepo.php
index 235246f82..e6d713f77 100644
--- a/app/Repos/PageRepo.php
+++ b/app/Repos/PageRepo.php
@@ -5,8 +5,10 @@ use BookStack\Book;
use BookStack\Chapter;
use BookStack\Entity;
use BookStack\Exceptions\NotFoundException;
+use BookStack\Services\AttachmentService;
use Carbon\Carbon;
use DOMDocument;
+use DOMXPath;
use Illuminate\Support\Str;
use BookStack\Page;
use BookStack\PageRevision;
@@ -47,7 +49,7 @@ class PageRepo extends EntityRepo
* Get a page via a specific ID.
* @param $id
* @param bool $allowDrafts
- * @return mixed
+ * @return Page
*/
public function getById($id, $allowDrafts = false)
{
@@ -58,7 +60,7 @@ class PageRepo extends EntityRepo
* Get a page identified by the given slug.
* @param $slug
* @param $bookId
- * @return mixed
+ * @return Page
* @throws NotFoundException
*/
public function getBySlug($slug, $bookId)
@@ -110,31 +112,6 @@ class PageRepo extends EntityRepo
return $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId)->count();
}
- /**
- * Save a new page into the system.
- * Input validation must be done beforehand.
- * @param array $input
- * @param Book $book
- * @param int $chapterId
- * @return Page
- */
- public function saveNew(array $input, Book $book, $chapterId = null)
- {
- $page = $this->newFromInput($input);
- $page->slug = $this->findSuitableSlug($page->name, $book->id);
-
- if ($chapterId) $page->chapter_id = $chapterId;
-
- $page->html = $this->formatHtml($input['html']);
- $page->text = strip_tags($page->html);
- $page->created_by = auth()->user()->id;
- $page->updated_by = auth()->user()->id;
-
- $book->pages()->save($page);
- return $page;
- }
-
-
/**
* Publish a draft page to make it a normal page.
* Sets the slug and updates the content.
@@ -172,8 +149,8 @@ class PageRepo extends EntityRepo
{
$page = $this->page->newInstance();
$page->name = 'New Page';
- $page->created_by = auth()->user()->id;
- $page->updated_by = auth()->user()->id;
+ $page->created_by = user()->id;
+ $page->updated_by = user()->id;
$page->draft = true;
if ($chapter) $page->chapter_id = $chapter->id;
@@ -183,6 +160,35 @@ class PageRepo extends EntityRepo
return $page;
}
+ /**
+ * Parse te headers on the page to get a navigation menu
+ * @param Page $page
+ * @return array
+ */
+ public function getPageNav(Page $page)
+ {
+ if ($page->html == '') return null;
+ libxml_use_internal_errors(true);
+ $doc = new DOMDocument();
+ $doc->loadHTML(mb_convert_encoding($page->html, 'HTML-ENTITIES', 'UTF-8'));
+ $xPath = new DOMXPath($doc);
+ $headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6");
+
+ if (is_null($headers)) return null;
+
+ $tree = [];
+ foreach ($headers as $header) {
+ $text = $header->nodeValue;
+ $tree[] = [
+ 'nodeName' => strtolower($header->nodeName),
+ 'level' => intval(str_replace('h', '', $header->nodeName)),
+ 'link' => '#' . $header->getAttribute('id'),
+ 'text' => strlen($text) > 30 ? substr($text, 0, 27) . '...' : $text
+ ];
+ }
+ return $tree;
+ }
+
/**
* Formats a page's html to be tagged correctly
* within the system.
@@ -325,7 +331,7 @@ class PageRepo extends EntityRepo
}
// Update with new details
- $userId = auth()->user()->id;
+ $userId = user()->id;
$page->fill($input);
$page->html = $this->formatHtml($input['html']);
$page->text = strip_tags($page->html);
@@ -358,7 +364,7 @@ class PageRepo extends EntityRepo
$page->fill($revision->toArray());
$page->slug = $this->findSuitableSlug($page->name, $book->id, $page->id);
$page->text = strip_tags($page->html);
- $page->updated_by = auth()->user()->id;
+ $page->updated_by = user()->id;
$page->save();
return $page;
}
@@ -371,21 +377,23 @@ class PageRepo extends EntityRepo
*/
public function saveRevision(Page $page, $summary = null)
{
- $revision = $this->pageRevision->fill($page->toArray());
+ $revision = $this->pageRevision->newInstance($page->toArray());
if (setting('app-editor') !== 'markdown') $revision->markdown = '';
$revision->page_id = $page->id;
$revision->slug = $page->slug;
$revision->book_slug = $page->book->slug;
- $revision->created_by = auth()->user()->id;
+ $revision->created_by = user()->id;
$revision->created_at = $page->updated_at;
$revision->type = 'version';
$revision->summary = $summary;
$revision->save();
+
// Clear old revisions
if ($this->pageRevision->where('page_id', '=', $page->id)->count() > 50) {
$this->pageRevision->where('page_id', '=', $page->id)
->orderBy('created_at', 'desc')->skip(50)->take(5)->delete();
}
+
return $revision;
}
@@ -397,7 +405,7 @@ class PageRepo extends EntityRepo
*/
public function saveUpdateDraft(Page $page, $data = [])
{
- $userId = auth()->user()->id;
+ $userId = user()->id;
$drafts = $this->userUpdateDraftsQuery($page, $userId)->get();
if ($drafts->count() > 0) {
@@ -528,7 +536,7 @@ class PageRepo extends EntityRepo
$query = $this->pageRevision->where('type', '=', 'update_draft')
->where('page_id', '=', $page->id)
->where('updated_at', '>', $page->updated_at)
- ->where('created_by', '!=', auth()->user()->id)
+ ->where('created_by', '!=', user()->id)
->with('createdBy');
if ($minRange !== null) {
@@ -541,7 +549,7 @@ class PageRepo extends EntityRepo
/**
* Gets a single revision via it's id.
* @param $id
- * @return mixed
+ * @return PageRevision
*/
public function getRevisionById($id)
{
@@ -606,8 +614,7 @@ class PageRepo extends EntityRepo
*/
public function findSuitableSlug($name, $bookId, $currentId = false)
{
- $slug = Str::slug($name);
- if ($slug === "") $slug = substr(md5(rand(1, 500)), 0, 5);
+ $slug = $this->nameToSlug($name);
while ($this->doesSlugExist($slug, $bookId, $currentId)) {
$slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
}
@@ -626,12 +633,20 @@ class PageRepo extends EntityRepo
$page->revisions()->delete();
$page->permissions()->delete();
$this->permissionService->deleteJointPermissionsForEntity($page);
+
+ // Delete AttachedFiles
+ $attachmentService = app(AttachmentService::class);
+ foreach ($page->attachments as $attachment) {
+ $attachmentService->deleteFile($attachment);
+ }
+
$page->delete();
}
/**
* Get the latest pages added to the system.
* @param $count
+ * @return mixed
*/
public function getRecentlyCreatedPaginated($count = 20)
{
@@ -641,6 +656,7 @@ class PageRepo extends EntityRepo
/**
* Get the latest pages added to the system.
* @param $count
+ * @return mixed
*/
public function getRecentlyUpdatedPaginated($count = 20)
{
diff --git a/app/Repos/PermissionsRepo.php b/app/Repos/PermissionsRepo.php
index e026d83e8..24497c911 100644
--- a/app/Repos/PermissionsRepo.php
+++ b/app/Repos/PermissionsRepo.php
@@ -35,7 +35,7 @@ class PermissionsRepo
*/
public function getAllRoles()
{
- return $this->role->where('hidden', '=', false)->get();
+ return $this->role->all();
}
/**
@@ -45,7 +45,7 @@ class PermissionsRepo
*/
public function getAllRolesExcept(Role $role)
{
- return $this->role->where('id', '!=', $role->id)->where('hidden', '=', false)->get();
+ return $this->role->where('id', '!=', $role->id)->get();
}
/**
@@ -90,8 +90,6 @@ class PermissionsRepo
{
$role = $this->role->findOrFail($roleId);
- if ($role->hidden) throw new PermissionsException("Cannot update a hidden role");
-
$permissions = isset($roleData['permissions']) ? array_keys($roleData['permissions']) : [];
$this->assignRolePermissions($role, $permissions);
diff --git a/app/Repos/UserRepo.php b/app/Repos/UserRepo.php
index 0926f6304..ab3716fca 100644
--- a/app/Repos/UserRepo.php
+++ b/app/Repos/UserRepo.php
@@ -2,6 +2,7 @@
use BookStack\Role;
use BookStack\User;
+use Exception;
use Setting;
class UserRepo
@@ -84,9 +85,14 @@ class UserRepo
// Get avatar from gravatar and save
if (!config('services.disable_services')) {
- $avatar = \Images::saveUserGravatar($user);
- $user->avatar()->associate($avatar);
- $user->save();
+ try {
+ $avatar = \Images::saveUserGravatar($user);
+ $user->avatar()->associate($avatar);
+ $user->save();
+ } catch (Exception $e) {
+ $user->save();
+ \Log::error('Failed to save user gravatar image');
+ }
}
return $user;
@@ -193,9 +199,9 @@ class UserRepo
* Get the roles in the system that are assignable to a user.
* @return mixed
*/
- public function getAssignableRoles()
+ public function getAllRoles()
{
- return $this->role->visible();
+ return $this->role->all();
}
/**
@@ -205,7 +211,7 @@ class UserRepo
*/
public function getRestrictableRoles()
{
- return $this->role->where('hidden', '=', false)->where('system_name', '=', '')->get();
+ return $this->role->where('system_name', '!=', 'admin')->get();
}
}
\ No newline at end of file
diff --git a/app/Role.php b/app/Role.php
index 8d0a79e75..bf9685ee2 100644
--- a/app/Role.php
+++ b/app/Role.php
@@ -66,7 +66,7 @@ class Role extends Model
/**
* Get the role object for the specified role.
* @param $roleName
- * @return mixed
+ * @return Role
*/
public static function getRole($roleName)
{
@@ -76,7 +76,7 @@ class Role extends Model
/**
* Get the role object for the specified system role.
* @param $roleName
- * @return mixed
+ * @return Role
*/
public static function getSystemRole($roleName)
{
diff --git a/app/Services/ActivityService.php b/app/Services/ActivityService.php
index f6fea33a1..e41036238 100644
--- a/app/Services/ActivityService.php
+++ b/app/Services/ActivityService.php
@@ -19,7 +19,7 @@ class ActivityService
{
$this->activity = $activity;
$this->permissionService = $permissionService;
- $this->user = auth()->user();
+ $this->user = user();
}
/**
diff --git a/app/Services/AttachmentService.php b/app/Services/AttachmentService.php
new file mode 100644
index 000000000..e0ee3a04d
--- /dev/null
+++ b/app/Services/AttachmentService.php
@@ -0,0 +1,201 @@
+getStorageBasePath() . $attachment->path;
+ return $this->getStorage()->get($attachmentPath);
+ }
+
+ /**
+ * Store a new attachment upon user upload.
+ * @param UploadedFile $uploadedFile
+ * @param int $page_id
+ * @return Attachment
+ * @throws FileUploadException
+ */
+ public function saveNewUpload(UploadedFile $uploadedFile, $page_id)
+ {
+ $attachmentName = $uploadedFile->getClientOriginalName();
+ $attachmentPath = $this->putFileInStorage($attachmentName, $uploadedFile);
+ $largestExistingOrder = Attachment::where('uploaded_to', '=', $page_id)->max('order');
+
+ $attachment = Attachment::forceCreate([
+ 'name' => $attachmentName,
+ 'path' => $attachmentPath,
+ 'extension' => $uploadedFile->getClientOriginalExtension(),
+ 'uploaded_to' => $page_id,
+ 'created_by' => user()->id,
+ 'updated_by' => user()->id,
+ 'order' => $largestExistingOrder + 1
+ ]);
+
+ return $attachment;
+ }
+
+ /**
+ * Store a upload, saving to a file and deleting any existing uploads
+ * attached to that file.
+ * @param UploadedFile $uploadedFile
+ * @param Attachment $attachment
+ * @return Attachment
+ * @throws FileUploadException
+ */
+ public function saveUpdatedUpload(UploadedFile $uploadedFile, Attachment $attachment)
+ {
+ if (!$attachment->external) {
+ $this->deleteFileInStorage($attachment);
+ }
+
+ $attachmentName = $uploadedFile->getClientOriginalName();
+ $attachmentPath = $this->putFileInStorage($attachmentName, $uploadedFile);
+
+ $attachment->name = $attachmentName;
+ $attachment->path = $attachmentPath;
+ $attachment->external = false;
+ $attachment->extension = $uploadedFile->getClientOriginalExtension();
+ $attachment->save();
+ return $attachment;
+ }
+
+ /**
+ * Save a new File attachment from a given link and name.
+ * @param string $name
+ * @param string $link
+ * @param int $page_id
+ * @return Attachment
+ */
+ public function saveNewFromLink($name, $link, $page_id)
+ {
+ $largestExistingOrder = Attachment::where('uploaded_to', '=', $page_id)->max('order');
+ return Attachment::forceCreate([
+ 'name' => $name,
+ 'path' => $link,
+ 'external' => true,
+ 'extension' => '',
+ 'uploaded_to' => $page_id,
+ 'created_by' => user()->id,
+ 'updated_by' => user()->id,
+ 'order' => $largestExistingOrder + 1
+ ]);
+ }
+
+ /**
+ * 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
+ * @param $pageId
+ */
+ public function updateFileOrderWithinPage($attachmentList, $pageId)
+ {
+ foreach ($attachmentList as $index => $attachment) {
+ Attachment::where('uploaded_to', '=', $pageId)->where('id', '=', $attachment['id'])->update(['order' => $index]);
+ }
+ }
+
+
+ /**
+ * Update the details of a file.
+ * @param Attachment $attachment
+ * @param $requestData
+ * @return Attachment
+ */
+ public function updateFile(Attachment $attachment, $requestData)
+ {
+ $attachment->name = $requestData['name'];
+ if (isset($requestData['link']) && trim($requestData['link']) !== '') {
+ $attachment->path = $requestData['link'];
+ if (!$attachment->external) {
+ $this->deleteFileInStorage($attachment);
+ $attachment->external = true;
+ }
+ }
+ $attachment->save();
+ return $attachment;
+ }
+
+ /**
+ * Delete a File from the database and storage.
+ * @param Attachment $attachment
+ */
+ public function deleteFile(Attachment $attachment)
+ {
+ if ($attachment->external) {
+ $attachment->delete();
+ return;
+ }
+
+ $this->deleteFileInStorage($attachment);
+ $attachment->delete();
+ }
+
+ /**
+ * Delete a file from the filesystem it sits on.
+ * Cleans any empty leftover folders.
+ * @param Attachment $attachment
+ */
+ protected function deleteFileInStorage(Attachment $attachment)
+ {
+ $storedFilePath = $this->getStorageBasePath() . $attachment->path;
+ $storage = $this->getStorage();
+ $dirPath = dirname($storedFilePath);
+
+ $storage->delete($storedFilePath);
+ if (count($storage->allFiles($dirPath)) === 0) {
+ $storage->deleteDirectory($dirPath);
+ }
+ }
+
+ /**
+ * Store a file in storage with the given filename
+ * @param $attachmentName
+ * @param UploadedFile $uploadedFile
+ * @return string
+ * @throws FileUploadException
+ */
+ protected function putFileInStorage($attachmentName, UploadedFile $uploadedFile)
+ {
+ $attachmentData = file_get_contents($uploadedFile->getRealPath());
+
+ $storage = $this->getStorage();
+ $attachmentBasePath = 'uploads/files/' . Date('Y-m-M') . '/';
+ $storageBasePath = $this->getStorageBasePath() . $attachmentBasePath;
+
+ $uploadFileName = $attachmentName;
+ while ($storage->exists($storageBasePath . $uploadFileName)) {
+ $uploadFileName = str_random(3) . $uploadFileName;
+ }
+
+ $attachmentPath = $attachmentBasePath . $uploadFileName;
+ $attachmentStoragePath = $this->getStorageBasePath() . $attachmentPath;
+
+ try {
+ $storage->put($attachmentStoragePath, $attachmentData);
+ } catch (Exception $e) {
+ throw new FileUploadException('File path ' . $attachmentStoragePath . ' could not be uploaded to. Ensure it is writable to the server.');
+ }
+ return $attachmentPath;
+ }
+
+}
\ No newline at end of file
diff --git a/app/Services/EmailConfirmationService.php b/app/Services/EmailConfirmationService.php
index c3096c654..d4ec1e976 100644
--- a/app/Services/EmailConfirmationService.php
+++ b/app/Services/EmailConfirmationService.php
@@ -1,30 +1,27 @@
mailer = $mailer;
- $this->emailConfirmation = $emailConfirmation;
+ $this->db = $db;
+ $this->users = $users;
}
/**
@@ -38,16 +35,28 @@ class EmailConfirmationService
if ($user->email_confirmed) {
throw new ConfirmationEmailException('Email has already been confirmed, Try logging in.', '/login');
}
+
$this->deleteConfirmationsByUser($user);
+ $token = $this->createEmailConfirmation($user);
+
+ $user->notify(new ConfirmEmail($token));
+ }
+
+ /**
+ * Creates a new email confirmation in the database and returns the token.
+ * @param User $user
+ * @return string
+ */
+ public function createEmailConfirmation(User $user)
+ {
$token = $this->getToken();
- $this->emailConfirmation->create([
+ $this->db->table('email_confirmations')->insert([
'user_id' => $user->id,
- 'token' => $token,
+ 'token' => $token,
+ 'created_at' => Carbon::now(),
+ 'updated_at' => Carbon::now()
]);
- $this->mailer->send('emails/email-confirmation', ['token' => $token], function (Message $message) use ($user) {
- $appName = setting('app-name', 'BookStack');
- $message->to($user->email, $user->name)->subject('Confirm your email on ' . $appName . '.');
- });
+ return $token;
}
/**
@@ -59,22 +68,24 @@ class EmailConfirmationService
*/
public function getEmailConfirmationFromToken($token)
{
- $emailConfirmation = $this->emailConfirmation->where('token', '=', $token)->first();
- // If not found
+ $emailConfirmation = $this->db->table('email_confirmations')->where('token', '=', $token)->first();
+
+ // If not found show error
if ($emailConfirmation === null) {
throw new UserRegistrationException('This confirmation token is not valid or has already been used, Please try registering again.', '/register');
}
// If more than a day old
- if (Carbon::now()->subDay()->gt($emailConfirmation->created_at)) {
- $this->sendConfirmation($emailConfirmation->user);
+ if (Carbon::now()->subDay()->gt(new Carbon($emailConfirmation->created_at))) {
+ $user = $this->users->getById($emailConfirmation->user_id);
+ $this->sendConfirmation($user);
throw new UserRegistrationException('The confirmation token has expired, A new confirmation email has been sent.', '/register/confirm');
}
+ $emailConfirmation->user = $this->users->getById($emailConfirmation->user_id);
return $emailConfirmation;
}
-
/**
* Delete all email confirmations that belong to a user.
* @param User $user
@@ -82,7 +93,7 @@ class EmailConfirmationService
*/
public function deleteConfirmationsByUser(User $user)
{
- return $this->emailConfirmation->where('user_id', '=', $user->id)->delete();
+ return $this->db->table('email_confirmations')->where('user_id', '=', $user->id)->delete();
}
/**
@@ -92,7 +103,7 @@ class EmailConfirmationService
protected function getToken()
{
$token = str_random(24);
- while ($this->emailConfirmation->where('token', '=', $token)->exists()) {
+ while ($this->db->table('email_confirmations')->where('token', '=', $token)->exists()) {
$token = str_random(25);
}
return $token;
diff --git a/app/Services/ImageService.php b/app/Services/ImageService.php
index 4401cb230..dfe2cf453 100644
--- a/app/Services/ImageService.php
+++ b/app/Services/ImageService.php
@@ -9,20 +9,13 @@ use Intervention\Image\ImageManager;
use Illuminate\Contracts\Filesystem\Factory as FileSystem;
use Illuminate\Contracts\Filesystem\Filesystem as FileSystemInstance;
use Illuminate\Contracts\Cache\Repository as Cache;
-use Setting;
use Symfony\Component\HttpFoundation\File\UploadedFile;
-class ImageService
+class ImageService extends UploadService
{
protected $imageTool;
- protected $fileSystem;
protected $cache;
-
- /**
- * @var FileSystemInstance
- */
- protected $storageInstance;
protected $storageUrl;
/**
@@ -34,8 +27,8 @@ class ImageService
public function __construct(ImageManager $imageTool, FileSystem $fileSystem, Cache $cache)
{
$this->imageTool = $imageTool;
- $this->fileSystem = $fileSystem;
$this->cache = $cache;
+ parent::__construct($fileSystem);
}
/**
@@ -88,6 +81,9 @@ class ImageService
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;
}
@@ -100,6 +96,8 @@ class ImageService
throw new ImageUploadException('Image Path ' . $fullPath . ' is not writable by the server.');
}
+ if ($this->isLocal()) $fullPath = str_replace_first('/public', '', $fullPath);
+
$imageDetails = [
'name' => $imageName,
'path' => $fullPath,
@@ -108,8 +106,8 @@ class ImageService
'uploaded_to' => $uploadedTo
];
- if (auth()->user() && auth()->user()->id !== 0) {
- $userId = auth()->user()->id;
+ if (user()->id !== 0) {
+ $userId = user()->id;
$imageDetails['created_by'] = $userId;
$imageDetails['updated_by'] = $userId;
}
@@ -119,6 +117,16 @@ class ImageService
return $image;
}
+ /**
+ * Get the storage path, Dependant of storage type.
+ * @param Image $image
+ * @return mixed|string
+ */
+ protected function getPath(Image $image)
+ {
+ return ($this->isLocal()) ? ('public/' . $image->path) : $image->path;
+ }
+
/**
* Get the thumbnail for an image.
* If $keepRatio is true only the width will be used.
@@ -135,7 +143,8 @@ class ImageService
public function getThumbnail(Image $image, $width = 220, $height = 220, $keepRatio = false)
{
$thumbDirName = '/' . ($keepRatio ? 'scaled-' : 'thumbs-') . $width . '-' . $height . '/';
- $thumbFilePath = dirname($image->path) . $thumbDirName . basename($image->path);
+ $imagePath = $this->getPath($image);
+ $thumbFilePath = dirname($imagePath) . $thumbDirName . basename($imagePath);
if ($this->cache->has('images-' . $image->id . '-' . $thumbFilePath) && $this->cache->get('images-' . $thumbFilePath)) {
return $this->getPublicUrl($thumbFilePath);
@@ -148,7 +157,7 @@ class ImageService
}
try {
- $thumb = $this->imageTool->make($storage->get($image->path));
+ $thumb = $this->imageTool->make($storage->get($imagePath));
} catch (Exception $e) {
if ($e instanceof \ErrorException || $e instanceof NotSupportedException) {
throw new ImageUploadException('The server cannot create thumbnails. Please check you have the GD PHP extension installed.');
@@ -183,8 +192,8 @@ class ImageService
{
$storage = $this->getStorage();
- $imageFolder = dirname($image->path);
- $imageFileName = basename($image->path);
+ $imageFolder = dirname($this->getPath($image));
+ $imageFileName = basename($this->getPath($image));
$allImages = collect($storage->allFiles($imageFolder));
$imagesToDelete = $allImages->filter(function ($imagePath) use ($imageFileName) {
@@ -213,7 +222,7 @@ class ImageService
public function saveUserGravatar(User $user, $size = 500)
{
$emailHash = md5(strtolower(trim($user->email)));
- $url = 'http://www.gravatar.com/avatar/' . $emailHash . '?s=' . $size . '&d=identicon';
+ $url = 'https://www.gravatar.com/avatar/' . $emailHash . '?s=' . $size . '&d=identicon';
$imageName = str_replace(' ', '-', $user->name . '-gravatar.png');
$image = $this->saveNewFromUrl($url, 'user', $imageName);
$image->created_by = $user->id;
@@ -222,35 +231,9 @@ class ImageService
return $image;
}
- /**
- * Get the storage that will be used for storing images.
- * @return FileSystemInstance
- */
- private function getStorage()
- {
- if ($this->storageInstance !== null) return $this->storageInstance;
-
- $storageType = config('filesystems.default');
- $this->storageInstance = $this->fileSystem->disk($storageType);
-
- return $this->storageInstance;
- }
-
- /**
- * Check whether or not a folder is empty.
- * @param $path
- * @return int
- */
- private function isFolderEmpty($path)
- {
- $files = $this->getStorage()->files($path);
- $folders = $this->getStorage()->directories($path);
- return count($files) === 0 && count($folders) === 0;
- }
-
/**
* Gets a public facing url for an image by checking relevant environment variables.
- * @param $filePath
+ * @param string $filePath
* @return string
*/
private function getPublicUrl($filePath)
@@ -273,6 +256,8 @@ class ImageService
$this->storageUrl = $storageUrl;
}
+ if ($this->isLocal()) $filePath = str_replace_first('public/', '', $filePath);
+
return ($this->storageUrl == false ? rtrim(baseUrl(''), '/') : rtrim($this->storageUrl, '/')) . $filePath;
}
diff --git a/app/Services/PermissionService.php b/app/Services/PermissionService.php
index cee074cd7..bb78f0b0a 100644
--- a/app/Services/PermissionService.php
+++ b/app/Services/PermissionService.php
@@ -9,14 +9,15 @@ use BookStack\Page;
use BookStack\Role;
use BookStack\User;
use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\Log;
class PermissionService
{
- protected $userRoles;
- protected $isAdmin;
protected $currentAction;
- protected $currentUser;
+ protected $isAdminUser;
+ protected $userRoles = false;
+ protected $currentUserModel = false;
public $book;
public $chapter;
@@ -37,12 +38,6 @@ class PermissionService
*/
public function __construct(JointPermission $jointPermission, Book $book, Chapter $chapter, Page $page, Role $role)
{
- $this->currentUser = auth()->user();
- $userSet = $this->currentUser !== null;
- $this->userRoles = false;
- $this->isAdmin = $userSet ? $this->currentUser->hasRole('admin') : false;
- if (!$userSet) $this->currentUser = new User();
-
$this->jointPermission = $jointPermission;
$this->role = $role;
$this->book = $book;
@@ -117,7 +112,7 @@ class PermissionService
}
- foreach ($this->currentUser->roles as $role) {
+ foreach ($this->currentUser()->roles as $role) {
$roles[] = $role->id;
}
return $roles;
@@ -389,7 +384,11 @@ class PermissionService
*/
public function checkOwnableUserAccess(Ownable $ownable, $permission)
{
- if ($this->isAdmin) return true;
+ if ($this->isAdmin()) {
+ $this->clean();
+ return true;
+ }
+
$explodedPermission = explode('-', $permission);
$baseQuery = $ownable->where('id', '=', $ownable->id);
@@ -400,10 +399,10 @@ class PermissionService
// Handle non entity specific jointPermissions
if (in_array($explodedPermission[0], $nonJointPermissions)) {
- $allPermission = $this->currentUser && $this->currentUser->can($permission . '-all');
- $ownPermission = $this->currentUser && $this->currentUser->can($permission . '-own');
+ $allPermission = $this->currentUser() && $this->currentUser()->can($permission . '-all');
+ $ownPermission = $this->currentUser() && $this->currentUser()->can($permission . '-own');
$this->currentAction = 'view';
- $isOwner = $this->currentUser && $this->currentUser->id === $ownable->created_by;
+ $isOwner = $this->currentUser() && $this->currentUser()->id === $ownable->created_by;
return ($allPermission || ($isOwner && $ownPermission));
}
@@ -413,7 +412,9 @@ class PermissionService
}
- return $this->entityRestrictionQuery($baseQuery)->count() > 0;
+ $q = $this->entityRestrictionQuery($baseQuery)->count() > 0;
+ $this->clean();
+ return $q;
}
/**
@@ -443,7 +444,7 @@ class PermissionService
*/
protected function entityRestrictionQuery($query)
{
- return $query->where(function ($parentQuery) {
+ $q = $query->where(function ($parentQuery) {
$parentQuery->whereHas('jointPermissions', function ($permissionQuery) {
$permissionQuery->whereIn('role_id', $this->getRoles())
->where('action', '=', $this->currentAction)
@@ -451,11 +452,13 @@ class PermissionService
$query->where('has_permission', '=', true)
->orWhere(function ($query) {
$query->where('has_permission_own', '=', true)
- ->where('created_by', '=', $this->currentUser->id);
+ ->where('created_by', '=', $this->currentUser()->id);
});
});
});
});
+ $this->clean();
+ return $q;
}
/**
@@ -469,9 +472,9 @@ class PermissionService
// Prevent drafts being visible to others.
$query = $query->where(function ($query) {
$query->where('draft', '=', false);
- if ($this->currentUser) {
+ if ($this->currentUser()) {
$query->orWhere(function ($query) {
- $query->where('draft', '=', true)->where('created_by', '=', $this->currentUser->id);
+ $query->where('draft', '=', true)->where('created_by', '=', $this->currentUser()->id);
});
}
});
@@ -509,7 +512,10 @@ class PermissionService
*/
public function enforceEntityRestrictions($query, $action = 'view')
{
- if ($this->isAdmin) return $query;
+ if ($this->isAdmin()) {
+ $this->clean();
+ return $query;
+ }
$this->currentAction = $action;
return $this->entityRestrictionQuery($query);
}
@@ -524,11 +530,15 @@ class PermissionService
*/
public function filterRestrictedEntityRelations($query, $tableName, $entityIdColumn, $entityTypeColumn)
{
- if ($this->isAdmin) return $query;
+ if ($this->isAdmin()) {
+ $this->clean();
+ return $query;
+ }
+
$this->currentAction = 'view';
$tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn, 'entityTypeColumn' => $entityTypeColumn];
- return $query->where(function ($query) use ($tableDetails) {
+ $q = $query->where(function ($query) use ($tableDetails) {
$query->whereExists(function ($permissionQuery) use (&$tableDetails) {
$permissionQuery->select('id')->from('joint_permissions')
->whereRaw('joint_permissions.entity_id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
@@ -538,12 +548,12 @@ class PermissionService
->where(function ($query) {
$query->where('has_permission', '=', true)->orWhere(function ($query) {
$query->where('has_permission_own', '=', true)
- ->where('created_by', '=', $this->currentUser->id);
+ ->where('created_by', '=', $this->currentUser()->id);
});
});
});
});
-
+ return $q;
}
/**
@@ -555,11 +565,15 @@ class PermissionService
*/
public function filterRelatedPages($query, $tableName, $entityIdColumn)
{
- if ($this->isAdmin) return $query;
+ if ($this->isAdmin()) {
+ $this->clean();
+ return $query;
+ }
+
$this->currentAction = 'view';
$tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn];
- return $query->where(function ($query) use ($tableDetails) {
+ $q = $query->where(function ($query) use ($tableDetails) {
$query->where(function ($query) use (&$tableDetails) {
$query->whereExists(function ($permissionQuery) use (&$tableDetails) {
$permissionQuery->select('id')->from('joint_permissions')
@@ -570,12 +584,50 @@ class PermissionService
->where(function ($query) {
$query->where('has_permission', '=', true)->orWhere(function ($query) {
$query->where('has_permission_own', '=', true)
- ->where('created_by', '=', $this->currentUser->id);
+ ->where('created_by', '=', $this->currentUser()->id);
});
});
});
})->orWhere($tableDetails['entityIdColumn'], '=', 0);
});
+ $this->clean();
+ return $q;
+ }
+
+ /**
+ * Check if the current user is an admin.
+ * @return bool
+ */
+ private function isAdmin()
+ {
+ if ($this->isAdminUser === null) {
+ $this->isAdminUser = ($this->currentUser()->id !== null) ? $this->currentUser()->hasRole('admin') : false;
+ }
+
+ return $this->isAdminUser;
+ }
+
+ /**
+ * Get the current user
+ * @return User
+ */
+ private function currentUser()
+ {
+ if ($this->currentUserModel === false) {
+ $this->currentUserModel = user();
+ }
+
+ return $this->currentUserModel;
+ }
+
+ /**
+ * Clean the cached user elements.
+ */
+ private function clean()
+ {
+ $this->currentUserModel = false;
+ $this->userRoles = false;
+ $this->isAdminUser = null;
}
}
\ No newline at end of file
diff --git a/app/Services/SocialAuthService.php b/app/Services/SocialAuthService.php
index b28a97ea4..d76a7231b 100644
--- a/app/Services/SocialAuthService.php
+++ b/app/Services/SocialAuthService.php
@@ -100,7 +100,7 @@ class SocialAuthService
$socialAccount = $this->socialAccount->where('driver_id', '=', $socialId)->first();
$user = $this->userRepo->getByEmail($socialUser->getEmail());
$isLoggedIn = auth()->check();
- $currentUser = auth()->user();
+ $currentUser = user();
// When a user is not logged in and a matching SocialAccount exists,
// Simply log the user into the application.
@@ -214,9 +214,9 @@ class SocialAuthService
public function detachSocialAccount($socialDriver)
{
session();
- auth()->user()->socialAccounts()->where('driver', '=', $socialDriver)->delete();
+ user()->socialAccounts()->where('driver', '=', $socialDriver)->delete();
session()->flash('success', title_case($socialDriver) . ' account successfully detached');
- return redirect(auth()->user()->getEditUrl());
+ return redirect(user()->getEditUrl());
}
}
\ No newline at end of file
diff --git a/app/Services/UploadService.php b/app/Services/UploadService.php
new file mode 100644
index 000000000..44d4bb4f7
--- /dev/null
+++ b/app/Services/UploadService.php
@@ -0,0 +1,64 @@
+fileSystem = $fileSystem;
+ }
+
+ /**
+ * Get the storage that will be used for storing images.
+ * @return FileSystemInstance
+ */
+ protected function getStorage()
+ {
+ if ($this->storageInstance !== null) return $this->storageInstance;
+
+ $storageType = config('filesystems.default');
+ $this->storageInstance = $this->fileSystem->disk($storageType);
+
+ return $this->storageInstance;
+ }
+
+
+ /**
+ * Check whether or not a folder is empty.
+ * @param $path
+ * @return bool
+ */
+ protected function isFolderEmpty($path)
+ {
+ $files = $this->getStorage()->files($path);
+ $folders = $this->getStorage()->directories($path);
+ return (count($files) === 0 && count($folders) === 0);
+ }
+
+ /**
+ * Check if using a local filesystem.
+ * @return bool
+ */
+ protected function isLocal()
+ {
+ 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 aac9831f7..1a9ee5f70 100644
--- a/app/Services/ViewService.php
+++ b/app/Services/ViewService.php
@@ -18,7 +18,7 @@ class ViewService
public function __construct(View $view, PermissionService $permissionService)
{
$this->view = $view;
- $this->user = auth()->user();
+ $this->user = user();
$this->permissionService = $permissionService;
}
@@ -84,7 +84,7 @@ class ViewService
->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type');
if ($filterModel) $query = $query->where('viewable_type', '=', get_class($filterModel));
- $query = $query->where('user_id', '=', auth()->user()->id);
+ $query = $query->where('user_id', '=', user()->id);
$viewables = $query->with('viewable')->orderBy('updated_at', 'desc')
->skip($count * $page)->take($count)->get()->pluck('viewable');
diff --git a/app/User.php b/app/User.php
index 32449971d..09b189cbb 100644
--- a/app/User.php
+++ b/app/User.php
@@ -1,13 +1,16 @@
'guest',
- 'name' => 'Guest'
- ]);
+ return static::where('system_name', '=', 'public')->first();
+ }
+
+ /**
+ * Check if the user is the default public user.
+ * @return bool
+ */
+ public function isDefault()
+ {
+ return $this->system_name === 'public';
}
/**
* The roles that belong to the user.
+ * @return BelongsToMany
*/
public function roles()
{
+ if ($this->id === 0) return ;
return $this->belongsToMany(Role::class);
}
@@ -183,4 +195,14 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
return '';
}
+
+ /**
+ * Send the password reset notification.
+ * @param string $token
+ * @return void
+ */
+ public function sendPasswordResetNotification($token)
+ {
+ $this->notify(new ResetPassword($token));
+ }
}
diff --git a/app/helpers.php b/app/helpers.php
index c12708877..b5be0fd11 100644
--- a/app/helpers.php
+++ b/app/helpers.php
@@ -11,29 +11,30 @@ use BookStack\Ownable;
*/
function versioned_asset($file = '')
{
- // Don't require css and JS assets for testing
- if (config('app.env') === 'testing') return '';
+ static $version = null;
- static $manifest = null;
- $manifestPath = 'build/manifest.json';
-
- if (is_null($manifest) && file_exists($manifestPath)) {
- $manifest = json_decode(file_get_contents(public_path($manifestPath)), true);
- } else if (!file_exists($manifestPath)) {
- if (config('app.env') !== 'production') {
- $path = public_path($manifestPath);
- $error = "No {$path} file found, Ensure you have built the css/js assets using gulp.";
- } else {
- $error = "No {$manifestPath} file found, Ensure you are using the release version of BookStack";
- }
- throw new \Exception($error);
+ if (is_null($version)) {
+ $versionFile = base_path('version');
+ $version = trim(file_get_contents($versionFile));
}
- if (isset($manifest[$file])) {
- return baseUrl($manifest[$file]);
+ $additional = '';
+ if (config('app.env') === 'development') {
+ $additional = sha1_file(public_path($file));
}
- throw new InvalidArgumentException("File {$file} not defined in asset manifest.");
+ $path = $file . '?version=' . urlencode($version) . $additional;
+ return baseUrl($path);
+}
+
+/**
+ * Helper method to get the current User.
+ * Defaults to public 'Guest' user if not logged in.
+ * @return \BookStack\User
+ */
+function user()
+{
+ return auth()->user() ?: \BookStack\User::getDefault();
}
/**
@@ -47,7 +48,7 @@ function versioned_asset($file = '')
function userCan($permission, Ownable $ownable = null)
{
if ($ownable === null) {
- return auth()->user() && auth()->user()->can($permission);
+ return user() && user()->can($permission);
}
// Check permission on ownable item
@@ -63,7 +64,7 @@ function userCan($permission, Ownable $ownable = null)
*/
function setting($key, $default = false)
{
- $settingService = app('BookStack\Services\SettingService');
+ $settingService = app(\BookStack\Services\SettingService::class);
return $settingService->get($key, $default);
}
@@ -79,6 +80,7 @@ function baseUrl($path, $forceAppDomain = false)
if ($isFullUrl && !$forceAppDomain) return $path;
$path = trim($path, '/');
+ // Remove non-specified domain if forced and we have a domain
if ($isFullUrl && $forceAppDomain) {
$explodedPath = explode('/', $path);
$path = implode('/', array_splice($explodedPath, 3));
@@ -127,14 +129,14 @@ function sortUrl($path, $data, $overrideData = [])
{
$queryStringSections = [];
$queryData = array_merge($data, $overrideData);
-
+
// Change sorting direction is already sorted on current attribute
if (isset($overrideData['sort']) && $overrideData['sort'] === $data['sort']) {
$queryData['order'] = ($data['order'] === 'asc') ? 'desc' : 'asc';
} else {
$queryData['order'] = 'asc';
}
-
+
foreach ($queryData as $name => $value) {
$trimmedVal = trim($value);
if ($trimmedVal === '') continue;
@@ -144,4 +146,4 @@ function sortUrl($path, $data, $overrideData = [])
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 5c77a68c4..7d4b5e62b 100644
--- a/composer.json
+++ b/composer.json
@@ -5,23 +5,24 @@
"license": "MIT",
"type": "project",
"require": {
- "php": ">=5.5.9",
- "laravel/framework": "5.2.*",
+ "php": ">=5.6.4",
+ "laravel/framework": "^5.3.4",
+ "ext-tidy": "*",
"intervention/image": "^2.3",
"laravel/socialite": "^2.0",
"barryvdh/laravel-ide-helper": "^2.1",
- "barryvdh/laravel-debugbar": "^2.0",
+ "barryvdh/laravel-debugbar": "^2.2.3",
"league/flysystem-aws-s3-v3": "^1.0",
- "barryvdh/laravel-dompdf": "0.6.*",
- "predis/predis": "^1.0"
+ "barryvdh/laravel-dompdf": "^0.7",
+ "predis/predis": "^1.1",
+ "gathercontent/htmldiff": "^0.2.1"
},
"require-dev": {
"fzaninotto/faker": "~1.4",
"mockery/mockery": "0.9.*",
- "phpunit/phpunit": "~4.0",
- "phpspec/phpspec": "~2.1",
- "symfony/dom-crawler": "~3.0",
- "symfony/css-selector": "~3.0"
+ "phpunit/phpunit": "~5.0",
+ "symfony/css-selector": "3.1.*",
+ "symfony/dom-crawler": "3.1.*"
},
"autoload": {
"classmap": [
@@ -37,21 +38,19 @@
]
},
"scripts": {
- "post-install-cmd": [
- "php artisan clear-compiled",
- "php artisan optimize"
- ],
- "pre-update-cmd": [
- "php artisan clear-compiled"
- ],
- "post-update-cmd": [
- "php artisan optimize"
- ],
"post-root-package-install": [
- "php -r \"copy('.env.example', '.env');\""
+ "php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"php artisan key:generate"
+ ],
+ "post-install-cmd": [
+ "Illuminate\\Foundation\\ComposerScripts::postInstall",
+ "php artisan optimize"
+ ],
+ "post-update-cmd": [
+ "Illuminate\\Foundation\\ComposerScripts::postUpdate",
+ "php artisan optimize"
]
},
"config": {
diff --git a/composer.lock b/composer.lock
index 63d378753..74a090288 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,27 +4,27 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "eb7c71e9ed116d3fd2a1d0af07f9f134",
- "content-hash": "17d2d7fc5fed682f2a290d6588538035",
+ "hash": "3124d900cfe857392a94de479f3ff6d4",
+ "content-hash": "a968767a73f77e66e865c276cf76eedf",
"packages": [
{
"name": "aws/aws-sdk-php",
- "version": "3.17.5",
+ "version": "3.19.11",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
- "reference": "1cef9b334729b3564c9aef15481a55561c54b53f"
+ "reference": "19bac3bdd7988cbf7f89d5ce8e2748d774e2cde8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/1cef9b334729b3564c9aef15481a55561c54b53f",
- "reference": "1cef9b334729b3564c9aef15481a55561c54b53f",
+ "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/19bac3bdd7988cbf7f89d5ce8e2748d774e2cde8",
+ "reference": "19bac3bdd7988cbf7f89d5ce8e2748d774e2cde8",
"shasum": ""
},
"require": {
- "guzzlehttp/guzzle": "~5.3|~6.0.1|~6.1",
+ "guzzlehttp/guzzle": "^5.3.1|^6.2.1",
"guzzlehttp/promises": "~1.0",
- "guzzlehttp/psr7": "~1.0",
+ "guzzlehttp/psr7": "~1.3.1",
"mtdowling/jmespath.php": "~2.2",
"php": ">=5.5"
},
@@ -85,32 +85,32 @@
"s3",
"sdk"
],
- "time": "2016-04-07 22:44:13"
+ "time": "2016-09-27 19:38:36"
},
{
"name": "barryvdh/laravel-debugbar",
- "version": "v2.2.0",
+ "version": "v2.3.0",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
- "reference": "13b7058d2120c8d5af7f1ada21b7c44dd87b666a"
+ "reference": "0c87981df959c7c1943abe227baf607c92f204f9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/13b7058d2120c8d5af7f1ada21b7c44dd87b666a",
- "reference": "13b7058d2120c8d5af7f1ada21b7c44dd87b666a",
+ "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/0c87981df959c7c1943abe227baf607c92f204f9",
+ "reference": "0c87981df959c7c1943abe227baf607c92f204f9",
"shasum": ""
},
"require": {
- "illuminate/support": "5.1.*|5.2.*",
- "maximebf/debugbar": "~1.11.0",
+ "illuminate/support": "5.1.*|5.2.*|5.3.*",
+ "maximebf/debugbar": "~1.13.0",
"php": ">=5.5.9",
"symfony/finder": "~2.7|~3.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.2-dev"
+ "dev-master": "2.3-dev"
}
},
"autoload": {
@@ -139,31 +139,31 @@
"profiler",
"webprofiler"
],
- "time": "2016-02-17 08:32:21"
+ "time": "2016-09-15 14:05:56"
},
{
"name": "barryvdh/laravel-dompdf",
- "version": "v0.6.1",
+ "version": "v0.7.0",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-dompdf.git",
- "reference": "b606788108833f7765801dca35455fb23ce9f869"
+ "reference": "9b8bd179262ad6b200a11edfe7b53516afcfc42a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/b606788108833f7765801dca35455fb23ce9f869",
- "reference": "b606788108833f7765801dca35455fb23ce9f869",
+ "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/9b8bd179262ad6b200a11edfe7b53516afcfc42a",
+ "reference": "9b8bd179262ad6b200a11edfe7b53516afcfc42a",
"shasum": ""
},
"require": {
- "dompdf/dompdf": "0.6.*",
- "illuminate/support": "5.0.x|5.1.x|5.2.x",
- "php": ">=5.4.0"
+ "dompdf/dompdf": "^0.7",
+ "illuminate/support": "5.1.x|5.2.x|5.3.x",
+ "php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "0.6-dev"
+ "dev-master": "0.7-dev"
}
},
"autoload": {
@@ -187,32 +187,35 @@
"laravel",
"pdf"
],
- "time": "2015-12-21 19:51:22"
+ "time": "2016-08-17 08:17:33"
},
{
"name": "barryvdh/laravel-ide-helper",
- "version": "v2.1.4",
+ "version": "v2.2.1",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-ide-helper.git",
- "reference": "f1ebd847aac9a4545325d35108cafc285fe1605f"
+ "reference": "28af7cd19ca41cc0c63dd1de2b46c2b84d31c463"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/f1ebd847aac9a4545325d35108cafc285fe1605f",
- "reference": "f1ebd847aac9a4545325d35108cafc285fe1605f",
+ "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/28af7cd19ca41cc0c63dd1de2b46c2b84d31c463",
+ "reference": "28af7cd19ca41cc0c63dd1de2b46c2b84d31c463",
"shasum": ""
},
"require": {
- "illuminate/console": "5.0.x|5.1.x|5.2.x",
- "illuminate/filesystem": "5.0.x|5.1.x|5.2.x",
- "illuminate/support": "5.0.x|5.1.x|5.2.x",
+ "barryvdh/reflection-docblock": "^2.0.4",
+ "illuminate/console": "^5.0,<5.4",
+ "illuminate/filesystem": "^5.0,<5.4",
+ "illuminate/support": "^5.0,<5.4",
"php": ">=5.4.0",
- "phpdocumentor/reflection-docblock": "^2.0.4",
- "symfony/class-loader": "~2.3|~3.0"
+ "symfony/class-loader": "^2.3|^3.0"
},
"require-dev": {
- "doctrine/dbal": "~2.3"
+ "doctrine/dbal": "~2.3",
+ "phpunit/phpunit": "4.*",
+ "scrutinizer/ocular": "~1.1",
+ "squizlabs/php_codesniffer": "~2.3"
},
"suggest": {
"doctrine/dbal": "Load information from the database about models for phpdocs (~2.3)"
@@ -220,7 +223,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.1-dev"
+ "dev-master": "2.2-dev"
}
},
"autoload": {
@@ -250,7 +253,56 @@
"phpstorm",
"sublime"
],
- "time": "2016-03-03 08:45:00"
+ "time": "2016-07-04 11:52:48"
+ },
+ {
+ "name": "barryvdh/reflection-docblock",
+ "version": "v2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/barryvdh/ReflectionDocBlock.git",
+ "reference": "3dcbd98b5d9384a5357266efba8fd29884458e5c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/3dcbd98b5d9384a5357266efba8fd29884458e5c",
+ "reference": "3dcbd98b5d9384a5357266efba8fd29884458e5c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.0,<4.5"
+ },
+ "suggest": {
+ "dflydev/markdown": "~1.0",
+ "erusev/parsedown": "~1.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Barryvdh": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "mike.vanriel@naenius.com"
+ }
+ ],
+ "time": "2016-06-13 19:28:20"
},
{
"name": "classpreloader/classpreloader",
@@ -306,6 +358,57 @@
],
"time": "2015-11-09 22:51:51"
},
+ {
+ "name": "cogpowered/finediff",
+ "version": "0.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cogpowered/FineDiff.git",
+ "reference": "339ddc8c3afb656efed4f2f0a80e5c3d026f8ea8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cogpowered/FineDiff/zipball/339ddc8c3afb656efed4f2f0a80e5c3d026f8ea8",
+ "reference": "339ddc8c3afb656efed4f2f0a80e5c3d026f8ea8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "mockery/mockery": "*",
+ "phpunit/phpunit": "*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "cogpowered\\FineDiff": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Rob Crowe",
+ "email": "rob@cogpowered.com"
+ },
+ {
+ "name": "Raymond Hill"
+ }
+ ],
+ "description": "PHP implementation of a Fine granularity Diff engine",
+ "homepage": "https://github.com/cogpowered/FineDiff",
+ "keywords": [
+ "diff",
+ "finediff",
+ "opcode",
+ "string",
+ "text"
+ ],
+ "time": "2014-05-19 10:25:02"
+ },
{
"name": "dnoegel/php-xdg-base-dir",
"version": "0.1",
@@ -408,30 +511,46 @@
},
{
"name": "dompdf/dompdf",
- "version": "v0.6.2",
+ "version": "v0.7.0",
"source": {
"type": "git",
"url": "https://github.com/dompdf/dompdf.git",
- "reference": "cc06008f75262510ee135b8cbb14e333a309f651"
+ "reference": "5c98652b1a5beb7e3cc8ec35419b2828dd63ab14"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/dompdf/dompdf/zipball/cc06008f75262510ee135b8cbb14e333a309f651",
- "reference": "cc06008f75262510ee135b8cbb14e333a309f651",
+ "url": "https://api.github.com/repos/dompdf/dompdf/zipball/5c98652b1a5beb7e3cc8ec35419b2828dd63ab14",
+ "reference": "5c98652b1a5beb7e3cc8ec35419b2828dd63ab14",
"shasum": ""
},
"require": {
- "phenx/php-font-lib": "0.2.*"
+ "ext-dom": "*",
+ "ext-gd": "*",
+ "ext-mbstring": "*",
+ "phenx/php-font-lib": "0.4.*",
+ "phenx/php-svg-lib": "0.1.*",
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "3.7.*"
},
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "0.7-dev"
+ }
+ },
"autoload": {
+ "psr-4": {
+ "Dompdf\\": "src/"
+ },
"classmap": [
- "include/"
+ "lib/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "LGPL"
+ "LGPL-2.1"
],
"authors": [
{
@@ -441,74 +560,42 @@
{
"name": "Brian Sweeney",
"email": "eclecticgeek@gmail.com"
+ },
+ {
+ "name": "Gabriel Bull",
+ "email": "me@gabrielbull.com"
}
],
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
"homepage": "https://github.com/dompdf/dompdf",
- "time": "2015-12-07 04:07:13"
+ "time": "2016-05-11 00:36:29"
},
{
- "name": "guzzle/guzzle",
- "version": "v3.8.1",
+ "name": "gathercontent/htmldiff",
+ "version": "0.2.1",
"source": {
"type": "git",
- "url": "https://github.com/guzzle/guzzle.git",
- "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba"
+ "url": "https://github.com/gathercontent/htmldiff.git",
+ "reference": "24674a62315f64330134b4a4c5b01a7b59193c93"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/4de0618a01b34aa1c8c33a3f13f396dcd3882eba",
- "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba",
+ "url": "https://api.github.com/repos/gathercontent/htmldiff/zipball/24674a62315f64330134b4a4c5b01a7b59193c93",
+ "reference": "24674a62315f64330134b4a4c5b01a7b59193c93",
"shasum": ""
},
"require": {
- "ext-curl": "*",
- "php": ">=5.3.3",
- "symfony/event-dispatcher": ">=2.1"
- },
- "replace": {
- "guzzle/batch": "self.version",
- "guzzle/cache": "self.version",
- "guzzle/common": "self.version",
- "guzzle/http": "self.version",
- "guzzle/inflection": "self.version",
- "guzzle/iterator": "self.version",
- "guzzle/log": "self.version",
- "guzzle/parser": "self.version",
- "guzzle/plugin": "self.version",
- "guzzle/plugin-async": "self.version",
- "guzzle/plugin-backoff": "self.version",
- "guzzle/plugin-cache": "self.version",
- "guzzle/plugin-cookie": "self.version",
- "guzzle/plugin-curlauth": "self.version",
- "guzzle/plugin-error-response": "self.version",
- "guzzle/plugin-history": "self.version",
- "guzzle/plugin-log": "self.version",
- "guzzle/plugin-md5": "self.version",
- "guzzle/plugin-mock": "self.version",
- "guzzle/plugin-oauth": "self.version",
- "guzzle/service": "self.version",
- "guzzle/stream": "self.version"
+ "cogpowered/finediff": "0.3.1",
+ "ext-tidy": "*"
},
"require-dev": {
- "doctrine/cache": "*",
- "monolog/monolog": "1.*",
- "phpunit/phpunit": "3.7.*",
- "psr/log": "1.0.*",
- "symfony/class-loader": "*",
- "zendframework/zend-cache": "<2.3",
- "zendframework/zend-log": "<2.3"
+ "phpunit/phpunit": "4.*",
+ "squizlabs/php_codesniffer": "1.*"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.8-dev"
- }
- },
"autoload": {
"psr-0": {
- "Guzzle": "src/",
- "Guzzle\\Tests": "tests/"
+ "GatherContent\\Htmldiff": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -517,51 +604,44 @@
],
"authors": [
{
- "name": "Michael Dowling",
- "email": "mtdowling@gmail.com",
- "homepage": "https://github.com/mtdowling"
+ "name": "Andrew Cairns",
+ "email": "andrew@gathercontent.com"
},
{
- "name": "Guzzle Community",
- "homepage": "https://github.com/guzzle/guzzle/contributors"
+ "name": "Mathew Chapman",
+ "email": "mat@gathercontent.com"
+ },
+ {
+ "name": "Peter Legierski",
+ "email": "peter@gathercontent.com"
}
],
- "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
- "homepage": "http://guzzlephp.org/",
- "keywords": [
- "client",
- "curl",
- "framework",
- "http",
- "http client",
- "rest",
- "web service"
- ],
- "time": "2014-01-28 22:29:15"
+ "description": "Compare two HTML strings",
+ "time": "2015-04-15 15:39:46"
},
{
"name": "guzzlehttp/guzzle",
- "version": "6.2.0",
+ "version": "6.2.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
- "reference": "d094e337976dff9d8e2424e8485872194e768662"
+ "reference": "3f808fba627f2c5b69e2501217bf31af349c1427"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d094e337976dff9d8e2424e8485872194e768662",
- "reference": "d094e337976dff9d8e2424e8485872194e768662",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/3f808fba627f2c5b69e2501217bf31af349c1427",
+ "reference": "3f808fba627f2c5b69e2501217bf31af349c1427",
"shasum": ""
},
"require": {
- "guzzlehttp/promises": "~1.0",
- "guzzlehttp/psr7": "~1.1",
- "php": ">=5.5.0"
+ "guzzlehttp/promises": "^1.0",
+ "guzzlehttp/psr7": "^1.3.1",
+ "php": ">=5.5"
},
"require-dev": {
"ext-curl": "*",
- "phpunit/phpunit": "~4.0",
- "psr/log": "~1.0"
+ "phpunit/phpunit": "^4.0",
+ "psr/log": "^1.0"
},
"type": "library",
"extra": {
@@ -599,20 +679,20 @@
"rest",
"web service"
],
- "time": "2016-03-21 20:02:09"
+ "time": "2016-07-15 17:22:37"
},
{
"name": "guzzlehttp/promises",
- "version": "1.1.0",
+ "version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
- "reference": "bb9024c526b22f3fe6ae55a561fd70653d470aa8"
+ "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/promises/zipball/bb9024c526b22f3fe6ae55a561fd70653d470aa8",
- "reference": "bb9024c526b22f3fe6ae55a561fd70653d470aa8",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579",
+ "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579",
"shasum": ""
},
"require": {
@@ -650,20 +730,20 @@
"keywords": [
"promise"
],
- "time": "2016-03-08 01:15:46"
+ "time": "2016-05-18 16:56:05"
},
{
"name": "guzzlehttp/psr7",
- "version": "1.2.3",
+ "version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
- "reference": "2e89629ff057ebb49492ba08e6995d3a6a80021b"
+ "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/2e89629ff057ebb49492ba08e6995d3a6a80021b",
- "reference": "2e89629ff057ebb49492ba08e6995d3a6a80021b",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b",
+ "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b",
"shasum": ""
},
"require": {
@@ -679,7 +759,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0-dev"
+ "dev-master": "1.4-dev"
}
},
"autoload": {
@@ -708,20 +788,20 @@
"stream",
"uri"
],
- "time": "2016-02-18 21:54:00"
+ "time": "2016-06-24 23:00:38"
},
{
"name": "intervention/image",
- "version": "2.3.6",
+ "version": "2.3.8",
"source": {
"type": "git",
"url": "https://github.com/Intervention/image.git",
- "reference": "e368d262887dbb2fdfaf710880571ede51e9c0e6"
+ "reference": "4064a980324f6c3bfa2bd981dfb247afa705ec3c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Intervention/image/zipball/e368d262887dbb2fdfaf710880571ede51e9c0e6",
- "reference": "e368d262887dbb2fdfaf710880571ede51e9c0e6",
+ "url": "https://api.github.com/repos/Intervention/image/zipball/4064a980324f6c3bfa2bd981dfb247afa705ec3c",
+ "reference": "4064a980324f6c3bfa2bd981dfb247afa705ec3c",
"shasum": ""
},
"require": {
@@ -770,7 +850,7 @@
"thumbnail",
"watermark"
],
- "time": "2016-02-26 18:18:19"
+ "time": "2016-09-01 17:04:03"
},
{
"name": "jakub-onderka/php-console-color",
@@ -919,16 +999,16 @@
},
{
"name": "laravel/framework",
- "version": "v5.2.29",
+ "version": "v5.3.11",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
- "reference": "e3d644eb131f18c5f3d28ff7bc678bc797091f20"
+ "reference": "ca48001b95a0543fb39fcd7219de960bbc03eaa5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/framework/zipball/e3d644eb131f18c5f3d28ff7bc678bc797091f20",
- "reference": "e3d644eb131f18c5f3d28ff7bc678bc797091f20",
+ "url": "https://api.github.com/repos/laravel/framework/zipball/ca48001b95a0543fb39fcd7219de960bbc03eaa5",
+ "reference": "ca48001b95a0543fb39fcd7219de960bbc03eaa5",
"shasum": ""
},
"require": {
@@ -941,20 +1021,20 @@
"monolog/monolog": "~1.11",
"mtdowling/cron-expression": "~1.0",
"nesbot/carbon": "~1.20",
- "paragonie/random_compat": "~1.4",
- "php": ">=5.5.9",
+ "paragonie/random_compat": "~1.4|~2.0",
+ "php": ">=5.6.4",
"psy/psysh": "0.7.*",
+ "ramsey/uuid": "~3.0",
"swiftmailer/swiftmailer": "~5.1",
- "symfony/console": "2.8.*|3.0.*",
- "symfony/debug": "2.8.*|3.0.*",
- "symfony/finder": "2.8.*|3.0.*",
- "symfony/http-foundation": "2.8.*|3.0.*",
- "symfony/http-kernel": "2.8.*|3.0.*",
- "symfony/polyfill-php56": "~1.0",
- "symfony/process": "2.8.*|3.0.*",
- "symfony/routing": "2.8.*|3.0.*",
- "symfony/translation": "2.8.*|3.0.*",
- "symfony/var-dumper": "2.8.*|3.0.*",
+ "symfony/console": "3.1.*",
+ "symfony/debug": "3.1.*",
+ "symfony/finder": "3.1.*",
+ "symfony/http-foundation": "3.1.*",
+ "symfony/http-kernel": "3.1.*",
+ "symfony/process": "3.1.*",
+ "symfony/routing": "3.1.*",
+ "symfony/translation": "3.1.*",
+ "symfony/var-dumper": "3.1.*",
"vlucas/phpdotenv": "~2.2"
},
"replace": {
@@ -976,6 +1056,7 @@
"illuminate/http": "self.version",
"illuminate/log": "self.version",
"illuminate/mail": "self.version",
+ "illuminate/notifications": "self.version",
"illuminate/pagination": "self.version",
"illuminate/pipeline": "self.version",
"illuminate/queue": "self.version",
@@ -985,16 +1066,17 @@
"illuminate/support": "self.version",
"illuminate/translation": "self.version",
"illuminate/validation": "self.version",
- "illuminate/view": "self.version"
+ "illuminate/view": "self.version",
+ "tightenco/collect": "self.version"
},
"require-dev": {
"aws/aws-sdk-php": "~3.0",
- "mockery/mockery": "~0.9.2",
+ "mockery/mockery": "~0.9.4",
"pda/pheanstalk": "~3.0",
- "phpunit/phpunit": "~4.1",
+ "phpunit/phpunit": "~5.4",
"predis/predis": "~1.0",
- "symfony/css-selector": "2.8.*|3.0.*",
- "symfony/dom-crawler": "2.8.*|3.0.*"
+ "symfony/css-selector": "3.1.*",
+ "symfony/dom-crawler": "3.1.*"
},
"suggest": {
"aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).",
@@ -1006,19 +1088,17 @@
"pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).",
"predis/predis": "Required to use the redis cache and queue drivers (~1.0).",
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~2.0).",
- "symfony/css-selector": "Required to use some of the crawler integration testing tools (2.8.*|3.0.*).",
- "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (2.8.*|3.0.*)."
+ "symfony/css-selector": "Required to use some of the crawler integration testing tools (3.1.*).",
+ "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (3.1.*).",
+ "symfony/psr-http-message-bridge": "Required to psr7 bridging features (0.2.*)."
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.2-dev"
+ "dev-master": "5.3-dev"
}
},
"autoload": {
- "classmap": [
- "src/Illuminate/Queue/IlluminateQueueClosure.php"
- ],
"files": [
"src/Illuminate/Foundation/helpers.php",
"src/Illuminate/Support/helpers.php"
@@ -1034,29 +1114,29 @@
"authors": [
{
"name": "Taylor Otwell",
- "email": "taylorotwell@gmail.com"
+ "email": "taylor@laravel.com"
}
],
"description": "The Laravel Framework.",
- "homepage": "http://laravel.com",
+ "homepage": "https://laravel.com",
"keywords": [
"framework",
"laravel"
],
- "time": "2016-04-03 01:43:55"
+ "time": "2016-09-28 02:15:37"
},
{
"name": "laravel/socialite",
- "version": "v2.0.15",
+ "version": "v2.0.18",
"source": {
"type": "git",
"url": "https://github.com/laravel/socialite.git",
- "reference": "edd00ab96933e3ef053533cce81e958fb26921af"
+ "reference": "76ee5397fcdea5a062361392abca4eb397e519a3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/socialite/zipball/edd00ab96933e3ef053533cce81e958fb26921af",
- "reference": "edd00ab96933e3ef053533cce81e958fb26921af",
+ "url": "https://api.github.com/repos/laravel/socialite/zipball/76ee5397fcdea5a062361392abca4eb397e519a3",
+ "reference": "76ee5397fcdea5a062361392abca4eb397e519a3",
"shasum": ""
},
"require": {
@@ -1069,7 +1149,7 @@
},
"require-dev": {
"mockery/mockery": "~0.9",
- "phpunit/phpunit": "~4.0"
+ "phpunit/phpunit": "~4.0|~5.0"
},
"type": "library",
"extra": {
@@ -1097,20 +1177,20 @@
"laravel",
"oauth"
],
- "time": "2016-03-21 14:30:30"
+ "time": "2016-06-22 12:40:16"
},
{
"name": "league/flysystem",
- "version": "1.0.20",
+ "version": "1.0.27",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
- "reference": "e87a786e3ae12a25cf78a71bb07b4b384bfaa83a"
+ "reference": "50e2045ed70a7e75a5e30bc3662904f3b67af8a9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/e87a786e3ae12a25cf78a71bb07b4b384bfaa83a",
- "reference": "e87a786e3ae12a25cf78a71bb07b4b384bfaa83a",
+ "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/50e2045ed70a7e75a5e30bc3662904f3b67af8a9",
+ "reference": "50e2045ed70a7e75a5e30bc3662904f3b67af8a9",
"shasum": ""
},
"require": {
@@ -1123,7 +1203,7 @@
"ext-fileinfo": "*",
"mockery/mockery": "~0.9",
"phpspec/phpspec": "^2.2",
- "phpunit/phpunit": "~4.8 || ~5.0"
+ "phpunit/phpunit": "~4.8"
},
"suggest": {
"ext-fileinfo": "Required for MimeType",
@@ -1180,20 +1260,20 @@
"sftp",
"storage"
],
- "time": "2016-03-14 21:54:11"
+ "time": "2016-08-10 08:55:11"
},
{
"name": "league/flysystem-aws-s3-v3",
- "version": "1.0.9",
+ "version": "1.0.13",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
- "reference": "595e24678bf78f8107ebc9355d8376ae0eb712c6"
+ "reference": "dc56a8faf3aff0841f9eae04b6af94a50657896c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/595e24678bf78f8107ebc9355d8376ae0eb712c6",
- "reference": "595e24678bf78f8107ebc9355d8376ae0eb712c6",
+ "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/dc56a8faf3aff0841f9eae04b6af94a50657896c",
+ "reference": "dc56a8faf3aff0841f9eae04b6af94a50657896c",
"shasum": ""
},
"require": {
@@ -1227,30 +1307,30 @@
}
],
"description": "Flysystem adapter for the AWS S3 SDK v3.x",
- "time": "2015-11-19 08:44:16"
+ "time": "2016-06-21 21:34:35"
},
{
"name": "league/oauth1-client",
- "version": "1.6.1",
+ "version": "1.7.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/oauth1-client.git",
- "reference": "cef3ceda13c78f89c323e4d5e6301c0eb7cea422"
+ "reference": "fca5f160650cb74d23fc11aa570dd61f86dcf647"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/cef3ceda13c78f89c323e4d5e6301c0eb7cea422",
- "reference": "cef3ceda13c78f89c323e4d5e6301c0eb7cea422",
+ "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/fca5f160650cb74d23fc11aa570dd61f86dcf647",
+ "reference": "fca5f160650cb74d23fc11aa570dd61f86dcf647",
"shasum": ""
},
"require": {
- "guzzle/guzzle": "3.*",
- "php": ">=5.3.0"
+ "guzzlehttp/guzzle": "^6.0",
+ "php": ">=5.5.0"
},
"require-dev": {
- "mockery/mockery": "~0.9",
- "phpunit/phpunit": "~4.0",
- "squizlabs/php_codesniffer": "~2.0"
+ "mockery/mockery": "^0.9",
+ "phpunit/phpunit": "^4.0",
+ "squizlabs/php_codesniffer": "^2.0"
},
"type": "library",
"extra": {
@@ -1290,20 +1370,20 @@
"tumblr",
"twitter"
],
- "time": "2015-10-23 04:02:07"
+ "time": "2016-08-17 00:36:58"
},
{
"name": "maximebf/debugbar",
- "version": "v1.11.1",
+ "version": "v1.13.0",
"source": {
"type": "git",
"url": "https://github.com/maximebf/php-debugbar.git",
- "reference": "d9302891c1f0a0ac5a4f66725163a00537c6359f"
+ "reference": "5f49a5ed6cfde81d31d89378806670d77462526e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/d9302891c1f0a0ac5a4f66725163a00537c6359f",
- "reference": "d9302891c1f0a0ac5a4f66725163a00537c6359f",
+ "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/5f49a5ed6cfde81d31d89378806670d77462526e",
+ "reference": "5f49a5ed6cfde81d31d89378806670d77462526e",
"shasum": ""
},
"require": {
@@ -1322,7 +1402,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.11-dev"
+ "dev-master": "1.13-dev"
}
},
"autoload": {
@@ -1351,20 +1431,20 @@
"debug",
"debugbar"
],
- "time": "2016-01-22 12:22:23"
+ "time": "2016-09-15 14:01:59"
},
{
"name": "monolog/monolog",
- "version": "1.18.2",
+ "version": "1.21.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
- "reference": "064b38c16790249488e7a8b987acf1c9d7383c09"
+ "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Seldaek/monolog/zipball/064b38c16790249488e7a8b987acf1c9d7383c09",
- "reference": "064b38c16790249488e7a8b987acf1c9d7383c09",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f42fbdfd53e306bda545845e4dbfd3e72edb4952",
+ "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952",
"shasum": ""
},
"require": {
@@ -1383,8 +1463,8 @@
"php-console/php-console": "^3.1.3",
"phpunit/phpunit": "~4.5",
"phpunit/phpunit-mock-objects": "2.3.0",
- "raven/raven": "^0.13",
"ruflin/elastica": ">=0.90 <3.0",
+ "sentry/sentry": "^0.13",
"swiftmailer/swiftmailer": "~5.3"
},
"suggest": {
@@ -1396,9 +1476,9 @@
"mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
"php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
"php-console/php-console": "Allow sending log messages to Google Chrome",
- "raven/raven": "Allow sending log messages to a Sentry server",
"rollbar/rollbar": "Allow sending log messages to Rollbar",
- "ruflin/elastica": "Allow sending log messages to an Elastic Search server"
+ "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
+ "sentry/sentry": "Allow sending log messages to a Sentry server"
},
"type": "library",
"extra": {
@@ -1429,7 +1509,7 @@
"logging",
"psr-3"
],
- "time": "2016-04-02 13:12:58"
+ "time": "2016-07-29 03:23:52"
},
{
"name": "mtdowling/cron-expression",
@@ -1579,16 +1659,16 @@
},
{
"name": "nikic/php-parser",
- "version": "v2.0.1",
+ "version": "v2.1.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "ce5be709d59b32dd8a88c80259028759991a4206"
+ "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ce5be709d59b32dd8a88c80259028759991a4206",
- "reference": "ce5be709d59b32dd8a88c80259028759991a4206",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4dd659edadffdc2143e4753df655d866dbfeedf0",
+ "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0",
"shasum": ""
},
"require": {
@@ -1604,7 +1684,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0-dev"
+ "dev-master": "2.1-dev"
}
},
"autoload": {
@@ -1626,20 +1706,20 @@
"parser",
"php"
],
- "time": "2016-02-28 19:48:28"
+ "time": "2016-09-16 12:04:44"
},
{
"name": "paragonie/random_compat",
- "version": "v1.4.1",
+ "version": "v2.0.2",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
- "reference": "c7e26a21ba357863de030f0b9e701c7d04593774"
+ "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774",
- "reference": "c7e26a21ba357863de030f0b9e701c7d04593774",
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf",
+ "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf",
"shasum": ""
},
"require": {
@@ -1674,31 +1754,31 @@
"pseudorandom",
"random"
],
- "time": "2016-03-18 20:34:03"
+ "time": "2016-04-03 06:00:07"
},
{
"name": "phenx/php-font-lib",
- "version": "0.2.2",
+ "version": "0.4",
"source": {
"type": "git",
"url": "https://github.com/PhenX/php-font-lib.git",
- "reference": "c30c7fc00a6b0d863e9bb4c5d5dd015298b2dc82"
+ "reference": "b8af0cacdc3cbf1e41a586fcb78f506f4121a088"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PhenX/php-font-lib/zipball/c30c7fc00a6b0d863e9bb4c5d5dd015298b2dc82",
- "reference": "c30c7fc00a6b0d863e9bb4c5d5dd015298b2dc82",
+ "url": "https://api.github.com/repos/PhenX/php-font-lib/zipball/b8af0cacdc3cbf1e41a586fcb78f506f4121a088",
+ "reference": "b8af0cacdc3cbf1e41a586fcb78f506f4121a088",
"shasum": ""
},
"type": "library",
"autoload": {
- "classmap": [
- "classes/"
- ]
+ "psr-0": {
+ "FontLib\\": "src/"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "LGPL"
+ "LGPL-3.0"
],
"authors": [
{
@@ -1708,76 +1788,61 @@
],
"description": "A library to read, parse, export and make subsets of different types of font files.",
"homepage": "https://github.com/PhenX/php-font-lib",
- "time": "2014-02-01 15:22:28"
+ "time": "2015-05-06 20:02:39"
},
{
- "name": "phpdocumentor/reflection-docblock",
- "version": "2.0.4",
+ "name": "phenx/php-svg-lib",
+ "version": "0.1",
"source": {
"type": "git",
- "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8"
+ "url": "https://github.com/PhenX/php-svg-lib.git",
+ "reference": "b419766515b3426c6da74b0e29e93d71c4f17099"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8",
- "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8",
+ "url": "https://api.github.com/repos/PhenX/php-svg-lib/zipball/b419766515b3426c6da74b0e29e93d71c4f17099",
+ "reference": "b419766515b3426c6da74b0e29e93d71c4f17099",
"shasum": ""
},
- "require": {
- "php": ">=5.3.3"
- },
- "require-dev": {
- "phpunit/phpunit": "~4.0"
- },
- "suggest": {
- "dflydev/markdown": "~1.0",
- "erusev/parsedown": "~1.0"
- },
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0.x-dev"
- }
- },
"autoload": {
"psr-0": {
- "phpDocumentor": [
- "src/"
- ]
+ "Svg\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "LGPL-3.0"
],
"authors": [
{
- "name": "Mike van Riel",
- "email": "mike.vanriel@naenius.com"
+ "name": "Fabien Ménager",
+ "email": "fabien.menager@gmail.com"
}
],
- "time": "2015-02-03 12:10:50"
+ "description": "A library to read, parse and export to PDF SVG files.",
+ "homepage": "https://github.com/PhenX/php-svg-lib",
+ "time": "2015-05-06 18:49:49"
},
{
"name": "predis/predis",
- "version": "v1.0.3",
+ "version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/nrk/predis.git",
- "reference": "84060b9034d756b4d79641667d7f9efe1aeb8e04"
+ "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nrk/predis/zipball/84060b9034d756b4d79641667d7f9efe1aeb8e04",
- "reference": "84060b9034d756b4d79641667d7f9efe1aeb8e04",
+ "url": "https://api.github.com/repos/nrk/predis/zipball/f0210e38881631afeafb56ab43405a92cafd9fd1",
+ "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1",
"shasum": ""
},
"require": {
- "php": ">=5.3.2"
+ "php": ">=5.3.9"
},
"require-dev": {
- "phpunit/phpunit": "~4.0"
+ "phpunit/phpunit": "~4.8"
},
"suggest": {
"ext-curl": "Allows access to Webdis when paired with phpiredis",
@@ -1800,27 +1865,27 @@
"homepage": "http://clorophilla.net"
}
],
- "description": "Flexible and feature-complete PHP client library for Redis",
+ "description": "Flexible and feature-complete Redis client for PHP and HHVM",
"homepage": "http://github.com/nrk/predis",
"keywords": [
"nosql",
"predis",
"redis"
],
- "time": "2015-07-30 18:34:15"
+ "time": "2016-06-16 16:22:20"
},
{
"name": "psr/http-message",
- "version": "1.0",
+ "version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
- "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
- "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
@@ -1848,6 +1913,7 @@
}
],
"description": "Common interface for HTTP messages",
+ "homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
@@ -1856,26 +1922,34 @@
"request",
"response"
],
- "time": "2015-05-04 20:22:00"
+ "time": "2016-08-06 14:39:51"
},
{
"name": "psr/log",
- "version": "1.0.0",
+ "version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
- "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
+ "reference": "5277094ed527a1c4477177d102fe4c53551953e0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
- "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/5277094ed527a1c4477177d102fe4c53551953e0",
+ "reference": "5277094ed527a1c4477177d102fe4c53551953e0",
"shasum": ""
},
+ "require": {
+ "php": ">=5.3.0"
+ },
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
"autoload": {
- "psr-0": {
- "Psr\\Log\\": ""
+ "psr-4": {
+ "Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1889,12 +1963,13 @@
}
],
"description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
- "time": "2012-12-21 11:40:51"
+ "time": "2016-09-19 16:02:08"
},
{
"name": "psy/psysh",
@@ -1969,24 +2044,104 @@
"time": "2016-03-09 05:03:14"
},
{
- "name": "swiftmailer/swiftmailer",
- "version": "v5.4.1",
+ "name": "ramsey/uuid",
+ "version": "3.5.0",
"source": {
"type": "git",
- "url": "https://github.com/swiftmailer/swiftmailer.git",
- "reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421"
+ "url": "https://github.com/ramsey/uuid.git",
+ "reference": "a6d15c8618ea3951fd54d34e326b68d3d0bc0786"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/0697e6aa65c83edf97bb0f23d8763f94e3f11421",
- "reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/a6d15c8618ea3951fd54d34e326b68d3d0bc0786",
+ "reference": "a6d15c8618ea3951fd54d34e326b68d3d0bc0786",
+ "shasum": ""
+ },
+ "require": {
+ "paragonie/random_compat": "^1.0|^2.0",
+ "php": ">=5.4"
+ },
+ "replace": {
+ "rhumsaa/uuid": "self.version"
+ },
+ "require-dev": {
+ "apigen/apigen": "^4.1",
+ "codeception/aspect-mock": "1.0.0",
+ "goaop/framework": "1.0.0-alpha.2",
+ "ircmaxell/random-lib": "^1.1",
+ "jakub-onderka/php-parallel-lint": "^0.9.0",
+ "mockery/mockery": "^0.9.4",
+ "moontoast/math": "^1.1",
+ "phpunit/phpunit": "^4.7|>=5.0 <5.4",
+ "satooshi/php-coveralls": "^0.6.1",
+ "squizlabs/php_codesniffer": "^2.3"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
+ "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
+ "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
+ "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
+ "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
+ "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Ramsey\\Uuid\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marijn Huizendveld",
+ "email": "marijn.huizendveld@gmail.com"
+ },
+ {
+ "name": "Thibaud Fabre",
+ "email": "thibaud@aztech.io"
+ },
+ {
+ "name": "Ben Ramsey",
+ "email": "ben@benramsey.com",
+ "homepage": "https://benramsey.com"
+ }
+ ],
+ "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
+ "homepage": "https://github.com/ramsey/uuid",
+ "keywords": [
+ "guid",
+ "identifier",
+ "uuid"
+ ],
+ "time": "2016-08-02 18:39:32"
+ },
+ {
+ "name": "swiftmailer/swiftmailer",
+ "version": "v5.4.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/swiftmailer/swiftmailer.git",
+ "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/4cc92842069c2bbc1f28daaaf1d2576ec4dfe153",
+ "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
- "mockery/mockery": "~0.9.1,<0.9.4"
+ "mockery/mockery": "~0.9.1"
},
"type": "library",
"extra": {
@@ -2019,20 +2174,20 @@
"mail",
"mailer"
],
- "time": "2015-06-06 14:19:39"
+ "time": "2016-07-08 11:51:25"
},
{
"name": "symfony/class-loader",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/class-loader.git",
- "reference": "cbb7e6a9c0213a0cffa5d9065ee8214ca4e83877"
+ "reference": "2d0ba77c46ecc96a6641009a98f72632216811ba"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/class-loader/zipball/cbb7e6a9c0213a0cffa5d9065ee8214ca4e83877",
- "reference": "cbb7e6a9c0213a0cffa5d9065ee8214ca4e83877",
+ "url": "https://api.github.com/repos/symfony/class-loader/zipball/2d0ba77c46ecc96a6641009a98f72632216811ba",
+ "reference": "2d0ba77c46ecc96a6641009a98f72632216811ba",
"shasum": ""
},
"require": {
@@ -2048,7 +2203,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -2075,20 +2230,20 @@
],
"description": "Symfony ClassLoader Component",
"homepage": "https://symfony.com",
- "time": "2016-03-30 10:41:14"
+ "time": "2016-08-23 13:39:15"
},
{
"name": "symfony/console",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "6b1175135bc2a74c08a28d89761272de8beed8cd"
+ "reference": "8ea494c34f0f772c3954b5fbe00bffc5a435e563"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/6b1175135bc2a74c08a28d89761272de8beed8cd",
- "reference": "6b1175135bc2a74c08a28d89761272de8beed8cd",
+ "url": "https://api.github.com/repos/symfony/console/zipball/8ea494c34f0f772c3954b5fbe00bffc5a435e563",
+ "reference": "8ea494c34f0f772c3954b5fbe00bffc5a435e563",
"shasum": ""
},
"require": {
@@ -2108,7 +2263,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -2135,20 +2290,20 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
- "time": "2016-03-16 17:00:50"
+ "time": "2016-08-19 06:48:39"
},
{
"name": "symfony/debug",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
- "reference": "a06d10888a45afd97534506afb058ec38d9ba35b"
+ "reference": "34f6ac18c2974ca5fce68adf419ee7d15def6f11"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/debug/zipball/a06d10888a45afd97534506afb058ec38d9ba35b",
- "reference": "a06d10888a45afd97534506afb058ec38d9ba35b",
+ "url": "https://api.github.com/repos/symfony/debug/zipball/34f6ac18c2974ca5fce68adf419ee7d15def6f11",
+ "reference": "34f6ac18c2974ca5fce68adf419ee7d15def6f11",
"shasum": ""
},
"require": {
@@ -2165,7 +2320,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -2192,20 +2347,20 @@
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
- "time": "2016-03-30 10:41:14"
+ "time": "2016-08-23 13:39:15"
},
{
"name": "symfony/event-dispatcher",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "9002dcf018d884d294b1ef20a6f968efc1128f39"
+ "reference": "c0c00c80b3a69132c4e55c3e7db32b4a387615e5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9002dcf018d884d294b1ef20a6f968efc1128f39",
- "reference": "9002dcf018d884d294b1ef20a6f968efc1128f39",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c0c00c80b3a69132c4e55c3e7db32b4a387615e5",
+ "reference": "c0c00c80b3a69132c4e55c3e7db32b4a387615e5",
"shasum": ""
},
"require": {
@@ -2225,7 +2380,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -2252,20 +2407,20 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
- "time": "2016-03-10 10:34:12"
+ "time": "2016-07-19 10:45:57"
},
{
"name": "symfony/finder",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "c54e407b35bc098916704e9fd090da21da4c4f52"
+ "reference": "e568ef1784f447a0e54dcb6f6de30b9747b0f577"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/c54e407b35bc098916704e9fd090da21da4c4f52",
- "reference": "c54e407b35bc098916704e9fd090da21da4c4f52",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/e568ef1784f447a0e54dcb6f6de30b9747b0f577",
+ "reference": "e568ef1784f447a0e54dcb6f6de30b9747b0f577",
"shasum": ""
},
"require": {
@@ -2274,7 +2429,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -2301,20 +2456,20 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
- "time": "2016-03-10 11:13:05"
+ "time": "2016-08-26 12:04:02"
},
{
"name": "symfony/http-foundation",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "99f38445a874e7becb8afc4b4a79ee181cf6ec3f"
+ "reference": "63592e00fd90632b57ee50220a1ddb29b6bf3bb4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/99f38445a874e7becb8afc4b4a79ee181cf6ec3f",
- "reference": "99f38445a874e7becb8afc4b4a79ee181cf6ec3f",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/63592e00fd90632b57ee50220a1ddb29b6bf3bb4",
+ "reference": "63592e00fd90632b57ee50220a1ddb29b6bf3bb4",
"shasum": ""
},
"require": {
@@ -2327,7 +2482,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -2354,20 +2509,20 @@
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com",
- "time": "2016-03-27 14:50:32"
+ "time": "2016-08-22 12:11:19"
},
{
"name": "symfony/http-kernel",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "579f828489659d7b3430f4bd9b67b4618b387dea"
+ "reference": "aeda215d6b01f119508c090d2a09ebb5b0bc61f3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/579f828489659d7b3430f4bd9b67b4618b387dea",
- "reference": "579f828489659d7b3430f4bd9b67b4618b387dea",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aeda215d6b01f119508c090d2a09ebb5b0bc61f3",
+ "reference": "aeda215d6b01f119508c090d2a09ebb5b0bc61f3",
"shasum": ""
},
"require": {
@@ -2375,7 +2530,7 @@
"psr/log": "~1.0",
"symfony/debug": "~2.8|~3.0",
"symfony/event-dispatcher": "~2.8|~3.0",
- "symfony/http-foundation": "~2.8|~3.0"
+ "symfony/http-foundation": "~2.8.8|~3.0.8|~3.1.2|~3.2"
},
"conflict": {
"symfony/config": "<2.8"
@@ -2409,7 +2564,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -2436,20 +2591,20 @@
],
"description": "Symfony HttpKernel Component",
"homepage": "https://symfony.com",
- "time": "2016-03-25 01:41:20"
+ "time": "2016-09-03 15:28:24"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.1.1",
+ "version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "1289d16209491b584839022f29257ad859b8532d"
+ "reference": "dff51f72b0706335131b00a7f49606168c582594"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d",
- "reference": "1289d16209491b584839022f29257ad859b8532d",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
+ "reference": "dff51f72b0706335131b00a7f49606168c582594",
"shasum": ""
},
"require": {
@@ -2461,7 +2616,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.1-dev"
+ "dev-master": "1.2-dev"
}
},
"autoload": {
@@ -2495,20 +2650,20 @@
"portable",
"shim"
],
- "time": "2016-01-20 09:13:37"
+ "time": "2016-05-18 14:26:46"
},
{
"name": "symfony/polyfill-php56",
- "version": "v1.1.1",
+ "version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php56.git",
- "reference": "4d891fff050101a53a4caabb03277284942d1ad9"
+ "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/4d891fff050101a53a4caabb03277284942d1ad9",
- "reference": "4d891fff050101a53a4caabb03277284942d1ad9",
+ "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/3edf57a8fbf9a927533344cef65ad7e1cf31030a",
+ "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a",
"shasum": ""
},
"require": {
@@ -2518,7 +2673,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.1-dev"
+ "dev-master": "1.2-dev"
}
},
"autoload": {
@@ -2551,20 +2706,20 @@
"portable",
"shim"
],
- "time": "2016-01-20 09:13:37"
+ "time": "2016-05-18 14:26:46"
},
{
"name": "symfony/polyfill-util",
- "version": "v1.1.1",
+ "version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-util.git",
- "reference": "8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4"
+ "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4",
- "reference": "8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4",
+ "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/ef830ce3d218e622b221d6bfad42c751d974bf99",
+ "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99",
"shasum": ""
},
"require": {
@@ -2573,7 +2728,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.1-dev"
+ "dev-master": "1.2-dev"
}
},
"autoload": {
@@ -2603,20 +2758,20 @@
"polyfill",
"shim"
],
- "time": "2016-01-20 09:13:37"
+ "time": "2016-05-18 14:26:46"
},
{
"name": "symfony/process",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "e6f1f98bbd355d209a992bfff45e7edfbd4a0776"
+ "reference": "e64e93041c80e77197ace5ab9385dedb5a143697"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/e6f1f98bbd355d209a992bfff45e7edfbd4a0776",
- "reference": "e6f1f98bbd355d209a992bfff45e7edfbd4a0776",
+ "url": "https://api.github.com/repos/symfony/process/zipball/e64e93041c80e77197ace5ab9385dedb5a143697",
+ "reference": "e64e93041c80e77197ace5ab9385dedb5a143697",
"shasum": ""
},
"require": {
@@ -2625,7 +2780,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -2652,20 +2807,20 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
- "time": "2016-03-30 10:41:14"
+ "time": "2016-08-16 14:58:24"
},
{
"name": "symfony/routing",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
- "reference": "d061b609f2d0769494c381ec92f5c5cc5e4a20aa"
+ "reference": "8edf62498a1a4c57ba317664a4b698339c10cdf6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/routing/zipball/d061b609f2d0769494c381ec92f5c5cc5e4a20aa",
- "reference": "d061b609f2d0769494c381ec92f5c5cc5e4a20aa",
+ "url": "https://api.github.com/repos/symfony/routing/zipball/8edf62498a1a4c57ba317664a4b698339c10cdf6",
+ "reference": "8edf62498a1a4c57ba317664a4b698339c10cdf6",
"shasum": ""
},
"require": {
@@ -2694,7 +2849,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -2727,20 +2882,20 @@
"uri",
"url"
],
- "time": "2016-03-23 13:23:25"
+ "time": "2016-08-16 14:58:24"
},
{
"name": "symfony/translation",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
- "reference": "f7a07af51ea067745a521dab1e3152044a2fb1f2"
+ "reference": "a35edc277513c9bc0f063ca174c36b346f974528"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation/zipball/f7a07af51ea067745a521dab1e3152044a2fb1f2",
- "reference": "f7a07af51ea067745a521dab1e3152044a2fb1f2",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/a35edc277513c9bc0f063ca174c36b346f974528",
+ "reference": "a35edc277513c9bc0f063ca174c36b346f974528",
"shasum": ""
},
"require": {
@@ -2764,7 +2919,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -2791,20 +2946,20 @@
],
"description": "Symfony Translation Component",
"homepage": "https://symfony.com",
- "time": "2016-03-25 01:41:20"
+ "time": "2016-08-05 08:37:39"
},
{
"name": "symfony/var-dumper",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
- "reference": "3841ed86527d18ee2c35fe4afb1b2fc60f8fae79"
+ "reference": "62ee73706c421654a4c840028954510277f7dfc8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3841ed86527d18ee2c35fe4afb1b2fc60f8fae79",
- "reference": "3841ed86527d18ee2c35fe4afb1b2fc60f8fae79",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/62ee73706c421654a4c840028954510277f7dfc8",
+ "reference": "62ee73706c421654a4c840028954510277f7dfc8",
"shasum": ""
},
"require": {
@@ -2820,7 +2975,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -2854,32 +3009,32 @@
"debug",
"dump"
],
- "time": "2016-03-10 10:34:12"
+ "time": "2016-08-31 09:05:42"
},
{
"name": "vlucas/phpdotenv",
- "version": "v2.2.0",
+ "version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/vlucas/phpdotenv.git",
- "reference": "9caf304153dc2288e4970caec6f1f3b3bc205412"
+ "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/9caf304153dc2288e4970caec6f1f3b3bc205412",
- "reference": "9caf304153dc2288e4970caec6f1f3b3bc205412",
+ "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c",
+ "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
- "phpunit/phpunit": "^4.8|^5.0"
+ "phpunit/phpunit": "^4.8 || ^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.2-dev"
+ "dev-master": "2.4-dev"
}
},
"autoload": {
@@ -2889,7 +3044,7 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD"
+ "BSD-3-Clause-Attribution"
],
"authors": [
{
@@ -2899,13 +3054,12 @@
}
],
"description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
- "homepage": "http://github.com/vlucas/phpdotenv",
"keywords": [
"dotenv",
"env",
"environment"
],
- "time": "2015-12-29 15:10:30"
+ "time": "2016-09-01 10:05:43"
}
],
"packages-dev": [
@@ -2965,33 +3119,29 @@
},
{
"name": "fzaninotto/faker",
- "version": "v1.5.0",
+ "version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/fzaninotto/Faker.git",
- "reference": "d0190b156bcca848d401fb80f31f504f37141c8d"
+ "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/d0190b156bcca848d401fb80f31f504f37141c8d",
- "reference": "d0190b156bcca848d401fb80f31f504f37141c8d",
+ "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/44f9a286a04b80c76a4e5fb7aad8bb539b920123",
+ "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": "^5.3.3|^7.0"
},
"require-dev": {
+ "ext-intl": "*",
"phpunit/phpunit": "~4.0",
"squizlabs/php_codesniffer": "~1.5"
},
- "suggest": {
- "ext-intl": "*"
- },
"type": "library",
"extra": {
- "branch-alias": {
- "dev-master": "1.5.x-dev"
- }
+ "branch-alias": []
},
"autoload": {
"psr-4": {
@@ -3013,7 +3163,7 @@
"faker",
"fixtures"
],
- "time": "2015-05-29 06:29:14"
+ "time": "2016-04-29 12:21:54"
},
{
"name": "hamcrest/hamcrest-php",
@@ -3062,16 +3212,16 @@
},
{
"name": "mockery/mockery",
- "version": "0.9.4",
+ "version": "0.9.5",
"source": {
"type": "git",
"url": "https://github.com/padraic/mockery.git",
- "reference": "70bba85e4aabc9449626651f48b9018ede04f86b"
+ "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/padraic/mockery/zipball/70bba85e4aabc9449626651f48b9018ede04f86b",
- "reference": "70bba85e4aabc9449626651f48b9018ede04f86b",
+ "url": "https://api.github.com/repos/padraic/mockery/zipball/4db079511a283e5aba1b3c2fb19037c645e70fc2",
+ "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2",
"shasum": ""
},
"require": {
@@ -3123,90 +3273,81 @@
"test double",
"testing"
],
- "time": "2015-04-02 19:54:00"
+ "time": "2016-05-22 21:52:33"
},
{
- "name": "phpspec/php-diff",
- "version": "v1.0.2",
+ "name": "myclabs/deep-copy",
+ "version": "1.5.4",
"source": {
"type": "git",
- "url": "https://github.com/phpspec/php-diff.git",
- "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a"
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/php-diff/zipball/30e103d19519fe678ae64a60d77884ef3d71b28a",
- "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/ea74994a3dc7f8d2f65a06009348f2d63c81e61f",
+ "reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f",
"shasum": ""
},
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "doctrine/collections": "1.*",
+ "phpunit/phpunit": "~4.1"
+ },
"type": "library",
"autoload": {
- "psr-0": {
- "Diff": "lib/"
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
- "authors": [
- {
- "name": "Chris Boulton",
- "homepage": "http://github.com/chrisboulton",
- "role": "Original developer"
- }
+ "description": "Create deep copies (clones) of your objects",
+ "homepage": "https://github.com/myclabs/DeepCopy",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
],
- "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).",
- "time": "2013-11-01 13:02:21"
+ "time": "2016-09-16 13:37:59"
},
{
- "name": "phpspec/phpspec",
- "version": "2.5.0",
+ "name": "phpdocumentor/reflection-common",
+ "version": "1.0",
"source": {
"type": "git",
- "url": "https://github.com/phpspec/phpspec.git",
- "reference": "385ecb015e97c13818074f1517928b24d4a26067"
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+ "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/phpspec/zipball/385ecb015e97c13818074f1517928b24d4a26067",
- "reference": "385ecb015e97c13818074f1517928b24d4a26067",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
+ "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
"shasum": ""
},
"require": {
- "doctrine/instantiator": "^1.0.1",
- "ext-tokenizer": "*",
- "php": ">=5.3.3",
- "phpspec/php-diff": "~1.0.0",
- "phpspec/prophecy": "~1.4",
- "sebastian/exporter": "~1.0",
- "symfony/console": "~2.3|~3.0",
- "symfony/event-dispatcher": "~2.1|~3.0",
- "symfony/finder": "~2.1|~3.0",
- "symfony/process": "^2.6|~3.0",
- "symfony/yaml": "~2.1|~3.0"
+ "php": ">=5.5"
},
"require-dev": {
- "behat/behat": "^3.0.11",
- "bossa/phpspec2-expect": "~1.0",
- "phpunit/phpunit": "~4.4",
- "symfony/filesystem": "~2.1|~3.0"
+ "phpunit/phpunit": "^4.6"
},
- "suggest": {
- "phpspec/nyan-formatters": "~1.0 – Adds Nyan formatters"
- },
- "bin": [
- "bin/phpspec"
- ],
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.2.x-dev"
+ "dev-master": "1.0.x-dev"
}
},
"autoload": {
- "psr-0": {
- "PhpSpec": "src/"
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": [
+ "src"
+ ]
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -3215,56 +3356,141 @@
],
"authors": [
{
- "name": "Konstantin Kudryashov",
- "email": "ever.zet@gmail.com",
- "homepage": "http://everzet.com"
- },
- {
- "name": "Marcello Duarte",
- "homepage": "http://marcelloduarte.net/"
+ "name": "Jaap van Otterdijk",
+ "email": "opensource@ijaap.nl"
}
],
- "description": "Specification-oriented BDD framework for PHP 5.3+",
- "homepage": "http://phpspec.net/",
+ "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+ "homepage": "http://www.phpdoc.org",
"keywords": [
- "BDD",
- "SpecBDD",
- "TDD",
- "spec",
- "specification",
- "testing",
- "tests"
+ "FQSEN",
+ "phpDocumentor",
+ "phpdoc",
+ "reflection",
+ "static analysis"
],
- "time": "2016-03-20 20:34:32"
+ "time": "2015-12-27 11:43:31"
},
{
- "name": "phpspec/prophecy",
- "version": "v1.6.0",
+ "name": "phpdocumentor/reflection-docblock",
+ "version": "3.1.0",
"source": {
"type": "git",
- "url": "https://github.com/phpspec/prophecy.git",
- "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+ "reference": "9270140b940ff02e58ec577c237274e92cd40cdd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
- "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd",
+ "reference": "9270140b940ff02e58ec577c237274e92cd40cdd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5",
+ "phpdocumentor/reflection-common": "^1.0@dev",
+ "phpdocumentor/type-resolver": "^0.2.0",
+ "webmozart/assert": "^1.0"
+ },
+ "require-dev": {
+ "mockery/mockery": "^0.9.4",
+ "phpunit/phpunit": "^4.4"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+ "time": "2016-06-10 09:48:41"
+ },
+ {
+ "name": "phpdocumentor/type-resolver",
+ "version": "0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/TypeResolver.git",
+ "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443",
+ "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5",
+ "phpdocumentor/reflection-common": "^1.0"
+ },
+ "require-dev": {
+ "mockery/mockery": "^0.9.4",
+ "phpunit/phpunit": "^5.2||^4.8.24"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "time": "2016-06-10 07:14:17"
+ },
+ {
+ "name": "phpspec/prophecy",
+ "version": "v1.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpspec/prophecy.git",
+ "reference": "58a8137754bc24b25740d4281399a4a3596058e0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0",
+ "reference": "58a8137754bc24b25740d4281399a4a3596058e0",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
- "phpdocumentor/reflection-docblock": "~2.0",
- "sebastian/comparator": "~1.1",
- "sebastian/recursion-context": "~1.0"
+ "phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
+ "sebastian/comparator": "^1.1",
+ "sebastian/recursion-context": "^1.0"
},
"require-dev": {
- "phpspec/phpspec": "~2.0"
+ "phpspec/phpspec": "^2.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.5.x-dev"
+ "dev-master": "1.6.x-dev"
}
},
"autoload": {
@@ -3297,43 +3523,44 @@
"spy",
"stub"
],
- "time": "2016-02-15 07:46:21"
+ "time": "2016-06-07 08:13:47"
},
{
"name": "phpunit/php-code-coverage",
- "version": "2.2.4",
+ "version": "4.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
+ "reference": "5f3f7e736d6319d5f1fc402aff8b026da26709a3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
- "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5f3f7e736d6319d5f1fc402aff8b026da26709a3",
+ "reference": "5f3f7e736d6319d5f1fc402aff8b026da26709a3",
"shasum": ""
},
"require": {
- "php": ">=5.3.3",
+ "php": "^5.6 || ^7.0",
"phpunit/php-file-iterator": "~1.3",
"phpunit/php-text-template": "~1.2",
- "phpunit/php-token-stream": "~1.3",
- "sebastian/environment": "^1.3.2",
- "sebastian/version": "~1.0"
+ "phpunit/php-token-stream": "^1.4.2",
+ "sebastian/code-unit-reverse-lookup": "~1.0",
+ "sebastian/environment": "^1.3.2 || ^2.0",
+ "sebastian/version": "~1.0|~2.0"
},
"require-dev": {
"ext-xdebug": ">=2.1.4",
- "phpunit/phpunit": "~4"
+ "phpunit/phpunit": "^5.4"
},
"suggest": {
"ext-dom": "*",
- "ext-xdebug": ">=2.2.1",
+ "ext-xdebug": ">=2.4.0",
"ext-xmlwriter": "*"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.2.x-dev"
+ "dev-master": "4.0.x-dev"
}
},
"autoload": {
@@ -3359,7 +3586,7 @@
"testing",
"xunit"
],
- "time": "2015-10-06 15:47:00"
+ "time": "2016-07-26 14:39:29"
},
{
"name": "phpunit/php-file-iterator",
@@ -3451,21 +3678,24 @@
},
{
"name": "phpunit/php-timer",
- "version": "1.0.7",
+ "version": "1.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b"
+ "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
- "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260",
+ "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
+ "require-dev": {
+ "phpunit/phpunit": "~4|~5"
+ },
"type": "library",
"autoload": {
"classmap": [
@@ -3488,7 +3718,7 @@
"keywords": [
"timer"
],
- "time": "2015-06-21 08:01:12"
+ "time": "2016-05-12 18:03:57"
},
{
"name": "phpunit/php-token-stream",
@@ -3541,40 +3771,51 @@
},
{
"name": "phpunit/phpunit",
- "version": "4.8.24",
+ "version": "5.5.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "a1066c562c52900a142a0e2bbf0582994671385e"
+ "reference": "a57126dc681b08289fef6ac96a48e30656f84350"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1066c562c52900a142a0e2bbf0582994671385e",
- "reference": "a1066c562c52900a142a0e2bbf0582994671385e",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a57126dc681b08289fef6ac96a48e30656f84350",
+ "reference": "a57126dc681b08289fef6ac96a48e30656f84350",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-json": "*",
- "ext-pcre": "*",
- "ext-reflection": "*",
- "ext-spl": "*",
- "php": ">=5.3.3",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "myclabs/deep-copy": "~1.3",
+ "php": "^5.6 || ^7.0",
"phpspec/prophecy": "^1.3.1",
- "phpunit/php-code-coverage": "~2.1",
+ "phpunit/php-code-coverage": "^4.0.1",
"phpunit/php-file-iterator": "~1.4",
"phpunit/php-text-template": "~1.2",
- "phpunit/php-timer": ">=1.0.6",
- "phpunit/phpunit-mock-objects": "~2.3",
+ "phpunit/php-timer": "^1.0.6",
+ "phpunit/phpunit-mock-objects": "^3.2",
"sebastian/comparator": "~1.1",
"sebastian/diff": "~1.2",
- "sebastian/environment": "~1.3",
+ "sebastian/environment": "^1.3 || ^2.0",
"sebastian/exporter": "~1.2",
"sebastian/global-state": "~1.0",
- "sebastian/version": "~1.0",
+ "sebastian/object-enumerator": "~1.0",
+ "sebastian/resource-operations": "~1.0",
+ "sebastian/version": "~1.0|~2.0",
"symfony/yaml": "~2.1|~3.0"
},
+ "conflict": {
+ "phpdocumentor/reflection-docblock": "3.0.2"
+ },
+ "require-dev": {
+ "ext-pdo": "*"
+ },
"suggest": {
+ "ext-tidy": "*",
+ "ext-xdebug": "*",
"phpunit/php-invoker": "~1.1"
},
"bin": [
@@ -3583,7 +3824,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.8.x-dev"
+ "dev-master": "5.5.x-dev"
}
},
"autoload": {
@@ -3609,30 +3850,33 @@
"testing",
"xunit"
],
- "time": "2016-03-14 06:16:08"
+ "time": "2016-09-21 14:40:13"
},
{
"name": "phpunit/phpunit-mock-objects",
- "version": "2.3.8",
+ "version": "3.2.7",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
- "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
+ "reference": "546898a2c0c356ef2891b39dd7d07f5d82c8ed0a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
- "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/546898a2c0c356ef2891b39dd7d07f5d82c8ed0a",
+ "reference": "546898a2c0c356ef2891b39dd7d07f5d82c8ed0a",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
- "php": ">=5.3.3",
- "phpunit/php-text-template": "~1.2",
- "sebastian/exporter": "~1.2"
+ "php": "^5.6 || ^7.0",
+ "phpunit/php-text-template": "^1.2",
+ "sebastian/exporter": "^1.2"
+ },
+ "conflict": {
+ "phpunit/phpunit": "<5.4.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.4"
+ "phpunit/phpunit": "^5.4"
},
"suggest": {
"ext-soap": "*"
@@ -3640,7 +3884,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3.x-dev"
+ "dev-master": "3.2.x-dev"
}
},
"autoload": {
@@ -3665,7 +3909,52 @@
"mock",
"xunit"
],
- "time": "2015-10-02 06:51:40"
+ "time": "2016-09-06 16:07:45"
+ },
+ {
+ "name": "sebastian/code-unit-reverse-lookup",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+ "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/c36f5e7cfce482fde5bf8d10d41a53591e0198fe",
+ "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Looks up which function or method a line of code belongs to",
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "time": "2016-02-13 06:45:14"
},
{
"name": "sebastian/comparator",
@@ -3785,23 +4074,23 @@
},
{
"name": "sebastian/environment",
- "version": "1.3.5",
+ "version": "1.3.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf"
+ "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
- "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
+ "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": "^5.3.3 || ^7.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.4"
+ "phpunit/phpunit": "^4.8 || ^5.0"
},
"type": "library",
"extra": {
@@ -3831,20 +4120,20 @@
"environment",
"hhvm"
],
- "time": "2016-02-26 18:40:46"
+ "time": "2016-08-18 05:49:44"
},
{
"name": "sebastian/exporter",
- "version": "1.2.1",
+ "version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "7ae5513327cb536431847bcc0c10edba2701064e"
+ "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e",
- "reference": "7ae5513327cb536431847bcc0c10edba2701064e",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
+ "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
"shasum": ""
},
"require": {
@@ -3852,12 +4141,13 @@
"sebastian/recursion-context": "~1.0"
},
"require-dev": {
+ "ext-mbstring": "*",
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.2.x-dev"
+ "dev-master": "1.3.x-dev"
}
},
"autoload": {
@@ -3897,7 +4187,7 @@
"export",
"exporter"
],
- "time": "2015-06-21 07:55:53"
+ "time": "2016-06-17 09:04:28"
},
{
"name": "sebastian/global-state",
@@ -3950,6 +4240,52 @@
],
"time": "2015-10-12 03:26:01"
},
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "d4ca2fb70344987502567bc50081c03e6192fb26"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26",
+ "reference": "d4ca2fb70344987502567bc50081c03e6192fb26",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6",
+ "sebastian/recursion-context": "~1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "time": "2016-01-28 13:25:10"
+ },
{
"name": "sebastian/recursion-context",
"version": "1.0.2",
@@ -4004,20 +4340,70 @@
"time": "2015-11-11 19:50:13"
},
{
- "name": "sebastian/version",
- "version": "1.0.6",
+ "name": "sebastian/resource-operations",
+ "version": "1.0.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/version.git",
- "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
+ "url": "https://github.com/sebastianbergmann/resource-operations.git",
+ "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
- "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+ "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
+ "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
"shasum": ""
},
+ "require": {
+ "php": ">=5.6.0"
+ },
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides a list of PHP built-in functions that operate on resources",
+ "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+ "time": "2015-07-28 20:34:47"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5",
+ "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
"autoload": {
"classmap": [
"src/"
@@ -4036,20 +4422,20 @@
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
- "time": "2015-06-21 13:59:46"
+ "time": "2016-02-04 12:56:52"
},
{
"name": "symfony/css-selector",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
- "reference": "65e764f404685f2dc20c057e889b3ad04b2e2db0"
+ "reference": "2851e1932d77ce727776154d659b232d061e816a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/css-selector/zipball/65e764f404685f2dc20c057e889b3ad04b2e2db0",
- "reference": "65e764f404685f2dc20c057e889b3ad04b2e2db0",
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/2851e1932d77ce727776154d659b232d061e816a",
+ "reference": "2851e1932d77ce727776154d659b232d061e816a",
"shasum": ""
},
"require": {
@@ -4058,7 +4444,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -4089,20 +4475,20 @@
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
- "time": "2016-03-04 07:55:57"
+ "time": "2016-06-29 05:41:56"
},
{
"name": "symfony/dom-crawler",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
- "reference": "18a06d7a9af41718c20764a674a0ebba3bc40d1f"
+ "reference": "bb7395e8b1db3654de82b9f35d019958276de4d7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/18a06d7a9af41718c20764a674a0ebba3bc40d1f",
- "reference": "18a06d7a9af41718c20764a674a0ebba3bc40d1f",
+ "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/bb7395e8b1db3654de82b9f35d019958276de4d7",
+ "reference": "bb7395e8b1db3654de82b9f35d019958276de4d7",
"shasum": ""
},
"require": {
@@ -4118,7 +4504,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -4145,20 +4531,20 @@
],
"description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com",
- "time": "2016-03-23 13:23:25"
+ "time": "2016-08-05 08:37:39"
},
{
"name": "symfony/yaml",
- "version": "v3.0.4",
+ "version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "0047c8366744a16de7516622c5b7355336afae96"
+ "reference": "f291ed25eb1435bddbe8a96caaef16469c2a092d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/0047c8366744a16de7516622c5b7355336afae96",
- "reference": "0047c8366744a16de7516622c5b7355336afae96",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/f291ed25eb1435bddbe8a96caaef16469c2a092d",
+ "reference": "f291ed25eb1435bddbe8a96caaef16469c2a092d",
"shasum": ""
},
"require": {
@@ -4167,7 +4553,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -4194,7 +4580,57 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
- "time": "2016-03-04 07:55:57"
+ "time": "2016-09-02 02:12:52"
+ },
+ {
+ "name": "webmozart/assert",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webmozart/assert.git",
+ "reference": "bb2d123231c095735130cc8f6d31385a44c7b308"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308",
+ "reference": "bb2d123231c095735130cc8f6d31385a44c7b308",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3|^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.6",
+ "sebastian/version": "^1.0.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.2-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Webmozart\\Assert\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Assertions to validate method input/output with nice error messages.",
+ "keywords": [
+ "assert",
+ "check",
+ "validate"
+ ],
+ "time": "2016-08-09 15:02:57"
}
],
"aliases": [],
@@ -4203,7 +4639,8 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": ">=5.5.9"
+ "php": ">=5.6.4",
+ "ext-tidy": "*"
},
"platform-dev": []
}
diff --git a/config/app.php b/config/app.php
index 0d6f6f2b0..786f005ac 100644
--- a/config/app.php
+++ b/config/app.php
@@ -57,7 +57,7 @@ return [
|
*/
- 'locale' => 'en',
+ 'locale' => env('APP_LANG', 'en'),
/*
|--------------------------------------------------------------------------
@@ -138,6 +138,7 @@ return [
Illuminate\Translation\TranslationServiceProvider::class,
Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class,
+ Illuminate\Notifications\NotificationServiceProvider::class,
Laravel\Socialite\SocialiteServiceProvider::class,
/**
@@ -156,6 +157,7 @@ return [
BookStack\Providers\AuthServiceProvider::class,
BookStack\Providers\AppServiceProvider::class,
+ BookStack\Providers\BroadcastServiceProvider::class,
BookStack\Providers\EventServiceProvider::class,
BookStack\Providers\RouteServiceProvider::class,
BookStack\Providers\CustomFacadeProvider::class,
@@ -194,6 +196,7 @@ return [
'Lang' => Illuminate\Support\Facades\Lang::class,
'Log' => Illuminate\Support\Facades\Log::class,
'Mail' => Illuminate\Support\Facades\Mail::class,
+ 'Notification' => Illuminate\Support\Facades\Notification::class,
'Password' => Illuminate\Support\Facades\Password::class,
'Queue' => Illuminate\Support\Facades\Queue::class,
'Redirect' => Illuminate\Support\Facades\Redirect::class,
diff --git a/config/filesystems.php b/config/filesystems.php
index dbcb03db1..836f68d3d 100644
--- a/config/filesystems.php
+++ b/config/filesystems.php
@@ -56,7 +56,7 @@ return [
'local' => [
'driver' => 'local',
- 'root' => public_path(),
+ 'root' => base_path(),
],
'ftp' => [
diff --git a/config/setting-defaults.php b/config/setting-defaults.php
index deafceb29..c681bb7f5 100644
--- a/config/setting-defaults.php
+++ b/config/setting-defaults.php
@@ -6,6 +6,7 @@
return [
'app-name' => 'BookStack',
+ 'app-name-header' => true,
'app-editor' => 'wysiwyg',
'app-color' => '#0288D1',
'app-color-light' => 'rgba(21, 101, 192, 0.15)',
diff --git a/database/migrations/2015_08_29_105422_add_roles_and_permissions.php b/database/migrations/2015_08_29_105422_add_roles_and_permissions.php
index 763a33fec..47a77e29f 100644
--- a/database/migrations/2015_08_29_105422_add_roles_and_permissions.php
+++ b/database/migrations/2015_08_29_105422_add_roles_and_permissions.php
@@ -129,7 +129,7 @@ class AddRolesAndPermissions extends Migration
// Set all current users as admins
// (At this point only the initially create user should be an admin)
- $users = DB::table('users')->get();
+ $users = DB::table('users')->get()->all();
foreach ($users as $user) {
DB::table('role_user')->insert([
'role_id' => $adminId,
diff --git a/database/migrations/2016_09_29_101449_remove_hidden_roles.php b/database/migrations/2016_09_29_101449_remove_hidden_roles.php
new file mode 100644
index 000000000..f666cad2c
--- /dev/null
+++ b/database/migrations/2016_09_29_101449_remove_hidden_roles.php
@@ -0,0 +1,66 @@
+dropColumn('hidden');
+ });
+
+ // Add column to mark system users
+ Schema::table('users', function(Blueprint $table) {
+ $table->string('system_name')->nullable()->index();
+ });
+
+ // Insert our new public system user.
+ $publicUserId = DB::table('users')->insertGetId([
+ 'email' => 'guest@example.com',
+ 'name' => 'Guest',
+ 'system_name' => 'public',
+ 'email_confirmed' => true,
+ 'created_at' => \Carbon\Carbon::now(),
+ 'updated_at' => \Carbon\Carbon::now(),
+ ]);
+
+ // Get the public role
+ $publicRole = DB::table('roles')->where('system_name', '=', 'public')->first();
+
+ // Connect the new public user to the public role
+ DB::table('role_user')->insert([
+ 'user_id' => $publicUserId,
+ 'role_id' => $publicRole->id
+ ]);
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('roles', function(Blueprint $table) {
+ $table->boolean('hidden')->default(false);
+ $table->index('hidden');
+ });
+
+ DB::table('users')->where('system_name', '=', 'public')->delete();
+
+ Schema::table('users', function(Blueprint $table) {
+ $table->dropColumn('system_name');
+ });
+
+ DB::table('roles')->where('system_name', '=', 'public')->update(['hidden' => true]);
+ }
+}
diff --git a/database/migrations/2016_10_09_142037_create_attachments_table.php b/database/migrations/2016_10_09_142037_create_attachments_table.php
new file mode 100644
index 000000000..627c237c4
--- /dev/null
+++ b/database/migrations/2016_10_09_142037_create_attachments_table.php
@@ -0,0 +1,71 @@
+increments('id');
+ $table->string('name');
+ $table->string('path');
+ $table->string('extension', 20);
+ $table->integer('uploaded_to');
+
+ $table->boolean('external');
+ $table->integer('order');
+
+ $table->integer('created_by');
+ $table->integer('updated_by');
+
+ $table->index('uploaded_to');
+ $table->timestamps();
+ });
+
+ // Get roles with permissions we need to change
+ $adminRoleId = DB::table('roles')->where('system_name', '=', 'admin')->first()->id;
+
+ // Create & attach new entity permissions
+ $ops = ['Create All', 'Create Own', 'Update All', 'Update Own', 'Delete All', 'Delete Own'];
+ $entity = 'Attachment';
+ foreach ($ops as $op) {
+ $permissionId = DB::table('role_permissions')->insertGetId([
+ 'name' => strtolower($entity) . '-' . strtolower(str_replace(' ', '-', $op)),
+ 'display_name' => $op . ' ' . $entity . 's',
+ 'created_at' => \Carbon\Carbon::now()->toDateTimeString(),
+ 'updated_at' => \Carbon\Carbon::now()->toDateTimeString()
+ ]);
+ DB::table('permission_role')->insert([
+ 'role_id' => $adminRoleId,
+ 'permission_id' => $permissionId
+ ]);
+ }
+
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('attachments');
+
+ // Create & attach new entity permissions
+ $ops = ['Create All', 'Create Own', 'Update All', 'Update Own', 'Delete All', 'Delete Own'];
+ $entity = 'Attachment';
+ foreach ($ops as $op) {
+ $permName = strtolower($entity) . '-' . strtolower(str_replace(' ', '-', $op));
+ DB::table('role_permissions')->where('name', '=', $permName)->delete();
+ }
+ }
+}
diff --git a/gulpfile.js b/gulpfile.js
index 7deefc71a..9d789d9b4 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -1,27 +1,8 @@
var elixir = require('laravel-elixir');
-// Custom extensions
-var gulp = require('gulp');
-var Task = elixir.Task;
-var fs = require('fs');
-
-elixir.extend('queryVersion', function(inputFiles) {
- new Task('queryVersion', function() {
- var manifestObject = {};
- var uidString = Date.now().toString(16).slice(4);
- for (var i = 0; i < inputFiles.length; i++) {
- var file = inputFiles[i];
- manifestObject[file] = file + '?version=' + uidString;
- }
- var fileContents = JSON.stringify(manifestObject, null, 1);
- fs.writeFileSync('public/build/manifest.json', fileContents);
- }).watch(['./public/css/*.css', './public/js/*.js']);
-});
-
-elixir(function(mix) {
- mix.sass('styles.scss')
- .sass('print-styles.scss')
- .sass('export-styles.scss')
- .browserify('global.js', 'public/js/common.js')
- .queryVersion(['css/styles.css', 'css/print-styles.css', 'js/common.js']);
+elixir(mix => {
+ mix.sass('styles.scss');
+ mix.sass('print-styles.scss');
+ mix.sass('export-styles.scss');
+ mix.browserify('global.js', './public/js/common.js');
});
diff --git a/package.json b/package.json
index fde090beb..30f288d45 100644
--- a/package.json
+++ b/package.json
@@ -1,18 +1,19 @@
{
"private": true,
- "devDependencies": {
- "gulp": "^3.9.0"
+ "scripts": {
+ "prod": "gulp --production",
+ "dev": "gulp watch"
},
- "dependencies": {
+ "devDependencies": {
"angular": "^1.5.5",
"angular-animate": "^1.5.5",
"angular-resource": "^1.5.5",
"angular-sanitize": "^1.5.5",
- "angular-ui-sortable": "^0.14.0",
- "babel-runtime": "^5.8.29",
- "bootstrap-sass": "^3.0.0",
+ "angular-ui-sortable": "^0.15.0",
"dropzone": "^4.0.1",
- "laravel-elixir": "^5.0.0",
+ "gulp": "^3.9.0",
+ "laravel-elixir": "^6.0.0-11",
+ "laravel-elixir-browserify-official": "^0.1.3",
"marked": "^0.3.5",
"moment": "^2.12.0",
"zeroclipboard": "^2.2.0"
diff --git a/phpspec.yml b/phpspec.yml
deleted file mode 100644
index 58f1d982e..000000000
--- a/phpspec.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-suites:
- main:
- namespace: BookStack
- psr4_prefix: BookStack
- src_path: app
\ No newline at end of file
diff --git a/phpunit.xml b/phpunit.xml
index a2b26d413..72e06a3fc 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -30,6 +30,7 @@
{!! $book->searchSnippet !!}
@else diff --git a/resources/views/chapters/list-item.blade.php b/resources/views/chapters/list-item.blade.php index 35d3a7589..f70e59244 100644 --- a/resources/views/chapters/list-item.blade.php +++ b/resources/views/chapters/list-item.blade.php @@ -1,5 +1,5 @@{!! $chapter->searchSnippet !!}
@else @@ -20,7 +20,7 @@{{ count($chapter->pages) }} Pages
- |
-
-
-
-
-
|
- - |
|
Upload some files or attach some link to display on your page. These are visible in the page sidebar. Changes here are saved instantly.
+ ++ |
+
+
+ Click delete again to confirm you want to delete this attachment.
+
+ + Cancel + |
+ + | + | + |
+ No files have been uploaded. +
+You can attach a link if you'd prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.
+This user represents any guest users that visit your instance. It cannot be used for logins but is assigned automatically.
+@endif + +
+
|
+