]> BookStack Code Mirror - bookstack/commitdiff
Merge pull request #1 from ssddanbrown/master
authorAbijeet Patro <redacted>
Sun, 25 Sep 2016 07:59:22 +0000 (13:29 +0530)
committerGitHub <redacted>
Sun, 25 Sep 2016 07:59:22 +0000 (13:29 +0530)
Getting the latest of BookStack.

63 files changed:
.gitignore
app/EmailConfirmation.php [deleted file]
app/Events/Event.php [deleted file]
app/Exceptions/Handler.php
app/Http/Controllers/Auth/ForgotPasswordController.php [new file with mode: 0644]
app/Http/Controllers/Auth/LoginController.php [new file with mode: 0644]
app/Http/Controllers/Auth/RegisterController.php [moved from app/Http/Controllers/Auth/AuthController.php with 66% similarity]
app/Http/Controllers/Auth/ResetPasswordController.php [moved from app/Http/Controllers/Auth/PasswordController.php with 82% similarity]
app/Http/Controllers/Controller.php
app/Http/Controllers/PageController.php
app/Http/Controllers/UserController.php
app/Http/Kernel.php
app/Http/Middleware/Authenticate.php
app/Http/Middleware/RedirectIfAuthenticated.php
app/Jobs/Job.php [deleted file]
app/Listeners/.gitkeep [deleted file]
app/Notifications/ConfirmEmail.php [new file with mode: 0644]
app/Notifications/ResetPassword.php [new file with mode: 0644]
app/Providers/BroadcastServiceProvider.php [new file with mode: 0644]
app/Providers/EventServiceProvider.php
app/Providers/PaginationServiceProvider.php
app/Providers/RouteServiceProvider.php
app/Repos/PageRepo.php
app/Repos/UserRepo.php
app/Services/EmailConfirmationService.php
app/Services/ImageService.php
app/Services/PermissionService.php
app/User.php
app/helpers.php
composer.json
composer.lock
config/app.php
config/setting-defaults.php
database/migrations/2015_08_29_105422_add_roles_and_permissions.php
phpspec.yml [deleted file]
resources/assets/js/controllers.js
resources/assets/js/pages/page-form.js
resources/assets/sass/_lists.scss
resources/assets/sass/_text.scss
resources/lang/en/auth.php [new file with mode: 0644]
resources/lang/en/settings.php [new file with mode: 0644]
resources/views/auth/passwords/email.blade.php [moved from resources/views/auth/password.blade.php with 100% similarity]
resources/views/auth/passwords/reset.blade.php [moved from resources/views/auth/reset.blade.php with 100% similarity]
resources/views/base.blade.php
resources/views/books/list-item.blade.php
resources/views/chapters/list-item.blade.php
resources/views/emails/email-confirmation.blade.php [deleted file]
resources/views/emails/password.blade.php [deleted file]
resources/views/home.blade.php
resources/views/pages/list-item.blade.php
resources/views/pages/show.blade.php
resources/views/pages/sidebar-tree-list.blade.php
resources/views/public.blade.php
resources/views/settings/index.blade.php
resources/views/users/index.blade.php
resources/views/vendor/.gitkeep [deleted file]
resources/views/vendor/notifications/email-plain.blade.php [new file with mode: 0644]
resources/views/vendor/notifications/email.blade.php [new file with mode: 0644]
routes/web.php [moved from app/Http/routes.php with 84% similarity]
tests/Auth/AuthTest.php
tests/Entity/EntityTest.php
tests/Entity/PageDraftTest.php
tests/ImageTest.php

index 69f0e2909a00e186026d2f62c46286459d74e675..7417bbdd840a06f545974781e4e656673545c951 100644 (file)
@@ -10,4 +10,5 @@ Homestead.yaml
 /public/bower
 /storage/images
 _ide_helper.php
-/storage/debugbar
\ No newline at end of file
+/storage/debugbar
+.phpstorm.meta.php
\ No newline at end of file
diff --git a/app/EmailConfirmation.php b/app/EmailConfirmation.php
deleted file mode 100644 (file)
index e77b754..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php namespace BookStack;
-
-class EmailConfirmation extends Model
-{
-    protected $fillable = ['user_id', 'token'];
-
-    /**
-     * Get the user that this confirmation is attached to.
-     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
-     */
-    public function user()
-    {
-        return $this->belongsTo(User::class);
-    }
-    
-}
diff --git a/app/Events/Event.php b/app/Events/Event.php
deleted file mode 100644 (file)
index dfe1738..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?php
-
-namespace BookStack\Events;
-
-abstract class Event
-{
-    //
-}
index 57e807db0e14d20014ebf13dea9469cdce87ea43..c64f0cd1fc7941ac15bba50cb7d16b0ce1817d6c 100644 (file)
@@ -87,4 +87,20 @@ class Handler extends ExceptionHandler
         } while ($e = $e->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/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php
new file mode 100644 (file)
index 0000000..d93854e
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+namespace BookStack\Http\Controllers\Auth;
+
+use BookStack\Http\Controllers\Controller;
+use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
+
+class ForgotPasswordController extends Controller
+{
+    /*
+    |--------------------------------------------------------------------------
+    | Password Reset Controller
+    |--------------------------------------------------------------------------
+    |
+    | This controller is responsible for handling password reset emails and
+    | includes a trait which assists in sending these notifications from
+    | your application to your users. Feel free to explore this trait.
+    |
+    */
+
+    use SendsPasswordResetEmails;
+
+    /**
+     * Create a new controller instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        $this->middleware('guest');
+        parent::__construct();
+    }
+}
\ 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 (file)
index 0000000..0de4a82
--- /dev/null
@@ -0,0 +1,123 @@
+<?php
+
+namespace BookStack\Http\Controllers\Auth;
+
+use BookStack\Http\Controllers\Controller;
+use BookStack\Repos\UserRepo;
+use BookStack\Services\SocialAuthService;
+use Illuminate\Contracts\Auth\Authenticatable;
+use Illuminate\Foundation\Auth\AuthenticatesUsers;
+use Illuminate\Http\Request;
+
+class LoginController extends Controller
+{
+    /*
+    |--------------------------------------------------------------------------
+    | Login Controller
+    |--------------------------------------------------------------------------
+    |
+    | This controller handles authenticating users for the application and
+    | redirecting them to your home screen. The controller uses a trait
+    | to conveniently provide its functionality to your applications.
+    |
+    */
+
+    use AuthenticatesUsers;
+
+    /**
+     * Where to redirect users after login.
+     *
+     * @var string
+     */
+    protected $redirectTo = '/';
+
+    protected $redirectPath = '/';
+    protected $redirectAfterLogout = '/login';
+
+    protected $socialAuthService;
+    protected $userRepo;
+
+    /**
+     * Create a new controller instance.
+     *
+     * @param SocialAuthService $socialAuthService
+     * @param UserRepo $userRepo
+     */
+    public function __construct(SocialAuthService $socialAuthService, UserRepo $userRepo)
+    {
+        $this->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
similarity index 66%
rename from app/Http/Controllers/Auth/AuthController.php
rename to app/Http/Controllers/Auth/RegisterController.php
index f2d3b274108616163cf55413ff77be90bb0934b8..6bba6de045f8d371e3f5b5d92d59b093ddd90df5 100644 (file)
@@ -1,62 +1,68 @@
-<?php namespace BookStack\Http\Controllers\Auth;
+<?php
 
-use BookStack\Exceptions\AuthException;
-use Illuminate\Contracts\Auth\Authenticatable;
-use Illuminate\Http\Request;
-use BookStack\Exceptions\SocialSignInException;
+namespace BookStack\Http\Controllers\Auth;
+
+use BookStack\Exceptions\ConfirmationEmailException;
 use BookStack\Exceptions\UserRegistrationException;
 use BookStack\Repos\UserRepo;
 use BookStack\Services\EmailConfirmationService;
 use BookStack\Services\SocialAuthService;
-use BookStack\SocialAccount;
+use BookStack\User;
+use Exception;
+use Illuminate\Http\Request;
+use Illuminate\Http\Response;
 use Validator;
 use BookStack\Http\Controllers\Controller;
-use Illuminate\Foundation\Auth\ThrottlesLogins;
-use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
+use Illuminate\Foundation\Auth\RegistersUsers;
 
-class AuthController extends Controller
+class RegisterController extends Controller
 {
     /*
     |--------------------------------------------------------------------------
-    | Registration & Login Controller
+    | Register Controller
     |--------------------------------------------------------------------------
     |
-    | This controller handles the registration of new users, as well as the
-    | authentication of existing users. By default, this controller uses
-    | a simple trait to add these behaviors. Why don't you explore it?
+    | This controller handles the registration of new users as well as their
+    | validation and creation. By default this controller uses a trait to
+    | provide this functionality without requiring any additional code.
     |
     */
 
-    use AuthenticatesAndRegistersUsers, ThrottlesLogins;
-
-    protected $redirectPath = '/';
-    protected $redirectAfterLogout = '/login';
-    protected $username = 'email';
+    use RegistersUsers;
 
     protected $socialAuthService;
     protected $emailConfirmationService;
     protected $userRepo;
 
     /**
-     * Create a new authentication controller instance.
+     * Where to redirect users after login / registration.
+     *
+     * @var string
+     */
+    protected $redirectTo = '/';
+    protected $redirectPath = '/';
+
+    /**
+     * Create a new controller instance.
+     *
      * @param SocialAuthService $socialAuthService
      * @param EmailConfirmationService $emailConfirmationService
      * @param UserRepo $userRepo
      */
     public function __construct(SocialAuthService $socialAuthService, EmailConfirmationService $emailConfirmationService, UserRepo $userRepo)
     {
-        $this->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,31 +221,17 @@ class AuthController extends Controller
             'email' => 'required|email|exists:users,email'
         ]);
         $user = $this->userRepo->getByEmail($request->get('email'));
-        $this->emailConfirmationService->sendConfirmation($user);
-        session()->flash('success', 'Confirmation email resent, Please check your inbox.');
-        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]);
-    }
+        try {
+            $this->emailConfirmationService->sendConfirmation($user);
+        } catch (Exception $e) {
+            session()->flash('error', trans('auth.email_confirm_send_error'));
+            return redirect('/register/confirm');
+        }
 
-    /**
-     * 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);
+        $this->emailConfirmationService->sendConfirmation($user);
+        session()->flash('success', trans('auth.email_confirm_resent'));
+        return redirect('/register/confirm');
     }
 
     /**
@@ -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
similarity index 82%
rename from app/Http/Controllers/Auth/PasswordController.php
rename to app/Http/Controllers/Auth/ResetPasswordController.php
index 038e444d24fc446fe2fb1217324e2ad43761b972..656b8cc42418a63840fe2c32946100e952ee64f0 100644 (file)
@@ -5,7 +5,7 @@ namespace BookStack\Http\Controllers\Auth;
 use BookStack\Http\Controllers\Controller;
 use Illuminate\Foundation\Auth\ResetsPasswords;
 
-class PasswordController extends Controller
+class ResetPasswordController extends Controller
 {
     /*
     |--------------------------------------------------------------------------
@@ -20,13 +20,14 @@ class PasswordController extends Controller
 
     use ResetsPasswords;
 
-    protected $redirectTo = '/';
-
     /**
-     * Create a new password controller instance.
+     * Create a new controller instance.
+     *
+     * @return void
      */
     public function __construct()
     {
         $this->middleware('guest');
+        parent::__construct();
     }
-}
+}
\ No newline at end of file
index 26eeb3002aeebecd9ec74796f428fe9eb2132a5a..43292d941a19140f7b341430187173aa1493d4ff 100644 (file)
@@ -30,17 +30,22 @@ 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 = auth()->user();
+            if (!$user) $user = User::getDefault();
 
-        // Share variables with controllers
-        $this->currentUser = $user;
-        $this->signedIn = auth()->check();
+            // Share variables with views
+            view()->share('signedIn', auth()->check());
+            view()->share('currentUser', $user);
+
+            // Share variables with controllers
+            $this->currentUser = $user;
+            $this->signedIn = auth()->check();
+
+            return $next($request);
+        });
     }
 
     /**
index 1509ace9563b7aee65fe3b8c167f5e07117bacf6..3d6abe5b4e97ea6f33041d2402f8c2002677333a 100644 (file)
@@ -42,7 +42,7 @@ class PageController extends Controller
 
     /**
      * Show the form for creating a new page.
-     * @param      $bookSlug
+     * @param string $bookSlug
      * @param bool $chapterSlug
      * @return Response
      * @internal param bool $pageSlug
@@ -61,8 +61,8 @@ class PageController extends Controller
 
     /**
      * 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)
@@ -112,8 +112,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 +131,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 +152,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)
@@ -185,8 +188,8 @@ class PageController extends Controller
     /**
      * 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,7 +208,7 @@ 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)
@@ -230,7 +233,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 +244,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 +260,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 +276,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 +294,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 +311,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 +325,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)
@@ -339,9 +342,9 @@ class PageController extends Controller
 
     /**
      * 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 +360,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 +377,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 +394,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 +437,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 +455,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 +473,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 +516,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
      */
index 053d9ebd57345017cb9f8faf22986de52335cf63..4c56516dc670f098933ae73de2796cdb8a6b673c 100644 (file)
@@ -3,6 +3,7 @@
 namespace BookStack\Http\Controllers;
 
 use BookStack\Activity;
+use Exception;
 use Illuminate\Http\Request;
 
 use Illuminate\Http\Response;
@@ -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');
index a1f2a581fb6c5038179dfa0be03cfc494150adbf..f1d95f5c070da381114dad0f3c41a4b69495ec90 100644 (file)
@@ -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,
index 372f30bf64f545957cd3a8fb2a63e27416ec441f..8461ed0ba18365574911168e9a3e091a1504f2ac 100644 (file)
@@ -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')) {
index ab8ce4d3a3243620902476957fca28bed55343a3..2b3c64695735d44daf3c6f47f76d4aa59584f4c2 100644 (file)
@@ -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 (file)
index 780af74..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-
-namespace BookStack\Jobs;
-
-use Illuminate\Bus\Queueable;
-
-abstract class Job
-{
-    /*
-    |--------------------------------------------------------------------------
-    | Queueable Jobs
-    |--------------------------------------------------------------------------
-    |
-    | This job base class provides a central location to place any logic that
-    | is shared across all of your jobs. The trait included with the class
-    | provides access to the "queueOn" and "delay" queue helper methods.
-    |
-    */
-
-    use Queueable;
-}
diff --git a/app/Listeners/.gitkeep b/app/Listeners/.gitkeep
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/app/Notifications/ConfirmEmail.php b/app/Notifications/ConfirmEmail.php
new file mode 100644 (file)
index 0000000..64d9bb9
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+
+namespace BookStack\Notifications;
+
+use Illuminate\Notifications\Notification;
+use Illuminate\Notifications\Messages\MailMessage;
+
+class ConfirmEmail extends Notification
+{
+
+    public $token;
+
+    /**
+     * Create a new notification instance.
+     * @param string $token
+     */
+    public function __construct($token)
+    {
+        $this->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 (file)
index 0000000..646030a
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+
+namespace BookStack\Notifications;
+
+use Illuminate\Notifications\Notification;
+use Illuminate\Notifications\Messages\MailMessage;
+
+class ResetPassword extends Notification
+{
+    /**
+     * The password reset token.
+     *
+     * @var string
+     */
+    public $token;
+
+    /**
+     * Create a notification instance.
+     *
+     * @param  string  $token
+     */
+    public function __construct($token)
+    {
+        $this->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/Providers/BroadcastServiceProvider.php b/app/Providers/BroadcastServiceProvider.php
new file mode 100644 (file)
index 0000000..11e3cc6
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+namespace BookStack\Providers;
+
+use Illuminate\Support\ServiceProvider;
+use Illuminate\Support\Facades\Broadcast;
+
+class BroadcastServiceProvider extends ServiceProvider
+{
+    /**
+     * Bootstrap any application services.
+     *
+     * @return void
+     */
+    public function boot()
+    {
+//        Broadcast::routes();
+//
+//        /*
+//         * Authenticate the user's personal channel...
+//         */
+//        Broadcast::channel('BookStack.User.*', function ($user, $userId) {
+//            return (int) $user->id === (int) $userId;
+//        });
+    }
+}
index f754b87a9c43c6f7bfd66ff67a3e1ebcb84fd668..3802f20c0de0ba7c4c9697c8736b4598feed3538 100644 (file)
@@ -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();
     }
 }
index a0e97f70db42a508f1fcf1e1114e0ad5681654f7..ec41267a4ba24f99b45be4fe8d984ed112c0bdd7 100644 (file)
@@ -1,11 +1,12 @@
 <?php namespace BookStack\Providers;
 
 
-use Illuminate\Support\ServiceProvider;
+use Illuminate\Pagination\PaginationServiceProvider as IlluminatePaginationServiceProvider;
 use Illuminate\Pagination\Paginator;
 
-class PaginationServiceProvider extends ServiceProvider
+class PaginationServiceProvider extends IlluminatePaginationServiceProvider
 {
+
     /**
      * Register the service provider.
      *
@@ -13,6 +14,10 @@ class PaginationServiceProvider extends ServiceProvider
      */
     public function register()
     {
+        Paginator::viewFactoryResolver(function () {
+            return $this->app['view'];
+        });
+
         Paginator::currentPathResolver(function () {
             return baseUrl($this->app['request']->path());
         });
index 2d9cd3b85daaec24a8e18f9e45c64819ed2d9d58..88ab23526e6c54aae08b992909859109e3e31e5b 100644 (file)
@@ -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()
+    {
+        $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()
     {
-        $router->group(['namespace' => $this->namespace], function ($router) {
-            require app_path('Http/routes.php');
+        Route::group([
+            'middleware' => 'api',
+            'namespace' => $this->namespace,
+            'prefix' => 'api',
+        ], function ($router) {
+            require base_path('routes/api.php');
         });
     }
 }
index 235246f823ef9696e1e97e934da79605dffe31b2..c64da126774bd3db3180028b8cb4f0a288dcee81 100644 (file)
@@ -7,6 +7,7 @@ use BookStack\Entity;
 use BookStack\Exceptions\NotFoundException;
 use Carbon\Carbon;
 use DOMDocument;
+use DOMXPath;
 use Illuminate\Support\Str;
 use BookStack\Page;
 use BookStack\PageRevision;
@@ -110,31 +111,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.
@@ -183,6 +159,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.
@@ -371,7 +376,7 @@ 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;
@@ -381,11 +386,13 @@ class PageRepo extends EntityRepo
         $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;
     }
 
index 0926f630471c24e1583b937e91ce74f2414d5da9..127db9fb59c482aab05198277558bf7b6abdcac6 100644 (file)
@@ -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;
index c3096c654fb0fb0e1853d6ec5961b8f9df78d07a..d4ec1e9760242a4b10b889c506a8690633eebfe0 100644 (file)
@@ -1,30 +1,27 @@
 <?php namespace BookStack\Services;
 
-
+use BookStack\Notifications\ConfirmEmail;
+use BookStack\Repos\UserRepo;
 use Carbon\Carbon;
-use Illuminate\Contracts\Mail\Mailer;
-use Illuminate\Mail\Message;
-use BookStack\EmailConfirmation;
 use BookStack\Exceptions\ConfirmationEmailException;
 use BookStack\Exceptions\UserRegistrationException;
-use BookStack\Repos\UserRepo;
-use BookStack\Setting;
 use BookStack\User;
+use Illuminate\Database\Connection as Database;
 
 class EmailConfirmationService
 {
-    protected $mailer;
-    protected $emailConfirmation;
+    protected $db;
+    protected $users;
 
     /**
      * EmailConfirmationService constructor.
-     * @param Mailer            $mailer
-     * @param EmailConfirmation $emailConfirmation
+     * @param Database $db
+     * @param UserRepo $users
      */
-    public function __construct(Mailer $mailer, EmailConfirmation $emailConfirmation)
+    public function __construct(Database $db, UserRepo $users)
     {
-        $this->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;
index 4401cb230a8b4105ba5458be1e4e88f596803ccb..aa1375487cd943f26afee06a8500c90cc4cb52d1 100644 (file)
@@ -213,7 +213,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;
index cee074cd7cd09b1f36278cef042443cb05166181..341a69edb624a4967b86c432c66b044a0ae896aa 100644 (file)
@@ -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 = auth()->user() ? auth()->user() : new 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
index 32449971d7847f8e4d0dc880d3868fd8eb2c528a..8c39d81be5303d32a881b40356ecb477f72aa3eb 100644 (file)
@@ -1,13 +1,15 @@
 <?php namespace BookStack;
 
+use BookStack\Notifications\ResetPassword;
 use Illuminate\Auth\Authenticatable;
 use Illuminate\Auth\Passwords\CanResetPassword;
 use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
 use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
+use Illuminate\Notifications\Notifiable;
 
 class User extends Model implements AuthenticatableContract, CanResetPasswordContract
 {
-    use Authenticatable, CanResetPassword;
+    use Authenticatable, CanResetPassword, Notifiable;
 
     /**
      * The database table used by the model.
@@ -183,4 +185,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));
+    }
 }
index b8abb10066a94d46bb155e2ff07c617281d49f86..dd835fbf64755adb17a0568902cff00cd7a75c4f 100644 (file)
@@ -63,7 +63,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,11 +79,17 @@ 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));
     }
 
+    // Return normal url path if not specified in config
+    if (config('app.url') === '') {
+        return url($path);
+    }
+
     return rtrim(config('app.url'), '/') . '/' . $path;
 }
 
index 5c77a68c4afd3de50cd34e2ffd1d5f51d2cd0cbb..d9603701998f1fd6db56a73bb12d378ac2641e41 100644 (file)
@@ -5,23 +5,22 @@
     "license": "MIT",
     "type": "project",
     "require": {
-        "php": ">=5.5.9",
-        "laravel/framework": "5.2.*",
+        "php": ">=5.6.4",
+        "laravel/framework": "^5.3.4",
         "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"
     },
     "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": [
         ]
     },
     "scripts": {
+        "post-root-package-install": [
+            "php -r \"file_exists('.env') || copy('.env.example', '.env');\""
+        ],
+        "post-create-project-cmd": [
+            "php artisan key:generate"
+        ],
         "post-install-cmd": [
-            "php artisan clear-compiled",
+            "Illuminate\\Foundation\\ComposerScripts::postInstall",
             "php artisan optimize"
         ],
-        "pre-update-cmd": [
-            "php artisan clear-compiled"
-        ],
         "post-update-cmd": [
+            "Illuminate\\Foundation\\ComposerScripts::postUpdate",
             "php artisan optimize"
-        ],
-        "post-root-package-install": [
-            "php -r \"copy('.env.example', '.env');\""
-        ],
-        "post-create-project-cmd": [
-            "php artisan key:generate"
         ]
     },
     "config": {
index 63d378753f569263af1c35c402ea43168822dbc1..c1c80e100b9b11cf2cd648b3785dd43caa3f30ec 100644 (file)
@@ -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": "c90a6e41767306ceb3b8cedb91468390",
+    "content-hash": "3b5d2d6b77fbe71101e7e8eaff0754fe",
     "packages": [
         {
             "name": "aws/aws-sdk-php",
-            "version": "3.17.5",
+            "version": "3.19.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/aws/aws-sdk-php.git",
-                "reference": "1cef9b334729b3564c9aef15481a55561c54b53f"
+                "reference": "34060bf0db260031697b17dbb37fa1bbec92f1c4"
             },
             "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/34060bf0db260031697b17dbb37fa1bbec92f1c4",
+                "reference": "34060bf0db260031697b17dbb37fa1bbec92f1c4",
                 "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"
             },
                 "s3",
                 "sdk"
             ],
-            "time": "2016-04-07 22:44:13"
+            "time": "2016-09-08 20:27:15"
         },
         {
             "name": "barryvdh/laravel-debugbar",
-            "version": "v2.2.0",
+            "version": "V2.2.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/barryvdh/laravel-debugbar.git",
-                "reference": "13b7058d2120c8d5af7f1ada21b7c44dd87b666a"
+                "reference": "ecd1ce5c4a827e2f6a8fb41bcf67713beb1c1cbd"
             },
             "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/ecd1ce5c4a827e2f6a8fb41bcf67713beb1c1cbd",
+                "reference": "ecd1ce5c4a827e2f6a8fb41bcf67713beb1c1cbd",
                 "shasum": ""
             },
             "require": {
-                "illuminate/support": "5.1.*|5.2.*",
-                "maximebf/debugbar": "~1.11.0",
+                "illuminate/support": "5.1.*|5.2.*|5.3.*",
+                "maximebf/debugbar": "~1.11.0|~1.12.0",
                 "php": ">=5.5.9",
                 "symfony/finder": "~2.7|~3.0"
             },
                 "profiler",
                 "webprofiler"
             ],
-            "time": "2016-02-17 08:32:21"
+            "time": "2016-07-29 15:00:36"
         },
         {
             "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": {
                 "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)"
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.1-dev"
+                    "dev-master": "2.2-dev"
                 }
             },
             "autoload": {
                 "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": "[email protected]"
+                }
+            ],
+            "time": "2016-06-13 19:28:20"
         },
         {
             "name": "classpreloader/classpreloader",
         },
         {
             "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": [
                 {
                 {
                     "name": "Brian Sweeney",
                     "email": "[email protected]"
-                }
-            ],
-            "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"
-        },
-        {
-            "name": "guzzle/guzzle",
-            "version": "v3.8.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/guzzle/guzzle.git",
-                "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/4de0618a01b34aa1c8c33a3f13f396dcd3882eba",
-                "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba",
-                "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"
-            },
-            "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"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.8-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Guzzle": "src/",
-                    "Guzzle\\Tests": "tests/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Michael Dowling",
-                    "email": "[email protected]",
-                    "homepage": "https://github.com/mtdowling"
                 },
                 {
-                    "name": "Guzzle Community",
-                    "homepage": "https://github.com/guzzle/guzzle/contributors"
+                    "name": "Gabriel Bull",
+                    "email": "[email protected]"
                 }
             ],
-            "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": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
+            "homepage": "https://github.com/dompdf/dompdf",
+            "time": "2016-05-11 00:36:29"
         },
         {
             "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": {
                 "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": {
             "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0-dev"
+                    "dev-master": "1.4-dev"
                 }
             },
             "autoload": {
                 "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": {
                 "thumbnail",
                 "watermark"
             ],
-            "time": "2016-02-26 18:18:19"
+            "time": "2016-09-01 17:04:03"
         },
         {
             "name": "jakub-onderka/php-console-color",
         },
         {
             "name": "laravel/framework",
-            "version": "v5.2.29",
+            "version": "v5.3.9",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/framework.git",
-                "reference": "e3d644eb131f18c5f3d28ff7bc678bc797091f20"
+                "reference": "f6fbb481672f8dc4bc6882d5d654bbfa3588c8ec"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/framework/zipball/e3d644eb131f18c5f3d28ff7bc678bc797091f20",
-                "reference": "e3d644eb131f18c5f3d28ff7bc678bc797091f20",
+                "url": "https://api.github.com/repos/laravel/framework/zipball/f6fbb481672f8dc4bc6882d5d654bbfa3588c8ec",
+                "reference": "f6fbb481672f8dc4bc6882d5d654bbfa3588c8ec",
                 "shasum": ""
             },
             "require": {
                 "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": {
                 "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).",
                 "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"
             "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-12 14:08:29"
         },
         {
             "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": {
             },
             "require-dev": {
                 "mockery/mockery": "~0.9",
-                "phpunit/phpunit": "~4.0"
+                "phpunit/phpunit": "~4.0|~5.0"
             },
             "type": "library",
             "extra": {
                 "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": {
                 "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",
                 "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": {
                 }
             ],
             "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": {
                 "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.12.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/maximebf/php-debugbar.git",
-                "reference": "d9302891c1f0a0ac5a4f66725163a00537c6359f"
+                "reference": "e634fbd32cd6bc3fa0e8c972b52d4bf49bab3988"
             },
             "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/e634fbd32cd6bc3fa0e8c972b52d4bf49bab3988",
+                "reference": "e634fbd32cd6bc3fa0e8c972b52d4bf49bab3988",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.11-dev"
+                    "dev-master": "1.12-dev"
                 }
             },
             "autoload": {
                 "debug",
                 "debugbar"
             ],
-            "time": "2016-01-22 12:22:23"
+            "time": "2016-05-15 13:11:34"
         },
         {
             "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": {
                 "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": {
                 "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": {
                 "logging",
                 "psr-3"
             ],
-            "time": "2016-04-02 13:12:58"
+            "time": "2016-07-29 03:23:52"
         },
         {
             "name": "mtdowling/cron-expression",
         },
         {
             "name": "nikic/php-parser",
-            "version": "v2.0.1",
+            "version": "v2.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nikic/PHP-Parser.git",
-                "reference": "ce5be709d59b32dd8a88c80259028759991a4206"
+                "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3"
             },
             "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/47b254ea51f1d6d5dc04b9b299e88346bf2369e3",
+                "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-master": "2.1-dev"
                 }
             },
             "autoload": {
                 "parser",
                 "php"
             ],
-            "time": "2016-02-28 19:48:28"
+            "time": "2016-04-19 13:41:41"
         },
         {
             "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": {
                 "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": [
                 {
             ],
             "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",
                     "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": {
                 }
             ],
             "description": "Common interface for HTTP messages",
+            "homepage": "https://github.com/php-fig/http-message",
             "keywords": [
                 "http",
                 "http-message",
                 "request",
                 "response"
             ],
-            "time": "2015-05-04 20:22:00"
+            "time": "2016-08-06 14:39:51"
         },
         {
             "name": "psr/log",
             ],
             "time": "2016-03-09 05:03:14"
         },
+        {
+            "name": "ramsey/uuid",
+            "version": "3.5.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ramsey/uuid.git",
+                "reference": "a6d15c8618ea3951fd54d34e326b68d3d0bc0786"
+            },
+            "dist": {
+                "type": "zip",
+                "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": "[email protected]"
+                },
+                {
+                    "name": "Thibaud Fabre",
+                    "email": "[email protected]"
+                },
+                {
+                    "name": "Ben Ramsey",
+                    "email": "[email protected]",
+                    "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.1",
+            "version": "v5.4.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/swiftmailer/swiftmailer.git",
-                "reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421"
+                "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/0697e6aa65c83edf97bb0f23d8763f94e3f11421",
-                "reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421",
+                "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": {
                 "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "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": {
                 "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"
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.1-dev"
+                    "dev-master": "1.2-dev"
                 }
             },
             "autoload": {
                 "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.1-dev"
+                    "dev-master": "1.2-dev"
                 }
             },
             "autoload": {
                 "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.1-dev"
+                    "dev-master": "1.2-dev"
                 }
             },
             "autoload": {
                 "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
                 "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
                 "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": {
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
-                "BSD"
+                "BSD-3-Clause-Attribution"
             ],
             "authors": [
                 {
                 }
             ],
             "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": [
         },
         {
             "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": {
                 "faker",
                 "fixtures"
             ],
-            "time": "2015-05-29 06:29:14"
+            "time": "2016-04-29 12:21:54"
         },
         {
             "name": "hamcrest/hamcrest-php",
         },
         {
             "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": {
                 "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.2",
             "source": {
                 "type": "git",
-                "url": "https://github.com/phpspec/php-diff.git",
-                "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a"
+                "url": "https://github.com/myclabs/DeepCopy.git",
+                "reference": "da8529775f14f4fdae33f916eb0cf65f6afbddbc"
             },
             "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/da8529775f14f4fdae33f916eb0cf65f6afbddbc",
+                "reference": "da8529775f14f4fdae33f916eb0cf65f6afbddbc",
                 "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"
+            ],
+            "description": "Create deep copies (clones) of your objects",
+            "homepage": "https://github.com/myclabs/DeepCopy",
+            "keywords": [
+                "clone",
+                "copy",
+                "duplicate",
+                "object",
+                "object graph"
+            ],
+            "time": "2016-09-06 16:07:05"
+        },
+        {
+            "name": "phpdocumentor/reflection-common",
+            "version": "1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+                "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
+                "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.6"
+            },
+            "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": "Chris Boulton",
-                    "homepage": "http://github.com/chrisboulton",
-                    "role": "Original developer"
+                    "name": "Jaap van Otterdijk",
+                    "email": "[email protected]"
                 }
             ],
-            "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).",
-            "time": "2013-11-01 13:02:21"
+            "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+            "homepage": "http://www.phpdoc.org",
+            "keywords": [
+                "FQSEN",
+                "phpDocumentor",
+                "phpdoc",
+                "reflection",
+                "static analysis"
+            ],
+            "time": "2015-12-27 11:43:31"
         },
         {
-            "name": "phpspec/phpspec",
-            "version": "2.5.0",
+            "name": "phpdocumentor/reflection-docblock",
+            "version": "3.1.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/phpspec/phpspec.git",
-                "reference": "385ecb015e97c13818074f1517928b24d4a26067"
+                "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+                "reference": "9270140b940ff02e58ec577c237274e92cd40cdd"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpspec/phpspec/zipball/385ecb015e97c13818074f1517928b24d4a26067",
-                "reference": "385ecb015e97c13818074f1517928b24d4a26067",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd",
+                "reference": "9270140b940ff02e58ec577c237274e92cd40cdd",
                 "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",
+                "phpdocumentor/reflection-common": "^1.0@dev",
+                "phpdocumentor/type-resolver": "^0.2.0",
+                "webmozart/assert": "^1.0"
             },
             "require-dev": {
-                "behat/behat": "^3.0.11",
-                "bossa/phpspec2-expect": "~1.0",
-                "phpunit/phpunit": "~4.4",
-                "symfony/filesystem": "~2.1|~3.0"
+                "mockery/mockery": "^0.9.4",
+                "phpunit/phpunit": "^4.4"
             },
-            "suggest": {
-                "phpspec/nyan-formatters": "~1.0 â€“ Adds Nyan formatters"
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "phpDocumentor\\Reflection\\": [
+                        "src/"
+                    ]
+                }
             },
-            "bin": [
-                "bin/phpspec"
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
             ],
+            "authors": [
+                {
+                    "name": "Mike van Riel",
+                    "email": "[email protected]"
+                }
+            ],
+            "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": "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/",
             ],
             "authors": [
                 {
-                    "name": "Konstantin Kudryashov",
-                    "email": "[email protected]",
-                    "homepage": "http://everzet.com"
-                },
-                {
-                    "name": "Marcello Duarte",
-                    "homepage": "http://marcelloduarte.net/"
+                    "name": "Mike van Riel",
+                    "email": "[email protected]"
                 }
             ],
-            "description": "Specification-oriented BDD framework for PHP 5.3+",
-            "homepage": "http://phpspec.net/",
-            "keywords": [
-                "BDD",
-                "SpecBDD",
-                "TDD",
-                "spec",
-                "specification",
-                "testing",
-                "tests"
-            ],
-            "time": "2016-03-20 20:34:32"
+            "time": "2016-06-10 07:14:17"
         },
         {
             "name": "phpspec/prophecy",
-            "version": "v1.6.0",
+            "version": "v1.6.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpspec/prophecy.git",
-                "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
+                "reference": "58a8137754bc24b25740d4281399a4a3596058e0"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
-                "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
+                "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": {
                 "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": {
                 "testing",
                 "xunit"
             ],
-            "time": "2015-10-06 15:47:00"
+            "time": "2016-07-26 14:39:29"
         },
         {
             "name": "phpunit/php-file-iterator",
         },
         {
             "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": [
             "keywords": [
                 "timer"
             ],
-            "time": "2015-06-21 08:01:12"
+            "time": "2016-05-12 18:03:57"
         },
         {
             "name": "phpunit/php-token-stream",
         },
         {
             "name": "phpunit/phpunit",
-            "version": "4.8.24",
+            "version": "5.5.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "a1066c562c52900a142a0e2bbf0582994671385e"
+                "reference": "3e6e88e56c912133de6e99b87728cca7ed70c5f5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1066c562c52900a142a0e2bbf0582994671385e",
-                "reference": "a1066c562c52900a142a0e2bbf0582994671385e",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3e6e88e56c912133de6e99b87728cca7ed70c5f5",
+                "reference": "3e6e88e56c912133de6e99b87728cca7ed70c5f5",
                 "shasum": ""
             },
             "require": {
                 "ext-pcre": "*",
                 "ext-reflection": "*",
                 "ext-spl": "*",
-                "php": ">=5.3.3",
+                "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"
+            },
             "suggest": {
                 "phpunit/php-invoker": "~1.1"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.8.x-dev"
+                    "dev-master": "5.5.x-dev"
                 }
             },
             "autoload": {
                 "testing",
                 "xunit"
             ],
-            "time": "2016-03-14 06:16:08"
+            "time": "2016-08-26 07:11:44"
         },
         {
             "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": "*"
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.3.x-dev"
+                    "dev-master": "3.2.x-dev"
                 }
             },
             "autoload": {
                 "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": "[email protected]"
+                }
+            ],
+            "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",
         },
         {
             "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": {
                 "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": {
                 "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": {
                 "export",
                 "exporter"
             ],
-            "time": "2015-06-21 07:55:53"
+            "time": "2016-06-17 09:04:28"
         },
         {
             "name": "sebastian/global-state",
             ],
             "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": "[email protected]"
+                }
+            ],
+            "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",
             "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
             "time": "2015-11-11 19:50:13"
         },
+        {
+            "name": "sebastian/resource-operations",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/resource-operations.git",
+                "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
+            },
+            "dist": {
+                "type": "zip",
+                "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": "[email protected]"
+                }
+            ],
+            "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": "1.0.6",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/version.git",
-                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
+                "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
-                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+                "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/"
             ],
             "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "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": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "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": "[email protected]"
+                }
+            ],
+            "description": "Assertions to validate method input/output with nice error messages.",
+            "keywords": [
+                "assert",
+                "check",
+                "validate"
+            ],
+            "time": "2016-08-09 15:02:57"
         }
     ],
     "aliases": [],
     "prefer-stable": false,
     "prefer-lowest": false,
     "platform": {
-        "php": ">=5.5.9"
+        "php": ">=5.6.4"
     },
     "platform-dev": []
 }
index 0d6f6f2b0744dd8ad37eda1196ac6de239263337..a5b0d2fe0e325399440d6e2250035fd1412f7e6f 100644 (file)
@@ -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,
index 24a49c364195ca03985f1fae198da59ed52069d9..5482c13315e8012f9f90f89644e765d895eb1569 100644 (file)
@@ -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)'
index 763a33fec4b46b96a621730220331bf7d066919c..47a77e29f95a20e59c830b70ba98b260637fda31 100644 (file)
@@ -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/phpspec.yml b/phpspec.yml
deleted file mode 100644 (file)
index 58f1d98..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-suites:
-    main:
-        namespace: BookStack
-        psr4_prefix: BookStack
-        src_path: app
\ No newline at end of file
index fcaba2914b8557bac98a33fe5c5ce5c32bb37355..2c0cf3e2b7af24318f70de2ed79482898c5b172f 100644 (file)
@@ -336,6 +336,8 @@ module.exports = function (ngApp, events) {
             $scope.editorChange = function() {};
         }
 
+        let lastSave = 0;
+
         /**
          * Start the AutoSave loop, Checks for content change
          * before performing the costly AJAX request.
@@ -345,6 +347,8 @@ module.exports = function (ngApp, events) {
             currentContent.html = $scope.editContent;
 
             autoSave = $interval(() => {
+                // Return if manually saved recently to prevent bombarding the server
+                if (Date.now() - lastSave < (1000*autosaveFrequency)/2) return;
                 var newTitle = $('#name').val();
                 var newHtml = $scope.editContent;
 
@@ -357,6 +361,7 @@ module.exports = function (ngApp, events) {
             }, 1000 * autosaveFrequency);
         }
 
+        let draftErroring = false;
         /**
          * Save a draft update into the system via an AJAX request.
          */
@@ -369,11 +374,17 @@ module.exports = function (ngApp, events) {
             if (isMarkdown) data.markdown = $scope.editContent;
 
             let url = window.baseUrl('/ajax/page/' + pageId + '/save-draft');
-            $http.put(url, data).then((responseData) => {
+            $http.put(url, data).then(responseData => {
+                draftErroring = false;
                 var updateTime = moment.utc(moment.unix(responseData.data.timestamp)).toDate();
                 $scope.draftText = responseData.data.message + moment(updateTime).format('HH:mm');
                 if (!$scope.isNewPageDraft) $scope.isUpdateDraft = true;
                 showDraftSaveNotification();
+                lastSave = Date.now();
+            }, errorRes => {
+                if (draftErroring) return;
+                events.emit('error', 'Failed to save draft. Ensure you have internet connection before saving this page.')
+                draftErroring = true;
             });
         }
 
index 755d558e83ffcde90d3f349e6568fc5da163f3c2..c1e6a92df26941dc683b92e3990f38aabb8a2bf0 100644 (file)
@@ -81,9 +81,10 @@ var mceOptions = module.exports = {
     toolbar: "undo redo | styleselect | bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image-insert link hr | removeformat code fullscreen",
     content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
     style_formats: [
-        {title: "Header 1", format: "h1"},
-        {title: "Header 2", format: "h2"},
-        {title: "Header 3", format: "h3"},
+        {title: "Header Large", format: "h2"},
+        {title: "Header Medium", format: "h3"},
+        {title: "Header Small", format: "h4"},
+        {title: "Header Tiny", format: "h5"},
         {title: "Paragraph", format: "p", exact: true, classes: ''},
         {title: "Blockquote", format: "blockquote"},
         {title: "Code Block", icon: "code", format: "pre"},
index 2658c46891bf75ebc99ec9553897be9e93bfa60b..54fd55dff6f075637a2d943a431e05a05a6458fc 100644 (file)
@@ -1,5 +1,5 @@
 .page-list {
-  h3 {
+  h4 {
     margin: $-l 0 $-xs 0;
     font-size: 1.666em;
   }
     overflow: hidden;
     margin-bottom: $-l;
   }
-  h4 {
+  h5 {
     display: block;
     margin: $-s 0 0 0;
     border-left: 5px solid $color-page;
     padding: $-xs 0 $-xs $-m;
+    font-size: 1.1em;
+    font-weight: normal;
     &.draft {
       border-left-color: $color-page-draft;
     }
   }
 }
 
-.page-nav-list {
+.sidebar-page-nav {
   $nav-indent: $-s;
-  margin-left: 2px;
   list-style: none;
+  margin: $-s 0 $-m 2px;
+  border-left: 2px dotted #BBB;
   li {
-    //border-left: 1px solid rgba(0, 0, 0, 0.1);
-    padding-left: $-xs;
-    border-left: 2px solid #888;
+    padding-left: $-s;
     margin-bottom: 4px;
+    font-size: 0.95em;
   }
-  li a {
-    color: #555;
+  .h1 {
+    margin-left: -2px;
   }
-  .nav-H2 {
+  .h2 {
+    margin-left: -2px;
+  }
+  .h3 {
     margin-left: $nav-indent;
-    font-size: 0.95em;
   }
-  .nav-H3 {
+  .h4 {
     margin-left: $nav-indent*2;
-    font-size: 0.90em
   }
-  .nav-H4 {
+  .h5 {
     margin-left: $nav-indent*3;
-    font-size: 0.85em
   }
-  .nav-H5 {
+  .h6 {
     margin-left: $nav-indent*4;
-    font-size: 0.80em
-  }
-  .nav-H6 {
-    margin-left: $nav-indent*5;
-    font-size: 0.75em
   }
 }
 
 // Sidebar list
 .book-tree {
-  padding: $-l 0 0 0;
+  padding: $-xs 0 0 0;
   position: relative;
   right: 0;
   top: 0;
@@ -306,10 +303,10 @@ ul.pagination {
 }
 
 .entity-list {
-  >div {
+  > div {
     padding: $-m 0;
   }
-  h3 {
+  h4 {
     margin: 0;
   }
   p {
@@ -327,9 +324,10 @@ ul.pagination {
     color: $color-page-draft;
   }
 }
+
 .entity-list.compact {
   font-size: 0.6em;
-  h3, a {
+  h4, a {
     line-height: 1.2;
   }
   p {
index cd81bb4e21326d24e2589751438b0a8e510e217b..fd993b685402813132cb3a4c0ff50405bc20b153 100644 (file)
@@ -15,31 +15,41 @@ h2 {
   margin-bottom: 0.43137255em;
 }
 h3 {
-  font-size: 1.75em;
+  font-size: 2.333em;
   line-height: 1.571428572em;
   margin-top: 0.78571429em;
   margin-bottom: 0.43137255em;
 }
 h4 {
-  font-size: 1em;
+  font-size: 1.666em;
   line-height: 1.375em;
   margin-top: 0.78571429em;
   margin-bottom: 0.43137255em;
 }
 
-h1, h2, h3, h4 {
+h1, h2, h3, h4, h5, h6 {
   font-weight: 400;
   position: relative;
   display: block;
   color: #555;
   .subheader {
-    //display: block;
     font-size: 0.5em;
     line-height: 1em;
     color: lighten($text-dark, 32%);
   }
 }
 
+h5 {
+  font-size: 1.4em;
+}
+
+h5, h6 {
+  font-weight: 500;
+  line-height: 1.2em;
+  margin-top: 0.78571429em;
+  margin-bottom: 0.66em;
+}
+
 /*
  * Link styling
  */
diff --git a/resources/lang/en/auth.php b/resources/lang/en/auth.php
new file mode 100644 (file)
index 0000000..ffdb1cf
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+return [
+    /*
+    |--------------------------------------------------------------------------
+    | Authentication Language Lines
+    |--------------------------------------------------------------------------
+    |
+    | The following language lines are used during authentication for various
+    | messages that we need to display to the user. You are free to modify
+    | these language lines according to your application's requirements.
+    |
+    */
+    'failed' => 'These credentials do not match our records.',
+    'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
+
+    /**
+     * Email Confirmation Text
+     */
+    'email_confirm_subject' => 'Confirm your email on :appName',
+    'email_confirm_greeting' => 'Thanks for joining :appName!',
+    'email_confirm_text' => 'Please confirm your email address by clicking the button below:',
+    'email_confirm_action' => 'Confirm Email',
+    'email_confirm_send_error' => 'Email confirmation required but the system could not send the email. Contact the admin to ensure email is set up correctly.',
+    'email_confirm_success' => 'Your email has been confirmed!',
+    'email_confirm_resent' => 'Confirmation email resent, Please check your inbox.',
+];
\ No newline at end of file
diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php
new file mode 100644 (file)
index 0000000..1b0bcad
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+return [
+    
+    /**
+     * Settings text strings
+     * Contains all text strings used in the general settings sections of BookStack
+     * including users and roles.
+     */
+    
+    'settings' => 'Settings',
+    'settings_save' => 'Save Settings',
+    
+    'app_settings' => 'App Settings',
+    'app_name' => 'Application name',
+    'app_name_desc' => 'This name is shown in the header and any emails.',
+    'app_name_header' => 'Show Application name in header?',
+    'app_public_viewing' => 'Allow public viewing?',
+    'app_secure_images' => 'Enable higher security image uploads?',
+    'app_secure_images_desc' => 'For performance reasons, all images are public. This option adds a random, hard-to-guess string in front of image urls. Ensure directory indexes are not enabled to prevent easy access.',
+    'app_editor' => 'Page editor',
+    'app_editor_desc' => 'Select which editor will be used by all users to edit pages.',
+    'app_custom_html' => 'Custom HTML head content',
+    'app_custom_html_desc' => 'Any content added here will be inserted into the bottom of the <head> section of every page. This is handy for overriding styles or adding analytics code.',
+    'app_logo' => 'Application logo',
+    'app_logo_desc' => 'This image should be 43px in height. <br>Large images will be scaled down.',
+    'app_primary_color' => 'Application primary color',
+    'app_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.',
+
+    'reg_settings' => 'Registration Settings',
+    'reg_allow' => 'Allow registration?',
+    'reg_default_role' => 'Default user role after registration',
+    'reg_confirm_email' => 'Require email confirmation?',
+    'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and the below value will be ignored.',
+    'reg_confirm_restrict_domain' => 'Restrict registration to domain',
+    'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application. <br> Note that users will be able to change their email addresses after successful registration.',
+    'reg_confirm_restrict_domain_placeholder' => 'No restriction set',
+
+];
\ No newline at end of file
index be47abdcaaf3e23903c63e03884f790433d3ac6a..1deed0a3fbad2057fc5ca0789f2a6029d7f24d45 100644 (file)
@@ -39,7 +39,9 @@
                         @if(setting('app-logo', '') !== 'none')
                             <img class="logo-image" src="{{ setting('app-logo', '') === '' ? baseUrl('/logo.png') : baseUrl(setting('app-logo', '')) }}" alt="Logo">
                         @endif
-                        <span class="logo-text">{{ setting('app-name') }}</span>
+                        @if (setting('app-name-header'))
+                            <span class="logo-text">{{ setting('app-name') }}</span>
+                        @endif
                     </a>
                 </div>
                 <div class="col-lg-4 col-sm-3 text-center">
index 2eefdfbf531c0a9917cc2606a344e32402863ffd..605841f7f0ae31ada7c4c9f39d5b96757b7e9e0b 100644 (file)
@@ -1,5 +1,5 @@
 <div class="book entity-list-item"  data-entity-type="book" data-entity-id="{{$book->id}}">
-    <h3 class="text-book"><a class="text-book entity-list-item-link" href="{{$book->getUrl()}}"><i class="zmdi zmdi-book"></i><span class="entity-list-item-name">{{$book->name}}</span></a></h3>
+    <h4 class="text-book"><a class="text-book entity-list-item-link" href="{{$book->getUrl()}}"><i class="zmdi zmdi-book"></i><span class="entity-list-item-name">{{$book->name}}</span></a></h4>
     @if(isset($book->searchSnippet))
         <p class="text-muted">{!! $book->searchSnippet !!}</p>
     @else
index 35d3a7589d927b313e8e8488c8ff2490cc82a289..f70e592448f00068e554a9332f5ae5a3faf7f903 100644 (file)
@@ -1,5 +1,5 @@
 <div class="chapter entity-list-item" data-entity-type="chapter" data-entity-id="{{$chapter->id}}">
-    <h3>
+    <h4>
         @if (isset($showPath) && $showPath)
             <a href="{{ $chapter->book->getUrl() }}" class="text-book">
                 <i class="zmdi zmdi-book"></i>{{ $chapter->book->name }}
@@ -9,7 +9,7 @@
         <a href="{{ $chapter->getUrl() }}" class="text-chapter entity-list-item-link">
             <i class="zmdi zmdi-collection-bookmark"></i><span class="entity-list-item-name">{{ $chapter->name }}</span>
         </a>
-    </h3>
+    </h4>
     @if(isset($chapter->searchSnippet))
         <p class="text-muted">{!! $chapter->searchSnippet !!}</p>
     @else
@@ -20,7 +20,7 @@
         <p class="text-muted chapter-toggle"><i class="zmdi zmdi-caret-right"></i> <i class="zmdi zmdi-file-text"></i> <span>{{ count($chapter->pages) }} Pages</span></p>
         <div class="inset-list">
             @foreach($chapter->pages as $page)
-                <h4 class="@if($page->draft) draft @endif"><a href="{{ $page->getUrl() }}" class="text-page @if($page->draft) draft @endif"><i class="zmdi zmdi-file-text"></i>{{$page->name}}</a></h4>
+                <h5 class="@if($page->draft) draft @endif"><a href="{{ $page->getUrl() }}" class="text-page @if($page->draft) draft @endif"><i class="zmdi zmdi-file-text"></i>{{$page->name}}</a></h5>
             @endforeach
         </div>
     @endif
diff --git a/resources/views/emails/email-confirmation.blade.php b/resources/views/emails/email-confirmation.blade.php
deleted file mode 100644 (file)
index 6a0dc03..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"
-      style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">
-
-<head style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">
-    <meta name="viewport" content="width=device-width"
-          style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;"/>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
-          style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;"/>
-    <title>Confirm Your Email At {{ setting('app-name')}}</title>
-    <style style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">
-        * {
-            margin: 0;
-            padding: 0;
-            font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif;
-            font-size: 100%;
-            line-height: 1.6;
-        }
-
-        img {
-            max-width: 100%;
-        }
-
-        body {
-            -webkit-font-smoothing: antialiased;
-            -webkit-text-size-adjust: none;
-            width: 100% !important;
-            height: 100%;
-        }
-
-        a {
-            color: #348eda;
-        }
-
-        .btn-primary {
-            text-decoration: none;
-            color: #FFF;
-            background-color: #348eda;
-            border: solid #348eda;
-            border-width: 10px 20px;
-            line-height: 2;
-            font-weight: bold;
-            margin-right: 10px;
-            text-align: center;
-            cursor: pointer;
-            display: inline-block;
-            border-radius: 4px;
-        }
-
-        .btn-secondary {
-            text-decoration: none;
-            color: #FFF;
-            background-color: #aaa;
-            border: solid #aaa;
-            border-width: 10px 20px;
-            line-height: 2;
-            font-weight: bold;
-            margin-right: 10px;
-            text-align: center;
-            cursor: pointer;
-            display: inline-block;
-            border-radius: 25px;
-        }
-
-        .last {
-            margin-bottom: 0;
-        }
-
-        .first {
-            margin-top: 0;
-        }
-
-        .padding {
-            padding: 10px 0;
-        }
-
-        table.body-wrap {
-            width: 100%;
-            padding: 20px;
-        }
-
-        table.body-wrap .container {
-            border: 1px solid #f0f0f0;
-        }
-
-        h1,
-        h2,
-        h3 {
-            font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
-            color: #444;
-            margin: 10px 0 10px;
-            line-height: 1.2;
-            font-weight: 200;
-        }
-
-        h1 {
-            font-size: 36px;
-        }
-
-        h2 {
-            font-size: 28px;
-        }
-
-        h3 {
-            font-size: 22px;
-        }
-
-        p,
-        ul,
-        ol {
-            margin-bottom: 10px;
-            font-weight: normal;
-            font-size: 14px;
-            color: #888888;
-        }
-
-        ul li,
-        ol li {
-            margin-left: 5px;
-            list-style-position: inside;
-        }
-
-        .container {
-            display: block !important;
-            max-width: 600px !important;
-            margin: 0 auto !important;
-            clear: both !important;
-        }
-
-        .body-wrap .container {
-            padding: 20px;
-        }
-
-        .content {
-            max-width: 600px;
-            margin: 0 auto;
-            display: block;
-        }
-
-        .content table {
-            width: 100%;
-        }
-    </style>
-</head>
-
-<body bgcolor="#f6f6f6"
-      style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:none;width:100%!important;height:100%;">
-<!-- body -->
-<table class="body-wrap" bgcolor="#f6f6f6"
-       style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;width:100%;padding-top:20px;padding-bottom:20px;padding-right:20px;padding-left:20px;">
-    <tr style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">
-        <td style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;"></td>
-        <td class="container" bgcolor="#FFFFFF"
-            style="font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;display:block!important;max-width:600px!important;margin-top:0 !important;margin-bottom:0 !important;margin-right:auto !important;margin-left:auto !important;clear:both!important;padding-top:20px;padding-bottom:20px;padding-right:20px;padding-left:20px;border-width:1px;border-style:solid;border-color:#f0f0f0;">
-            <!-- content -->
-            <div class="content"
-                 style="padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;max-width:600px;margin-top:0;margin-bottom:0;margin-right:auto;margin-left:auto;display:block;">
-                <table style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;width:100%;">
-                    <tr style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">
-                        <td style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">
-                            <h1 style="padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif;color:#444;margin-top:10px;margin-bottom:10px;margin-right:0;margin-left:0;line-height:1.2;font-weight:200;font-size:36px;">
-                                Email Confirmation</h1>
-                            <p style="margin-top:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;line-height:1.6;margin-bottom:10px;font-weight:normal;font-size:14px;color:#888888;">
-                                Thanks for joining <a href="{{ baseUrl('/') }}">{{ setting('app-name')}}</a>. <br/>
-                                Please confirm your email address by clicking the button below.</p>
-                            <table style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;width:100%;">
-                                <tr style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">
-                                    <td class="padding"
-                                        style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;padding-top:10px;padding-bottom:10px;padding-right:0;padding-left:0;">
-                                        <p style="margin-top:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;line-height:1.6;margin-bottom:10px;font-weight:normal;font-size:14px;color:#888888;">
-                                            <a class="btn-primary" href="{{ baseUrl('/register/confirm/' . $token) }}"
-                                               style="margin-top:0;margin-bottom:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;text-decoration:none;color:#FFF;background-color:#348eda;border-style:solid;border-color:#348eda;border-width:10px 20px;line-height:2;font-weight:bold;margin-right:10px;text-align:center;cursor:pointer;display:inline-block;border-radius:4px;">Confirm
-                                                Email</a></p>
-                                    </td>
-                                </tr>
-                            </table>
-                        </td>
-                    </tr>
-                </table>
-            </div>
-            <!-- /content -->
-        </td>
-        <td style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;"></td>
-    </tr>
-</table>
-<!-- /body -->
-</body>
-
-</html>
diff --git a/resources/views/emails/password.blade.php b/resources/views/emails/password.blade.php
deleted file mode 100644 (file)
index dfd8f3d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\r        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r<html xmlns="http://www.w3.org/1999/xhtml"\r      style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">\r\r<head style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">\r    <meta name="viewport" content="width=device-width"\r          style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;"/>\r    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"\r          style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;"/>\r    <title>Password Reset From {{ setting('app-name')}}</title>\r    <style style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">\r        * {\r            margin: 0;\r            padding: 0;\r            font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif;\r            font-size: 100%;\r            line-height: 1.6;\r        }\r\r        img {\r            max-width: 100%;\r        }\r\r        body {\r            -webkit-font-smoothing: antialiased;\r            -webkit-text-size-adjust: none;\r            width: 100% !important;\r            height: 100%;\r        }\r\r        a {\r            color: #348eda;\r        }\r\r        .btn-primary {\r            text-decoration: none;\r            color: #FFF;\r            background-color: #348eda;\r            border: solid #348eda;\r            border-width: 10px 20px;\r            line-height: 2;\r            font-weight: bold;\r            margin-right: 10px;\r            text-align: center;\r            cursor: pointer;\r            display: inline-block;\r            border-radius: 4px;\r        }\r\r        .btn-secondary {\r            text-decoration: none;\r            color: #FFF;\r            background-color: #aaa;\r            border: solid #aaa;\r            border-width: 10px 20px;\r            line-height: 2;\r            font-weight: bold;\r            margin-right: 10px;\r            text-align: center;\r            cursor: pointer;\r            display: inline-block;\r            border-radius: 25px;\r        }\r\r        .last {\r            margin-bottom: 0;\r        }\r\r        .first {\r            margin-top: 0;\r        }\r\r        .padding {\r            padding: 10px 0;\r        }\r\r        table.body-wrap {\r            width: 100%;\r            padding: 20px;\r        }\r\r        table.body-wrap .container {\r            border: 1px solid #f0f0f0;\r        }\r\r        h1,\r        h2,\r        h3 {\r            font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;\r            color: #444;\r            margin: 10px 0 10px;\r            line-height: 1.2;\r            font-weight: 200;\r        }\r\r        h1 {\r            font-size: 36px;\r        }\r\r        h2 {\r            font-size: 28px;\r        }\r\r        h3 {\r            font-size: 22px;\r        }\r\r        p,\r        ul,\r        ol {\r            margin-bottom: 10px;\r            font-weight: normal;\r            font-size: 14px;\r            color: #888888;\r        }\r\r        ul li,\r        ol li {\r            margin-left: 5px;\r            list-style-position: inside;\r        }\r\r        .container {\r            display: block !important;\r            max-width: 600px !important;\r            margin: 0 auto !important;\r            clear: both !important;\r        }\r\r        .body-wrap .container {\r            padding: 20px;\r        }\r\r        .content {\r            max-width: 600px;\r            margin: 0 auto;\r            display: block;\r        }\r\r        .content table {\r            width: 100%;\r        }\r    </style>\r</head>\r\r<body bgcolor="#f6f6f6"\r      style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:none;width:100%!important;height:100%;">\r<!-- body -->\r<table class="body-wrap" bgcolor="#f6f6f6"\r       style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;width:100%;padding-top:20px;padding-bottom:20px;padding-right:20px;padding-left:20px;">\r    <tr style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">\r        <td style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;"></td>\r        <td class="container" bgcolor="#FFFFFF"\r            style="font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;display:block!important;max-width:600px!important;margin-top:0 !important;margin-bottom:0 !important;margin-right:auto !important;margin-left:auto !important;clear:both!important;padding-top:20px;padding-bottom:20px;padding-right:20px;padding-left:20px;border-width:1px;border-style:solid;border-color:#f0f0f0;">\r            <!-- content -->\r            <div class="content"\r                 style="padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;max-width:600px;margin-top:0;margin-bottom:0;margin-right:auto;margin-left:auto;display:block;">\r                <table style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;width:100%;">\r                    <tr style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">\r                        <td style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">\r                            <h1 style="padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif;color:#444;margin-top:10px;margin-bottom:10px;margin-right:0;margin-left:0;line-height:1.2;font-weight:200;font-size:36px;">\r                                Password Reset</h1>\r                            <p style="margin-top:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;line-height:1.6;margin-bottom:10px;font-weight:normal;font-size:14px;color:#888888;">\r                                A password reset was requested for this email address on <a\r                                        href="{{ baseUrl('/') }}">{{ setting('app-name')}}</a>. If you did not request\r                                a password change please ignore this email.</p>\r                            <table style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;width:100%;">\r                                <tr style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;">\r                                    <td class="padding"\r                                        style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;padding-top:10px;padding-bottom:10px;padding-right:0;padding-left:0;">\r                                        <p style="margin-top:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;line-height:1.6;margin-bottom:10px;font-weight:normal;font-size:14px;color:#888888;">\r                                            <a class="btn-primary" href="{{ baseUrl('/password/reset/' . $token) }}"\r                                               style="margin-top:0;margin-bottom:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;text-decoration:none;color:#FFF;background-color:#348eda;border-style:solid;border-color:#348eda;border-width:10px 20px;line-height:2;font-weight:bold;margin-right:10px;text-align:center;cursor:pointer;display:inline-block;border-radius:4px;">Click\r                                                here to reset your password</a></p>\r                                    </td>\r                                </tr>\r                            </table>\r                        </td>\r                    </tr>\r                </table>\r            </div>\r            <!-- /content -->\r        </td>\r        <td style="margin-top:0;margin-bottom:0;margin-right:0;margin-left:0;padding-top:0;padding-bottom:0;padding-right:0;padding-left:0;font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;font-size:100%;line-height:1.6;"></td>\r    </tr>\r</table>\r<!-- /body -->\r</body>\r\r</html>\r
\ No newline at end of file
index 2529c39c7f77fb81b5b3cc082ade0b2ec422bd28..2fb4ac85597cca57cc0f26d6e86bde9a55efb881 100644 (file)
             <div class="col-sm-4">
                 <div id="recent-drafts">
                     @if(count($draftPages) > 0)
-                        <h3>My Recent Drafts</h3>
+                        <h4>My Recent Drafts</h4>
                         @include('partials/entity-list', ['entities' => $draftPages, 'style' => 'compact'])
                     @endif
                 </div>
                 @if($signedIn)
-                    <h3>My Recently Viewed</h3>
+                    <h4>My Recently Viewed</h4>
                 @else
-                    <h3>Recent Books</h3>
+                    <h4>Recent Books</h4>
                 @endif
                 @include('partials/entity-list', [
                 'entities' => $recents,
@@ -42,7 +42,7 @@
             </div>
 
             <div class="col-sm-4">
-                <h3><a class="no-color" href="{{ baseUrl("/pages/recently-created") }}">Recently Created Pages</a></h3>
+                <h4><a class="no-color" href="{{ baseUrl("/pages/recently-created") }}">Recently Created Pages</a></h4>
                 <div id="recently-created-pages">
                     @include('partials/entity-list', [
                     'entities' => $recentlyCreatedPages,
@@ -51,7 +51,7 @@
                     ])
                 </div>
 
-                <h3><a class="no-color" href="{{ baseUrl("/pages/recently-updated") }}">Recently Updated Pages</a></h3>
+                <h4><a class="no-color" href="{{ baseUrl("/pages/recently-updated") }}">Recently Updated Pages</a></h4>
                 <div id="recently-updated-pages">
                     @include('partials/entity-list', [
                     'entities' => $recentlyUpdatedPages,
@@ -62,7 +62,7 @@
             </div>
 
             <div class="col-sm-4" id="recent-activity">
-                <h3>Recent Activity</h3>
+                <h4>Recent Activity</h4>
                 @include('partials/activity-list', ['activity' => $activity])
             </div>
 
index 98243f6fa88ba63a2d09c20af659917025348186..7aa5d7933fb6661968fdb38aa12e0f1fea2259fe 100644 (file)
@@ -1,7 +1,7 @@
 <div class="page {{$page->draft ? 'draft' : ''}} entity-list-item" data-entity-type="page" data-entity-id="{{$page->id}}">
-    <h3>
+    <h4>
         <a href="{{ $page->getUrl() }}" class="text-page entity-list-item-link"><i class="zmdi zmdi-file-text"></i><span class="entity-list-item-name">{{ $page->name }}</span></a>
-    </h3>
+    </h4>
 
     @if(isset($page->searchSnippet))
         <p class="text-muted">{!! $page->searchSnippet !!}</p>
index 2e6e35476d9773d568f1aff4a7325a09d47a1b6c..af85075a204981b84e2644d5f93ea6eec1a3046b 100644 (file)
                         @endif
                     </div>
                 @endif
-                @include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree])
+
+                @include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree, 'pageNav' => $pageNav])
             </div>
 
         </div>
index e40fdbf0fcaa28d673aeea356246a05894ea6fc3..5fcec8731ee098620366f836c346551a35530c2c 100644 (file)
@@ -1,5 +1,19 @@
 
 <div class="book-tree" ng-non-bindable>
+
+    @if (isset($pageNav) && $pageNav)
+        <h6 class="text-muted">Page Navigation</h6>
+        <div class="sidebar-page-nav menu">
+            @foreach($pageNav as $navItem)
+                <li class="page-nav-item {{ $navItem['nodeName'] }}">
+                    <a href="{{ $navItem['link'] }}">{{ $navItem['text'] }}</a>
+                </li>
+            @endforeach
+        </div>
+
+
+    @endif
+
     <h6 class="text-muted">Book Navigation</h6>
     <ul class="sidebar-page-list menu">
         <li class="book-header"><a href="{{ $book->getUrl() }}" class="book {{ $current->matches($book)? 'selected' : '' }}"><i class="zmdi zmdi-book"></i>{{$book->name}}</a></li>
index 2de4d968a650fe6310684e2be8d1c3f636f60617..542d5c8679add17afe29e4070f456616fc21cbf8 100644 (file)
@@ -31,7 +31,9 @@
                     @if(setting('app-logo', '') !== 'none')
                         <img class="logo-image" src="{{ setting('app-logo', '') === '' ? baseUrl('/logo.png') : baseUrl(setting('app-logo', '')) }}" alt="Logo">
                     @endif
-                    <span class="logo-text">{{ setting('app-name') }}</span>
+                    @if (setting('app-name-header'))
+                        <span class="logo-text">{{ setting('app-name') }}</span>
+                    @endif
                 </a>
             </div>
             <div class="col-md-6">
index 222ff0f690492dddcd8c0c91365ba18a96c68cd1..757729763a17542cce69d13eabb6726ce7dad77e 100644 (file)
@@ -6,7 +6,7 @@
 
 <div class="container small settings-container">
 
-    <h1>Settings</h1>
+    <h1>{{ trans('settings.settings') }}</h1>
 
     <form action="{{ baseUrl("/settings") }}" method="POST" ng-cloak>
         {!! csrf_field() !!}
         <h3>App Settings</h3>
 
         <div class="row">
+
             <div class="col-md-6">
                 <div class="form-group">
-                    <label for="setting-app-name">Application name</label>
+                    <label for="setting-app-name">{{ trans('settings.app_name') }}</label>
+                    <p class="small">{{ trans('settings.app_name_desc') }}</p>
                     <input type="text" value="{{ setting('app-name', 'BookStack') }}" name="setting-app-name" id="setting-app-name">
                 </div>
                 <div class="form-group">
-                    <label>Allow public viewing?</label>
+                    <label>{{ trans('settings.app_name_header') }}</label>
+                    <div toggle-switch name="setting-app-name-header" value="{{ setting('app-name-header') }}"></div>
+                </div>
+                <div class="form-group">
+                    <label for="setting-app-public">{{ trans('settings.app_public_viewing') }}</label>
                     <div toggle-switch name="setting-app-public" value="{{ setting('app-public') }}"></div>
                 </div>
                 <div class="form-group">
-                    <label>Enable higher security image uploads?</label>
-                    <p class="small">For performance reasons, all images are public. This option adds a random, hard-to-guess string in front of image urls. Ensure directory indexes are not enabled to prevent easy access.</p>
+                    <label>{{ trans('settings.app_secure_images') }}</label>
+                    <p class="small">{{ trans('settings.app_secure_images_desc') }}</p>
                     <div toggle-switch name="setting-app-secure-images" value="{{ setting('app-secure-images') }}"></div>
                 </div>
                 <div class="form-group">
-                    <label for="setting-app-editor">Page editor</label>
-                    <p class="small">Select which editor will be used by all users to edit pages.</p>
+                    <label for="setting-app-editor">{{ trans('settings.app_editor') }}</label>
+                    <p class="small">{{ trans('settings.app_editor_desc') }}</p>
                     <select name="setting-app-editor" id="setting-app-editor">
                         <option @if(setting('app-editor') === 'wysiwyg') selected @endif value="wysiwyg">WYSIWYG</option>
                         <option @if(setting('app-editor') === 'markdown') selected @endif value="markdown">Markdown</option>
                     </select>
                 </div>
             </div>
+
             <div class="col-md-6">
                 <div class="form-group" id="logo-control">
-                    <label for="setting-app-logo">Application logo</label>
-                    <p class="small">This image should be 43px in height. <br>Large images will be scaled down.</p>
+                    <label for="setting-app-logo">{{ trans('settings.app_logo') }}</label>
+                    <p class="small">{!! trans('settings.app_logo_desc') !!}</p>
                     <image-picker resize-height="43" show-remove="true" resize-width="200" current-image="{{ setting('app-logo', '') }}" default-image="{{ baseUrl('/logo.png') }}" name="setting-app-logo" image-class="logo-image"></image-picker>
                 </div>
                 <div class="form-group" id="color-control">
-                    <label for="setting-app-color">Application primary color</label>
-                    <p class="small">This should be a hex value. <br> Leave empty to reset to the default color.</p>
+                    <label for="setting-app-color">{{ trans('settings.app_primary_color') }}</label>
+                    <p class="small">{!! trans('settings.app_primary_color_desc') !!}</p>
                     <input  type="text" value="{{ setting('app-color', '') }}" name="setting-app-color" id="setting-app-color" placeholder="#0288D1">
                     <input  type="hidden" value="{{ setting('app-color-light', '') }}" name="setting-app-color-light" id="setting-app-color-light" placeholder="rgba(21, 101, 192, 0.15)">
                 </div>
             </div>
+
         </div>
+
         <div class="form-group">
-            <label for="setting-app-custom-head">Custom HTML head content</label>
-            <p class="small">Any content added here will be inserted into the bottom of the &lt;head&gt; section of every page. This is handy for overriding styles or adding analytics code.</p>
+            <label for="setting-app-custom-head">{{ trans('settings.app_custom_html') }}</label>
+            <p class="small">{{ trans('settings.app_custom_html_desc') }}</p>
             <textarea name="setting-app-custom-head" id="setting-app-custom-head">{{ setting('app-custom-head', '') }}</textarea>
         </div>
 
         <hr class="margin-top">
 
-        <h3>Registration Settings</h3>
+        <h3>{{ trans('settings.reg_settings') }}</h3>
 
         <div class="row">
             <div class="col-md-6">
                 <div class="form-group">
-                    <label for="setting-registration-enabled">Allow registration?</label>
+                    <label for="setting-registration-enabled">{{ trans('settings.reg_allow') }}</label>
                     <div toggle-switch name="setting-registration-enabled" value="{{ setting('registration-enabled') }}"></div>
                 </div>
                 <div class="form-group">
-                    <label for="setting-registration-role">Default user role after registration</label>
+                    <label for="setting-registration-role">{{ trans('settings.reg_default_role') }}</label>
                     <select id="setting-registration-role" name="setting-registration-role" @if($errors->has('setting-registration-role')) class="neg" @endif>
                         @foreach(\BookStack\Role::visible() as $role)
                             <option value="{{$role->id}}" data-role-name="{{ $role->name }}"
                     </select>
                 </div>
                 <div class="form-group">
-                    <label for="setting-registration-confirmation">Require email confirmation?</label>
-                    <p class="small">If domain restriction is used then email confirmation will be required and the below value will be ignored.</p>
+                    <label for="setting-registration-confirmation">{{ trans('settings.reg_confirm_email') }}</label>
+                    <p class="small">{{ trans('settings.reg_confirm_email_desc') }}</p>
                     <div toggle-switch name="setting-registration-confirmation" value="{{ setting('registration-confirmation') }}"></div>
                 </div>
             </div>
             <div class="col-md-6">
                 <div class="form-group">
-                    <label for="setting-registration-restrict">Restrict registration to domain</label>
-                    <p class="small">Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application.
-                        <br> Note that users will be able to change their email addresses after successful registration.</p>
-                    <input type="text" id="setting-registration-restrict" name="setting-registration-restrict" placeholder="No restriction set" value="{{ setting('registration-restrict', '') }}">
+                    <label for="setting-registration-restrict">{{ trans('settings.reg_confirm_restrict_domain') }}</label>
+                    <p class="small">{!! trans('settings.reg_confirm_restrict_domain_desc') !!}</p>
+                    <input type="text" id="setting-registration-restrict" name="setting-registration-restrict" placeholder="{{ trans('settings.reg_confirm_restrict_domain_placeholder') }}" value="{{ setting('registration-restrict', '') }}">
                 </div>
             </div>
         </div>
             <span class="float right muted">
                 BookStack @if(strpos($version, 'v') !== 0) version @endif {{ $version }}
             </span>
-            <button type="submit" class="button pos">Save Settings</button>
+            <button type="submit" class="button pos">{{ trans('settings.settings_save') }}</button>
         </div>
     </form>
 
index e72a9e61a5df113d041190cde8707ccbd6d56749..105fddb5ba55d232cd69fd684006dd6070dab0ae 100644 (file)
@@ -22,7 +22,7 @@
         <div class="row">
             <div class="col-sm-8">
                 <div class="compact">
-                    {!! $users->links() !!}
+                    {{ $users->links() }}
                 </div>
             </div>
             <div class="col-sm-4">
@@ -76,7 +76,7 @@
         </table>
 
         <div>
-            {!! $users->links() !!}
+            {{ $users->links() }}
         </div>
     </div>
 
diff --git a/resources/views/vendor/.gitkeep b/resources/views/vendor/.gitkeep
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/resources/views/vendor/notifications/email-plain.blade.php b/resources/views/vendor/notifications/email-plain.blade.php
new file mode 100644 (file)
index 0000000..acefa65
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+
+if (! empty($greeting)) {
+    echo $greeting, "\n\n";
+} else {
+    echo $level == 'error' ? 'Whoops!' : 'Hello!', "\n\n";
+}
+
+if (! empty($introLines)) {
+    echo implode("\n", $introLines), "\n\n";
+}
+
+if (isset($actionText)) {
+    echo "{$actionText}: {$actionUrl}", "\n\n";
+}
+
+if (! empty($outroLines)) {
+    echo implode("\n", $outroLines), "\n\n";
+}
+
+echo 'Regards,', "\n";
+echo config('app.name'), "\n";
diff --git a/resources/views/vendor/notifications/email.blade.php b/resources/views/vendor/notifications/email.blade.php
new file mode 100644 (file)
index 0000000..297c6be
--- /dev/null
@@ -0,0 +1,206 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+    <style type="text/css" rel="stylesheet" media="all">
+        /* Media Queries */
+        @media only screen and (max-width: 500px) {
+            .button {
+                width: 100% !important;
+            }
+        }
+
+        @media only screen and (max-width: 600px) {
+            .button {
+                width: 100% !important;
+            }
+            .mobile {
+                max-width: 100%;
+                display: block;
+                width: 100%;
+            }
+        }
+    </style>
+</head>
+
+<?php
+
+$style = [
+    /* Layout ------------------------------ */
+
+    'body' => 'margin: 0; padding: 0; width: 100%; background-color: #F2F4F6;',
+    'email-wrapper' => 'width: 100%; margin: 0; padding: 0; background-color: #F2F4F6;',
+
+    /* Masthead ----------------------- */
+
+    'email-masthead' => 'padding: 25px 0; text-align: center;',
+    'email-masthead_name' => 'font-size: 24px; font-weight: 400; color: #2F3133; text-decoration: none; text-shadow: 0 1px 0 white;',
+
+    'email-body' => 'width: 100%; margin: 0; padding: 0; border-top: 4px solid '.setting('app-color').'; border-bottom: 1px solid #EDEFF2; background-color: #FFF;',
+    'email-body_inner' => 'width: auto; max-width: 100%; margin: 0 auto; padding: 0;',
+    'email-body_cell' => 'padding: 35px;',
+
+    'email-footer' => 'width: auto; max-width: 570px; margin: 0 auto; padding: 0; text-align: center;',
+    'email-footer_cell' => 'color: #AEAEAE; padding: 35px; text-align: center;',
+
+    /* Body ------------------------------ */
+
+    'body_action' => 'width: 100%; margin: 30px auto; padding: 0; text-align: center;',
+    'body_sub' => 'margin-top: 25px; padding-top: 25px; border-top: 1px solid #EDEFF2;',
+
+    /* Type ------------------------------ */
+
+    'anchor' => 'color: '.setting('app-color').';overflow-wrap: break-word;word-wrap: break-word;word-break: break-all;word-break:break-word;',
+    'header-1' => 'margin-top: 0; color: #2F3133; font-size: 19px; font-weight: bold; text-align: left;',
+    'paragraph' => 'margin-top: 0; color: #74787E; font-size: 16px; line-height: 1.5em;',
+    'paragraph-sub' => 'margin-top: 0; color: #74787E; font-size: 12px; line-height: 1.5em;',
+    'paragraph-center' => 'text-align: center;',
+
+    /* Buttons ------------------------------ */
+
+    'button' => 'display: block; display: inline-block; width: 200px; min-height: 20px; padding: 10px;
+                 background-color: #3869D4; border-radius: 3px; color: #ffffff; font-size: 15px; line-height: 25px;
+                 text-align: center; text-decoration: none; -webkit-text-size-adjust: none;',
+
+    'button--green' => 'background-color: #22BC66;',
+    'button--red' => 'background-color: #dc4d2f;',
+    'button--blue' => 'background-color: '.setting('app-color').';',
+];
+?>
+
+<?php $fontFamily = 'font-family: Arial, \'Helvetica Neue\', Helvetica, sans-serif;'; ?>
+
+<body style="{{ $style['body'] }}">
+    <table width="100%" cellpadding="0" cellspacing="0">
+        <tr>
+            <td align="center" class="mobile">
+                <table width="600" style="max-width: 100%; padding: 12px;text-align: left;" cellpadding="0" cellspacing="0" class="mobile">
+                    <tr>
+                        <td style="{{ $style['email-wrapper'] }}" align="center">
+                            <table width="100%" cellpadding="0" cellspacing="0">
+                                <!-- Logo -->
+                                <tr>
+                                    <td style="{{ $style['email-masthead'] }}">
+                                        <a style="{{ $fontFamily }} {{ $style['email-masthead_name'] }}" href="{{ baseUrl('/') }}" target="_blank">
+                                            {{ setting('app-name') }}
+                                        </a>
+                                    </td>
+                                </tr>
+
+                                <!-- Email Body -->
+                                <tr>
+                                    <td style="{{ $style['email-body'] }}" width="100%">
+                                        <table style="{{ $style['email-body_inner'] }}" align="center" width="100%" cellpadding="0" cellspacing="0">
+                                            <tr>
+                                                <td style="{{ $fontFamily }} {{ $style['email-body_cell'] }}">
+
+                                                    <!-- Greeting -->
+                                                    @if (!empty($greeting) || $level == 'error')
+                                                    <h1 style="{{ $style['header-1'] }}">
+                                                        @if (! empty($greeting))
+                                                            {{ $greeting }}
+                                                        @else
+                                                            @if ($level == 'error')
+                                                                Whoops!
+                                                            @endif
+                                                        @endif
+                                                    </h1>
+                                                    @endif
+
+                                                    <!-- Intro -->
+                                                    @foreach ($introLines as $line)
+                                                        <p style="{{ $style['paragraph'] }}">
+                                                            {{ $line }}
+                                                        </p>
+                                                    @endforeach
+
+                                                    <!-- Action Button -->
+                                                    @if (isset($actionText))
+                                                        <table style="{{ $style['body_action'] }}" align="center" width="100%" cellpadding="0" cellspacing="0">
+                                                            <tr>
+                                                                <td align="center">
+                                                                    <?php
+                                                                    switch ($level) {
+                                                                        case 'success':
+                                                                            $actionColor = 'button--green';
+                                                                            break;
+                                                                        case 'error':
+                                                                            $actionColor = 'button--red';
+                                                                            break;
+                                                                        default:
+                                                                            $actionColor = 'button--blue';
+                                                                    }
+                                                                    ?>
+
+                                                                    <a href="{{ $actionUrl }}"
+                                                                       style="{{ $fontFamily }} {{ $style['button'] }} {{ $style[$actionColor] }}"
+                                                                       class="button"
+                                                                       target="_blank">
+                                                                        {{ $actionText }}
+                                                                    </a>
+                                                                </td>
+                                                            </tr>
+                                                        </table>
+                                                    @endif
+
+                                                    <!-- Outro -->
+                                                    @foreach ($outroLines as $line)
+                                                        <p style="{{ $style['paragraph'] }}">
+                                                            {{ $line }}
+                                                        </p>
+                                                    @endforeach
+
+
+                                                    <!-- Sub Copy -->
+                                                    @if (isset($actionText))
+                                                        <table style="{{ $style['body_sub'] }}">
+                                                            <tr>
+                                                                <td style="{{ $fontFamily }}">
+                                                                    <p style="{{ $style['paragraph-sub'] }}">
+                                                                        If you’re having trouble clicking the "{{ $actionText }}" button,
+                                                                        copy and paste the URL below into your web browser:
+                                                                    </p>
+
+                                                                    <p style="{{ $style['paragraph-sub'] }}">
+                                                                        <a style="{{ $style['anchor'] }}" href="{{ $actionUrl }}" target="_blank">
+                                                                            {{ $actionUrl }}
+                                                                        </a>
+                                                                    </p>
+                                                                </td>
+                                                            </tr>
+                                                        </table>
+                                                    @endif
+
+                                                </td>
+                                            </tr>
+                                        </table>
+                                    </td>
+                                </tr>
+
+                                <!-- Footer -->
+                                <tr>
+                                    <td>
+                                        <table style="{{ $style['email-footer'] }}" align="center" width="100%" cellpadding="0" cellspacing="0">
+                                            <tr>
+                                                <td style="{{ $fontFamily }} {{ $style['email-footer_cell'] }}">
+                                                    <p style="{{ $style['paragraph-sub'] }}">
+                                                        &copy; {{ date('Y') }}
+                                                        <a style="{{ $style['anchor'] }}" href="{{ baseUrl('/') }}" target="_blank">{{ setting('app-name') }}</a>.
+                                                        All rights reserved.
+                                                    </p>
+                                                </td>
+                                            </tr>
+                                        </table>
+                                    </td>
+                                </tr>
+                            </table>
+                        </td>
+                    </tr>
+                </table>
+            </td>
+        </tr>
+    </table>
+</body>
+</html>
similarity index 84%
rename from app/Http/routes.php
rename to routes/web.php
index eb35f2a119846bd87836b3ff4b7ff156f242c89a..58ceb5f3b6930208654024a81c203d0c30e5ef2a 100644 (file)
@@ -139,27 +139,27 @@ Route::group(['middleware' => 'auth'], function () {
 
 });
 
-// Login using social authentication
-Route::get('/login/service/{socialDriver}', 'Auth\AuthController@getSocialLogin');
-Route::get('/login/service/{socialDriver}/callback', 'Auth\AuthController@socialCallback');
-Route::get('/login/service/{socialDriver}/detach', 'Auth\AuthController@detachSocialAccount');
+// Social auth routes
+Route::get('/login/service/{socialDriver}', 'Auth\RegisterController@getSocialLogin');
+Route::get('/login/service/{socialDriver}/callback', 'Auth\RegisterController@socialCallback');
+Route::get('/login/service/{socialDriver}/detach', 'Auth\RegisterController@detachSocialAccount');
+Route::get('/register/service/{socialDriver}', 'Auth\RegisterController@socialRegister');
 
 // Login/Logout routes
-Route::get('/login', 'Auth\AuthController@getLogin');
-Route::post('/login', 'Auth\AuthController@postLogin');
-Route::get('/logout', 'Auth\AuthController@getLogout');
-Route::get('/register', 'Auth\AuthController@getRegister');
-Route::get('/register/confirm', 'Auth\AuthController@getRegisterConfirmation');
-Route::get('/register/confirm/awaiting', 'Auth\AuthController@showAwaitingConfirmation');
-Route::post('/register/confirm/resend', 'Auth\AuthController@resendConfirmation');
-Route::get('/register/confirm/{token}', 'Auth\AuthController@confirmEmail');
-Route::get('/register/confirm/{token}/email', 'Auth\AuthController@viewConfirmEmail');
-Route::get('/register/service/{socialDriver}', 'Auth\AuthController@socialRegister');
-Route::post('/register', 'Auth\AuthController@postRegister');
+Route::get('/login', 'Auth\LoginController@getLogin');
+Route::post('/login', 'Auth\LoginController@login');
+Route::get('/logout', 'Auth\LoginController@logout');
+Route::get('/register', 'Auth\RegisterController@getRegister');
+Route::get('/register/confirm', 'Auth\RegisterController@getRegisterConfirmation');
+Route::get('/register/confirm/awaiting', 'Auth\RegisterController@showAwaitingConfirmation');
+Route::post('/register/confirm/resend', 'Auth\RegisterController@resendConfirmation');
+Route::get('/register/confirm/{token}', 'Auth\RegisterController@confirmEmail');
+Route::post('/register', 'Auth\RegisterController@postRegister');
 
 // Password reset link request routes...
-Route::get('/password/email', 'Auth\PasswordController@getEmail');
-Route::post('/password/email', 'Auth\PasswordController@postEmail');
+Route::get('/password/email', 'Auth\ForgotPasswordController@showLinkRequestForm');
+Route::post('/password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail');
+
 // Password reset routes...
-Route::get('/password/reset/{token}', 'Auth\PasswordController@getReset');
-Route::post('/password/reset', 'Auth\PasswordController@postReset');
\ No newline at end of file
+Route::get('/password/reset/{token}', 'Auth\ResetPasswordController@showResetForm');
+Route::post('/password/reset', 'Auth\ResetPasswordController@reset');
\ No newline at end of file
index 306771ed5a98883b4fb87b2242ecd90709a054fc..0affff799919c1e894f0c15dc9fe8254b7b1676c 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
-use BookStack\EmailConfirmation;
+use BookStack\Notifications\ConfirmEmail;
+use Illuminate\Support\Facades\Notification;
 
 class AuthTest extends TestCase
 {
@@ -57,15 +58,13 @@ class AuthTest extends TestCase
 
     public function test_confirmed_registration()
     {
+        // Fake notifications
+        Notification::fake();
+
         // Set settings and get user instance
         $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
         $user = factory(\BookStack\User::class)->make();
 
-        // Mock Mailer to ensure mail is being sent
-        $mockMailer = Mockery::mock('Illuminate\Contracts\Mail\Mailer');
-        $mockMailer->shouldReceive('send')->with('emails/email-confirmation', Mockery::type('array'), Mockery::type('callable'))->twice();
-        $this->app->instance('mailer', $mockMailer);
-
         // Go through registration process
         $this->visit('/register')
             ->see('Sign Up')
@@ -76,6 +75,10 @@ class AuthTest extends TestCase
             ->seePageIs('/register/confirm')
             ->seeInDatabase('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
 
+        // Ensure notification sent
+        $dbUser = \BookStack\User::where('email', '=', $user->email)->first();
+        Notification::assertSentTo($dbUser, ConfirmEmail::class);
+
         // Test access and resend confirmation email
         $this->login($user->email, $user->password)
             ->seePageIs('/register/confirm/awaiting')
@@ -84,19 +87,18 @@ class AuthTest extends TestCase
             ->seePageIs('/register/confirm/awaiting')
             ->press('Resend Confirmation Email');
 
-        // Get confirmation
-        $user = $user->where('email', '=', $user->email)->first();
-        $emailConfirmation = EmailConfirmation::where('user_id', '=', $user->id)->first();
-
-
-        // Check confirmation email button and confirmation activation.
-        $this->visit('/register/confirm/' . $emailConfirmation->token . '/email')
-            ->see('Email Confirmation')
-            ->click('Confirm Email')
+        // Get confirmation and confirm notification matches
+        $emailConfirmation = DB::table('email_confirmations')->where('user_id', '=', $dbUser->id)->first();
+        Notification::assertSentTo($dbUser, ConfirmEmail::class, function($notification, $channels) use ($emailConfirmation) {
+            return $notification->token === $emailConfirmation->token;
+        });
+        
+        // Check confirmation email confirmation activation.
+        $this->visit('/register/confirm/' . $emailConfirmation->token)
             ->seePageIs('/')
             ->see($user->name)
             ->notSeeInDatabase('email_confirmations', ['token' => $emailConfirmation->token])
-            ->seeInDatabase('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => true]);
+            ->seeInDatabase('users', ['name' => $dbUser->name, 'email' => $dbUser->email, 'email_confirmed' => true]);
     }
 
     public function test_restricted_registration()
index 296aa72edc1491ae703e3fab90a92b15db85cf7e..20721968f9a88c933d41cfa9efbb60c5cc652437 100644 (file)
@@ -236,8 +236,9 @@ class EntityTest extends TestCase
             ->type('super test page', '#name')
             ->press('Save Page')
             // Check redirect
-            ->seePageIs($newPageUrl)
-            ->visit($pageUrl)
+            ->seePageIs($newPageUrl);
+
+        $this->visit($pageUrl)
             ->seePageIs($newPageUrl);
     }
 
index 108b7459f79c860e7d12c8d4649b87bea6042ab6..1a46e30bc6b03c2e26361b9563b33b6a16a1ba1f 100644 (file)
@@ -86,7 +86,7 @@ class PageDraftTest extends TestCase
             ->visit($chapter->getUrl() . '/create-page')
             ->visit($book->getUrl())
             ->seeInElement('.page-list', 'New Page');
-
+        
         $this->asAdmin()
             ->visit($book->getUrl())
             ->dontSeeInElement('.page-list', 'New Page')
index 806a36acc11fcb507987ba4e9ab2fc6935afa2fd..d9acd4b71b8efbdf573bd7f0ccba48e3c5cd2f9a 100644 (file)
@@ -59,8 +59,10 @@ class ImageTest extends TestCase
 
         $this->assertTrue(file_exists(public_path($relPath)), 'Uploaded image exists');
 
+        $this->deleteImage($relPath);
+
         $this->seeInDatabase('images', [
-            'url' => $relPath,
+            'url' => $this->baseUrl . $relPath,
             'type' => 'gallery',
             'uploaded_to' => $page->id,
             'path' => $relPath,
@@ -69,7 +71,7 @@ class ImageTest extends TestCase
             'name' => $imageName
         ]);
         
-        $this->deleteImage($relPath);
+
     }
 
     public function test_image_delete()
@@ -85,7 +87,7 @@ class ImageTest extends TestCase
         $this->assertResponseOk();
 
         $this->dontSeeInDatabase('images', [
-            'url' => $relPath,
+            'url' => $this->baseUrl . $relPath,
             'type' => 'gallery'
         ]);