]> BookStack Code Mirror - bookstack/commitdiff
Merge pull request #6 from BookStackApp/master
authorAbijeet Patro <redacted>
Sun, 29 Jan 2017 04:05:21 +0000 (09:35 +0530)
committerGitHub <redacted>
Sun, 29 Jan 2017 04:05:21 +0000 (09:35 +0530)
Getting the latest

86 files changed:
.github/ISSUE_TEMPLATE.md
.travis.yml
app/Exceptions/Handler.php
app/Http/Controllers/BookController.php
app/Http/Controllers/Controller.php
app/Http/Controllers/PageController.php
app/Http/Controllers/UserController.php
app/Http/Kernel.php
app/Http/Middleware/Localization.php [new file with mode: 0644]
app/Http/Middleware/RedirectIfAuthenticated.php
app/Providers/AppServiceProvider.php
app/Repos/EntityRepo.php
app/Repos/PermissionsRepo.php
app/Services/ExportService.php
app/Services/Ldap.php
app/Services/LdapService.php
app/Services/PermissionService.php
app/Services/SettingService.php
app/User.php
app/helpers.php
composer.json
composer.lock
database/factories/ModelFactory.php
database/migrations/2017_01_21_163556_create_cache_table.php [new file with mode: 0644]
database/migrations/2017_01_21_163602_create_sessions_table.php [new file with mode: 0644]
package.json
public/ZeroClipboard.swf [deleted file]
readme.md
resources/assets/js/global.js
resources/assets/js/pages/page-form.js
resources/assets/js/pages/page-show.js
resources/assets/sass/_blocks.scss
resources/assets/sass/_buttons.scss
resources/assets/sass/_components.scss
resources/assets/sass/_pages.scss
resources/assets/sass/_text.scss
resources/assets/sass/export-styles.scss
resources/lang/en/entities.php
resources/lang/en/settings.php
resources/lang/fr/activities.php [new file with mode: 0644]
resources/lang/fr/auth.php [new file with mode: 0644]
resources/lang/fr/common.php [new file with mode: 0644]
resources/lang/fr/components.php [new file with mode: 0644]
resources/lang/fr/entities.php [new file with mode: 0644]
resources/lang/fr/errors.php [new file with mode: 0644]
resources/lang/fr/pagination.php [new file with mode: 0644]
resources/lang/fr/passwords.php [new file with mode: 0644]
resources/lang/fr/settings.php [new file with mode: 0644]
resources/lang/fr/validation.php [new file with mode: 0644]
resources/lang/pt_BR/activities.php [new file with mode: 0644]
resources/lang/pt_BR/auth.php [new file with mode: 0644]
resources/lang/pt_BR/common.php [new file with mode: 0644]
resources/lang/pt_BR/components.php [new file with mode: 0644]
resources/lang/pt_BR/entities.php [new file with mode: 0644]
resources/lang/pt_BR/errors.php [new file with mode: 0644]
resources/lang/pt_BR/pagination.php [new file with mode: 0644]
resources/lang/pt_BR/passwords.php [new file with mode: 0644]
resources/lang/pt_BR/settings.php [new file with mode: 0644]
resources/lang/pt_BR/validation.php [new file with mode: 0644]
resources/views/home.blade.php
resources/views/pages/page-display.blade.php
resources/views/pages/show.blade.php
resources/views/pages/sidebar-tree-list.blade.php
resources/views/settings/roles/form.blade.php
resources/views/users/create.blade.php
resources/views/users/edit.blade.php
tests/ActivityTrackingTest.php
tests/AttachmentTest.php
tests/Auth/AuthTest.php
tests/Auth/LdapTest.php
tests/Auth/SocialAuthTest.php
tests/BrowserKitTest.php [new file with mode: 0644]
tests/Entity/EntitySearchTest.php
tests/Entity/EntityTest.php
tests/Entity/MarkdownTest.php
tests/Entity/PageContentTest.php [new file with mode: 0644]
tests/Entity/PageDraftTest.php
tests/Entity/SortTest.php
tests/Entity/TagTest.php [moved from tests/Entity/TagTests.php with 59% similarity]
tests/ImageTest.php
tests/Permissions/RestrictionsTest.php
tests/Permissions/RolesTest.php
tests/PublicActionTest.php
tests/TestCase.php
tests/UserProfileTest.php
version

index 4f9f4c480bef388437fa0dc95bb472c6d2abc13f..e7e75cc9f432ec77a847f40a2966a87602895bea 100644 (file)
@@ -1,11 +1,13 @@
 ### For Feature Requests
+
 Desired Feature:
 
 ### For Bug Reports
-PHP Version:
 
-MySQL Version:
+* BookStack Version:
+* PHP Version:
+* MySQL Version:
 
-Expected Behavior:
+##### Expected Behavior
 
-Actual Behavior:
+##### Actual Behavior
index e2eb5f51111bf6a76523f83dc020da1a44152160..0ad753ced42e8f2bed7b57a3d74d2d34a448b561 100644 (file)
@@ -17,9 +17,7 @@ addons:
 
 before_script:
   - mysql -u root -e 'create database `bookstack-test`;'
-  - composer config -g github-oauth.github.com $GITHUB_ACCESS_TOKEN
   - phpenv config-rm xdebug.ini
-  - composer self-update
   - composer dump-autoload --no-interaction
   - composer install --prefer-dist --no-interaction
   - php artisan clear-compiled -n
index c64f0cd1fc7941ac15bba50cb7d16b0ce1817d6c..5260eb6cd88b95a5b75380eaa500ad7a33483e28 100644 (file)
@@ -3,9 +3,9 @@
 namespace BookStack\Exceptions;
 
 use Exception;
-use Illuminate\Contracts\Validation\ValidationException;
+use Illuminate\Auth\AuthenticationException;
+use Illuminate\Validation\ValidationException;
 use Illuminate\Database\Eloquent\ModelNotFoundException;
-use PhpSpec\Exception\Example\ErrorException;
 use Symfony\Component\HttpKernel\Exception\HttpException;
 use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
 use Illuminate\Auth\Access\AuthorizationException;
index 57ac486d5e71122b49b057b9fc7dc25dd36ef3ed..408192ff9085dadb68363c1c1eb821704572301c 100644 (file)
@@ -208,7 +208,7 @@ class BookController extends Controller
         }
 
         // Update permissions on changed models
-        $this->entityRepo->buildJointPermissions($updatedModels);
+        if (count($updatedModels) === 0) $this->entityRepo->buildJointPermissions($updatedModels);
 
         return redirect($book->getUrl());
     }
index 2b6c88fe0b73748ab5cbdf61a64138dcdc4d5c49..733d5416b774b8bbd7e02935c790d85fd0e4d098 100644 (file)
@@ -4,7 +4,7 @@ namespace BookStack\Http\Controllers;
 
 use BookStack\Ownable;
 use Illuminate\Foundation\Bus\DispatchesJobs;
-use Illuminate\Http\Exception\HttpResponseException;
+use Illuminate\Http\Exceptions\HttpResponseException;
 use Illuminate\Http\Request;
 use Illuminate\Routing\Controller as BaseController;
 use Illuminate\Foundation\Validation\ValidatesRequests;
index 6ed9fc30c79c8e6d037d06c1ca727448152ff0b9..4ed10d61e3efa2ba6ef8d1dd535040f0e68b1cc1 100644 (file)
@@ -158,13 +158,16 @@ class PageController extends Controller
 
         $this->checkOwnablePermission('page-view', $page);
 
+        $pageContent = $this->entityRepo->renderPage($page);
         $sidebarTree = $this->entityRepo->getBookChildren($page->book);
-        $pageNav = $this->entityRepo->getPageNav($page);
+        $pageNav = $this->entityRepo->getPageNav($pageContent);
         
         Views::add($page);
         $this->setPageTitle($page->getShortName());
-        return view('pages/show', ['page' => $page, 'book' => $page->book,
-                                   'current' => $page, 'sidebarTree' => $sidebarTree, 'pageNav' => $pageNav]);
+        return view('pages/show', [
+            'page' => $page,'book' => $page->book,
+            'current' => $page, 'sidebarTree' => $sidebarTree,
+            'pageNav' => $pageNav, 'pageContent' => $pageContent]);
     }
 
     /**
@@ -430,6 +433,7 @@ class PageController extends Controller
     {
         $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
         $pdfContent = $this->exportService->pageToPdf($page);
+//        return $pdfContent;
         return response()->make($pdfContent, 200, [
             'Content-Type'        => 'application/octet-stream',
             'Content-Disposition' => 'attachment; filename="' . $pageSlug . '.pdf'
index b5184c40acace93088c439b0b2eb3383ef4e8a56..c98d5f87eab71ebbf4383b8f77efe43fe17774f0 100644 (file)
@@ -1,13 +1,8 @@
-<?php
+<?php namespace BookStack\Http\Controllers;
 
-namespace BookStack\Http\Controllers;
-
-use BookStack\Activity;
 use Exception;
 use Illuminate\Http\Request;
-
 use Illuminate\Http\Response;
-use BookStack\Http\Requests;
 use BookStack\Repos\UserRepo;
 use BookStack\Services\SocialAuthService;
 use BookStack\User;
@@ -152,7 +147,8 @@ class UserController extends Controller
             'name'             => 'min:2',
             'email'            => 'min:2|email|unique:users,email,' . $id,
             'password'         => 'min:5|required_with:password_confirm',
-            'password-confirm' => 'same:password|required_with:password'
+            'password-confirm' => 'same:password|required_with:password',
+            'setting'          => 'array'
         ]);
 
         $user = $this->user->findOrFail($id);
@@ -175,6 +171,13 @@ class UserController extends Controller
             $user->external_auth_id = $request->get('external_auth_id');
         }
 
+        // Save an user-specific settings
+        if ($request->has('setting')) {
+            foreach ($request->get('setting') as $key => $value) {
+                setting()->putUser($user, $key, $value);
+            }
+        }
+
         $user->save();
         session()->flash('success', trans('settings.users_edit_success'));
 
index f1d95f5c070da381114dad0f3c41a4b69495ec90..c55cc9ab8d47f11caa0ee7bacf9b1cee705b73bf 100644 (file)
@@ -1,6 +1,4 @@
-<?php
-
-namespace BookStack\Http;
+<?php namespace BookStack\Http;
 
 use Illuminate\Foundation\Http\Kernel as HttpKernel;
 
@@ -30,6 +28,7 @@ class Kernel extends HttpKernel
             \Illuminate\View\Middleware\ShareErrorsFromSession::class,
             \BookStack\Http\Middleware\VerifyCsrfToken::class,
             \Illuminate\Routing\Middleware\SubstituteBindings::class,
+            \BookStack\Http\Middleware\Localization::class
         ],
         'api' => [
             'throttle:60,1',
diff --git a/app/Http/Middleware/Localization.php b/app/Http/Middleware/Localization.php
new file mode 100644 (file)
index 0000000..31cb5d9
--- /dev/null
@@ -0,0 +1,23 @@
+<?php namespace BookStack\Http\Middleware;
+
+use Carbon\Carbon;
+use Closure;
+
+class Localization
+{
+    /**
+     * Handle an incoming request.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \Closure  $next
+     * @return mixed
+     */
+    public function handle($request, Closure $next)
+    {
+        $defaultLang = config('app.locale');
+        $locale = setting()->getUser(user(), 'language', $defaultLang);
+        app()->setLocale($locale);
+        Carbon::setLocale($locale);
+        return $next($request);
+    }
+}
index 2b3c64695735d44daf3c6f47f76d4aa59584f4c2..c27df7af4f5434bdbf7d208fbe98f82ddde78bfb 100644 (file)
@@ -1,6 +1,4 @@
-<?php
-
-namespace BookStack\Http\Middleware;
+<?php namespace BookStack\Http\Middleware;
 
 use Closure;
 use Illuminate\Contracts\Auth\Guard;
index 66f40569a7686e6b583e046a3fc7ed0c6bd6c0c9..40a1eef3d81d5ecfdbbf1eb27f41d0b17ceb19b6 100644 (file)
@@ -1,6 +1,5 @@
 <?php namespace BookStack\Providers;
 
-use Carbon\Carbon;
 use Illuminate\Support\ServiceProvider;
 use Validator;
 
@@ -18,8 +17,6 @@ class AppServiceProvider extends ServiceProvider
             $imageMimes = ['image/png', 'image/bmp', 'image/gif', 'image/jpeg', 'image/jpg', 'image/tiff', 'image/webp'];
             return in_array($value->getMimeType(), $imageMimes);
         });
-
-        Carbon::setLocale(config('app.locale'));
     }
 
     /**
index 0515a4cd47c06d6ff88f136211241a56a76281d7..f1428735cc340149a3c33d0d3ed76e298cfe7f63 100644 (file)
@@ -139,7 +139,7 @@ class EntityRepo
      */
     public function getById($type, $id, $allowDrafts = false)
     {
-        return $this->entityQuery($type, $allowDrafts)->findOrFail($id);
+        return $this->entityQuery($type, $allowDrafts)->find($id);
     }
 
     /**
@@ -318,15 +318,15 @@ class EntityRepo
      */
     public function getBookChildren(Book $book, $filterDrafts = false)
     {
-        $q = $this->permissionService->bookChildrenQuery($book->id, $filterDrafts);
+        $q = $this->permissionService->bookChildrenQuery($book->id, $filterDrafts)->get();
         $entities = [];
         $parents = [];
         $tree = [];
 
         foreach ($q as $index => $rawEntity) {
-            if ($rawEntity->entity_type === 'Bookstack\\Page') {
+            if ($rawEntity->entity_type === 'BookStack\\Page') {
                 $entities[$index] = $this->page->newFromBuilder($rawEntity);
-            } else if ($rawEntity->entity_type === 'Bookstack\\Chapter') {
+            } else if ($rawEntity->entity_type === 'BookStack\\Chapter') {
                 $entities[$index] = $this->chapter->newFromBuilder($rawEntity);
                 $key = $entities[$index]->entity_type . ':' . $entities[$index]->id;
                 $parents[$key] = $entities[$index];
@@ -338,7 +338,7 @@ class EntityRepo
 
         foreach ($entities as $entity) {
             if ($entity->chapter_id === 0) continue;
-            $parentKey = 'Bookstack\\Chapter:' . $entity->chapter_id;
+            $parentKey = 'BookStack\\Chapter:' . $entity->chapter_id;
             $chapter = $parents[$parentKey];
             $chapter->pages->push($entity);
         }
@@ -796,6 +796,52 @@ class EntityRepo
         return $html;
     }
 
+
+    /**
+     * Render the page for viewing, Parsing and performing features such as page transclusion.
+     * @param Page $page
+     * @return mixed|string
+     */
+    public function renderPage(Page $page)
+    {
+        $content = $page->html;
+        $matches = [];
+        preg_match_all("/{{@\s?([0-9].*?)}}/", $content, $matches);
+        if (count($matches[0]) === 0) return $content;
+
+        foreach ($matches[1] as $index => $includeId) {
+            $splitInclude = explode('#', $includeId, 2);
+            $pageId = intval($splitInclude[0]);
+            if (is_nan($pageId)) continue;
+
+            $page = $this->getById('page', $pageId);
+            if ($page === null) {
+                $content = str_replace($matches[0][$index], '', $content);
+                continue;
+            }
+
+            if (count($splitInclude) === 1) {
+                $content = str_replace($matches[0][$index], $page->html, $content);
+                continue;
+            }
+
+            $doc = new DOMDocument();
+            $doc->loadHTML(mb_convert_encoding('<body>'.$page->html.'</body>', 'HTML-ENTITIES', 'UTF-8'));
+            $matchingElem = $doc->getElementById($splitInclude[1]);
+            if ($matchingElem === null) {
+                $content = str_replace($matches[0][$index], '', $content);
+                continue;
+            }
+            $innerContent = '';
+            foreach ($matchingElem->childNodes as $childNode) {
+                $innerContent .= $doc->saveHTML($childNode);
+            }
+            $content = str_replace($matches[0][$index], trim($innerContent), $content);
+        }
+
+        return $content;
+    }
+
     /**
      * Get a new draft page instance.
      * @param Book $book
@@ -835,19 +881,19 @@ class EntityRepo
 
     /**
      * Parse the headers on the page to get a navigation menu
-     * @param Page $page
-     * @return Collection
+     * @param String $pageContent
+     * @return array
      */
-    public function getPageNav(Page $page)
+    public function getPageNav($pageContent)
     {
-        if ($page->html == '') return null;
+        if ($pageContent == '') return [];
         libxml_use_internal_errors(true);
         $doc = new DOMDocument();
-        $doc->loadHTML(mb_convert_encoding($page->html, 'HTML-ENTITIES', 'UTF-8'));
+        $doc->loadHTML(mb_convert_encoding($pageContent, 'HTML-ENTITIES', 'UTF-8'));
         $xPath = new DOMXPath($doc);
         $headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6");
 
-        if (is_null($headers)) return null;
+        if (is_null($headers)) return [];
 
         $tree = collect([]);
         foreach ($headers as $header) {
@@ -868,7 +914,7 @@ class EntityRepo
                 return $header;
             });
         }
-        return $tree;
+        return $tree->toArray();
     }
 
     /**
index e1c6d87b12f3551ea28f2f0b4001c3ae222329e3..aa58d1718cc6bd22775c08d31fabd862159e4731 100644 (file)
@@ -93,7 +93,7 @@ class PermissionsRepo
         $permissions = isset($roleData['permissions']) ? array_keys($roleData['permissions']) : [];
         $this->assignRolePermissions($role, $permissions);
 
-        if ($role->name === 'admin') {
+        if ($role->system_name === 'admin') {
             $permissions = $this->permission->all()->pluck('id')->toArray();
             $role->permissions()->sync($permissions);
         }
index 50ba75c17a93a22f7dc8b16d7820fed26338e24d..880bc54ad4de920fa48f6247d2d5a1d1cac142b5 100644 (file)
@@ -1,10 +1,22 @@
 <?php namespace BookStack\Services;
 
 use BookStack\Page;
+use BookStack\Repos\EntityRepo;
 
 class ExportService
 {
 
+    protected $entityRepo;
+
+    /**
+     * ExportService constructor.
+     * @param $entityRepo
+     */
+    public function __construct(EntityRepo $entityRepo)
+    {
+        $this->entityRepo = $entityRepo;
+    }
+
     /**
      * Convert a page to a self-contained HTML file.
      * Includes required CSS & image content. Images are base64 encoded into the HTML.
@@ -14,7 +26,7 @@ class ExportService
     public function pageToContainedHtml(Page $page)
     {
         $cssContent = file_get_contents(public_path('/css/export-styles.css'));
-        $pageHtml = view('pages/export', ['page' => $page, 'css' => $cssContent])->render();
+        $pageHtml = view('pages/export', ['page' => $page, 'pageContent' => $this->entityRepo->renderPage($page), 'css' => $cssContent])->render();
         return $this->containHtml($pageHtml);
     }
 
@@ -26,7 +38,8 @@ class ExportService
     public function pageToPdf(Page $page)
     {
         $cssContent = file_get_contents(public_path('/css/export-styles.css'));
-        $pageHtml = view('pages/pdf', ['page' => $page, 'css' => $cssContent])->render();
+        $pageHtml = view('pages/pdf', ['page' => $page, 'pageContent' => $this->entityRepo->renderPage($page), 'css' => $cssContent])->render();
+//        return $pageHtml;
         $useWKHTML = config('snappy.pdf.binary') !== false;
         $containedHtml = $this->containHtml($pageHtml);
         if ($useWKHTML) {
@@ -59,9 +72,13 @@ class ExportService
                     $pathString = $srcString;
                 }
                 if ($isLocal && !file_exists($pathString)) continue;
-                $imageContent = file_get_contents($pathString);
-                $imageEncoded = 'data:image/' . pathinfo($pathString, PATHINFO_EXTENSION) . ';base64,' . base64_encode($imageContent);
-                $newImageString = str_replace($srcString, $imageEncoded, $oldImgString);
+                try {
+                    $imageContent = file_get_contents($pathString);
+                    $imageEncoded = 'data:image/' . pathinfo($pathString, PATHINFO_EXTENSION) . ';base64,' . base64_encode($imageContent);
+                    $newImageString = str_replace($srcString, $imageEncoded, $oldImgString);
+                } catch (\ErrorException $e) {
+                    $newImageString = '';
+                }
                 $htmlContent = str_replace($oldImgString, $newImageString, $htmlContent);
             }
         }
@@ -88,14 +105,14 @@ class ExportService
 
     /**
      * Converts the page contents into simple plain text.
-     * This method filters any bad looking content to
-     * provide a nice final output.
+     * This method filters any bad looking content to provide a nice final output.
      * @param Page $page
      * @return mixed
      */
     public function pageToPlainText(Page $page)
     {
-        $text = $page->text;
+        $html = $this->entityRepo->renderPage($page);
+        $text = strip_tags($html);
         // Replace multiple spaces with single spaces
         $text = preg_replace('/\ {2,}/', ' ', $text);
         // Reduce multiple horrid whitespace characters.
index 196e46a2f4cb5195a34997961907d33f0d77acaf..9c3bec3270af2f4321d155f7a980fca9a7d12839 100644 (file)
@@ -94,4 +94,4 @@ class Ldap
         return ldap_bind($ldapConnection, $bindRdn, $bindPassword);
     }
 
-}
\ No newline at end of file
+}
index 40b24f1419c06e60cc372dae0b57fd1e621fe70a..f8a4b88bb4b985c5fb75d5af875d3efb765864bd 100644 (file)
@@ -112,9 +112,13 @@ class LdapService
             throw new LdapException(trans('errors.ldap_extension_not_installed'));
         }
 
-        // Get port from server string if specified.
+        // Get port from server string and protocol if specified.
         $ldapServer = explode(':', $this->config['server']);
-        $ldapConnection = $this->ldap->connect($ldapServer[0], count($ldapServer) > 1 ? $ldapServer[1] : 389);
+        $hasProtocol = preg_match('/^ldaps{0,1}\:\/\//', $this->config['server']) === 1;
+        if (!$hasProtocol) array_unshift($ldapServer, '');
+        $hostName = $ldapServer[0] . ($hasProtocol?':':'') . $ldapServer[1];
+        $defaultPort = $ldapServer[0] === 'ldaps' ? 636 : 389;
+        $ldapConnection = $this->ldap->connect($hostName, count($ldapServer) > 2 ? intval($ldapServer[2]) : $defaultPort);
 
         if ($ldapConnection === false) {
             throw new LdapException(trans('errors.ldap_cannot_connect'));
index 467bf95da69f7f6dbe35361a2a595669cb977bc0..72a810b6b4ebf657f6c29cd681141b930652a34c 100644 (file)
@@ -157,7 +157,7 @@ class PermissionService
      */
     public function buildJointPermissionsForEntity(Entity $entity)
     {
-        $roles = $this->role->with('jointPermissions')->get();
+        $roles = $this->role->get();
         $entities = collect([$entity]);
 
         if ($entity->isA('book')) {
@@ -177,7 +177,7 @@ class PermissionService
      */
     public function buildJointPermissionsForEntities(Collection $entities)
     {
-        $roles = $this->role->with('jointPermissions')->get();
+        $roles = $this->role->get();
         $this->deleteManyJointPermissionsForEntities($entities);
         $this->createManyJointPermissions($entities, $roles);
     }
@@ -243,13 +243,14 @@ class PermissionService
      */
     protected function deleteManyJointPermissionsForEntities($entities)
     {
+        if (count($entities) === 0) return;
         $query = $this->jointPermission->newQuery();
-        foreach ($entities as $entity) {
-            $query->orWhere(function($query) use ($entity) {
-                $query->where('entity_id', '=', $entity->id)
-                    ->where('entity_type', '=', $entity->getMorphClass());
-            });
-        }
+            foreach ($entities as $entity) {
+                $query->orWhere(function($query) use ($entity) {
+                    $query->where('entity_id', '=', $entity->id)
+                        ->where('entity_type', '=', $entity->getMorphClass());
+                });
+            }
         $query->delete();
     }
 
@@ -405,7 +406,7 @@ class PermissionService
         $action = end($explodedPermission);
         $this->currentAction = $action;
 
-        $nonJointPermissions = ['restrictions'];
+        $nonJointPermissions = ['restrictions', 'image', 'attachment'];
 
         // Handle non entity specific jointPermissions
         if (in_array($explodedPermission[0], $nonJointPermissions)) {
@@ -421,7 +422,6 @@ class PermissionService
             $this->currentAction = $permission;
         }
 
-
         $q = $this->entityRestrictionQuery($baseQuery)->count() > 0;
         $this->clean();
         return $q;
@@ -471,49 +471,40 @@ class PermissionService
         return $q;
     }
 
+    /**
+     * Get the children of a book in an efficient single query, Filtered by the permission system.
+     * @param integer $book_id
+     * @param bool    $filterDrafts
+     * @return \Illuminate\Database\Query\Builder
+     */
     public function bookChildrenQuery($book_id, $filterDrafts = false) {
-
-        // Draft setup
-        $params = [
-            'userId' => $this->currentUser()->id,
-            'bookIdPage' => $book_id,
-            'bookIdChapter' => $book_id
-        ];
-        if (!$filterDrafts) {
-            $params['userIdDrafts'] = $this->currentUser()->id;
-        }
-        // Role setup
-        $userRoles = $this->getRoles();
-        $roleBindings = [];
-        $roleValues = [];
-        foreach ($userRoles as $index => $roleId) {
-            $roleBindings[':role'.$index] = $roleId;
-            $roleValues['role'.$index] = $roleId;
+        $pageSelect = $this->db->table('pages')->selectRaw("'BookStack\\\\Page' as entity_type, id, slug, name, text, '' as description, book_id, priority, chapter_id, draft")->where('book_id', '=', $book_id)->where(function($query) use ($filterDrafts) {
+            $query->where('draft', '=', 0);
+            if (!$filterDrafts) {
+                $query->orWhere(function($query) {
+                    $query->where('draft', '=', 1)->where('created_by', '=', $this->currentUser()->id);
+                });
+            }
+        });
+        $chapterSelect = $this->db->table('chapters')->selectRaw("'BookStack\\\\Chapter' as entity_type, id, slug, name, '' as text, description, book_id, priority, 0 as chapter_id, 0 as draft")->where('book_id', '=', $book_id);
+        $query = $this->db->query()->select('*')->from($this->db->raw("({$pageSelect->toSql()} UNION {$chapterSelect->toSql()}) AS U"))
+            ->mergeBindings($pageSelect)->mergeBindings($chapterSelect);
+
+        if (!$this->isAdmin()) {
+            $whereQuery = $this->db->table('joint_permissions as jp')->selectRaw('COUNT(*)')
+                ->whereRaw('jp.entity_id=U.id')->whereRaw('jp.entity_type=U.entity_type')
+                ->where('jp.action', '=', 'view')->whereIn('jp.role_id', $this->getRoles())
+                ->where(function($query) {
+                    $query->where('jp.has_permission', '=', 1)->orWhere(function($query) {
+                        $query->where('jp.has_permission_own', '=', 1)->where('jp.created_by', '=', $this->currentUser()->id);
+                    });
+                });
+            $query->whereRaw("({$whereQuery->toSql()}) > 0")->mergeBindings($whereQuery);
         }
-        // TODO - Clean this up, Maybe extract into a nice class for doing these kind of manual things
-        // Something which will handle the above role crap in a nice clean way
-        $roleBindingString = implode(',', array_keys($roleBindings));
-        $query = "SELECT * from (
-(SELECT 'Bookstack\\\Page' as entity_type, id, slug, name, text, '' as description, book_id, priority, chapter_id, draft FROM {$this->page->getTable()}
-    where book_id = :bookIdPage AND ". ($filterDrafts ? '(draft = 0)' : '(draft = 0 OR (draft = 1 AND created_by = :userIdDrafts))') .")
-UNION
-(SELECT 'Bookstack\\\Chapter' as entity_type, id, slug, name, '' as text, description, book_id, priority, 0 as chapter_id, 0 as draft FROM {$this->chapter->getTable()} WHERE book_id = :bookIdChapter)
-) as U  WHERE (
-       SELECT COUNT(*) FROM {$this->jointPermission->getTable()} jp
-    WHERE
-               jp.entity_id=U.id AND
-        jp.entity_type=U.entity_type AND
-               jp.action = 'view' AND
-        jp.role_id IN ({$roleBindingString}) AND
-        (
-                       jp.has_permission = 1 OR
-            (jp.has_permission_own = 1 AND jp.created_by = :userId)
-        )
-) > 0
-ORDER BY draft desc, priority asc";
 
+        $query->orderBy('draft', 'desc')->orderBy('priority', 'asc');
         $this->clean();
-        return $this->db->select($query, array_replace($roleValues, $params));
+        return  $query;
     }
 
     /**
@@ -579,6 +570,7 @@ ORDER BY draft desc, priority asc";
                     });
             });
         });
+        $this->clean();
         return $q;
     }
 
index bf5fa918e2b54cf7aadda0f6ff18c0875311d058..40094a513ed33deefb705b578b5903f2ae9174a8 100644 (file)
@@ -1,6 +1,7 @@
 <?php namespace BookStack\Services;
 
 use BookStack\Setting;
+use BookStack\User;
 use Illuminate\Contracts\Cache\Repository as Cache;
 
 /**
@@ -38,10 +39,23 @@ class SettingService
      */
     public function get($key, $default = false)
     {
+        if ($default === false) $default = config('setting-defaults.' . $key, false);
         $value = $this->getValueFromStore($key, $default);
         return $this->formatValue($value, $default);
     }
 
+    /**
+     * Get a user-specific setting from the database or cache.
+     * @param User $user
+     * @param $key
+     * @param bool $default
+     * @return bool|string
+     */
+    public function getUser($user, $key, $default = false)
+    {
+        return $this->get($this->userKey($user->id, $key), $default);
+    }
+
     /**
      * Gets a setting value from the cache or database.
      * Looks at the system defaults if not cached or in database.
@@ -69,14 +83,6 @@ class SettingService
             return $value;
         }
 
-        // Check the defaults set in the app config.
-        $configPrefix = 'setting-defaults.' . $key;
-        if (config()->has($configPrefix)) {
-            $value = config($configPrefix);
-            $this->cache->forever($cacheKey, $value);
-            return $value;
-        }
-
         return $default;
     }
 
@@ -118,6 +124,16 @@ class SettingService
         return $setting !== null;
     }
 
+    /**
+     * Check if a user setting is in the database.
+     * @param $key
+     * @return bool
+     */
+    public function hasUser($key)
+    {
+        return $this->has($this->userKey($key));
+    }
+
     /**
      * Add a setting to the database.
      * @param $key
@@ -135,6 +151,28 @@ class SettingService
         return true;
     }
 
+    /**
+     * Put a user-specific setting into the database.
+     * @param User $user
+     * @param $key
+     * @param $value
+     * @return bool
+     */
+    public function putUser($user, $key, $value)
+    {
+        return $this->put($this->userKey($user->id, $key), $value);
+    }
+
+    /**
+     * Convert a setting key into a user-specific key.
+     * @param $key
+     * @return string
+     */
+    protected function userKey($userId, $key = '')
+    {
+        return 'user:' . $userId . ':' . $key;
+    }
+
     /**
      * Removes a setting from the database.
      * @param $key
@@ -150,6 +188,16 @@ class SettingService
         return true;
     }
 
+    /**
+     * Delete settings for a given user id.
+     * @param $userId
+     * @return mixed
+     */
+    public function deleteUserSettings($userId)
+    {
+        return $this->setting->where('setting_key', 'like', $this->userKey($userId) . '%')->delete();
+    }
+
     /**
      * Gets a setting model from the database for the given key.
      * @param $key
index b5bb221e8652a29a2e8dbb19d84ac40799498bd8..afcd9af70c4f8094cea9fa52c9bfc0eaefa43068 100644 (file)
@@ -160,8 +160,16 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
      */
     public function getAvatar($size = 50)
     {
-        if ($this->image_id === 0 || $this->image_id === '0' || $this->image_id === null) return baseUrl('/user_avatar.png');
-        return baseUrl($this->avatar->getThumb($size, $size, false));
+        $default = baseUrl('/user_avatar.png');
+        $imageId = $this->image_id;
+        if ($imageId === 0 || $imageId === '0' || $imageId === null) return $default;
+
+        try {
+            $avatar = baseUrl($this->avatar->getThumb($size, $size, false));
+        } catch (\Exception $err) {
+            $avatar = $default;
+        }
+        return $avatar;
     }
 
     /**
index b5be0fd11bae196ccd085eb8e127ea3f0045d466..6decb08e96517233086eb9fe2e76ad002ce892fa 100644 (file)
@@ -60,11 +60,12 @@ function userCan($permission, Ownable $ownable = null)
  * Helper to access system settings.
  * @param $key
  * @param bool $default
- * @return mixed
+ * @return bool|string|\BookStack\Services\SettingService
  */
-function setting($key, $default = false)
+function setting($key = null, $default = false)
 {
     $settingService = app(\BookStack\Services\SettingService::class);
+    if (is_null($key)) return $settingService;
     return $settingService->get($key, $default);
 }
 
index 5a8fd67aea14d39ff03eee5bad2c599ea41837dc..c0543a4cad4b896cb17aa3af357c07a4b1ebf09a 100644 (file)
@@ -6,17 +6,18 @@
     "type": "project",
     "require": {
         "php": ">=5.6.4",
-        "laravel/framework": "^5.3.4",
+        "laravel/framework": "5.4.*",
         "ext-tidy": "*",
         "intervention/image": "^2.3",
-        "laravel/socialite": "^2.0",
-        "barryvdh/laravel-ide-helper": "^2.1",
-        "barryvdh/laravel-debugbar": "^2.2.3",
+        "laravel/socialite": "^3.0",
+        "barryvdh/laravel-ide-helper": "^2.2.3",
+        "barryvdh/laravel-debugbar": "^2.3.2",
         "league/flysystem-aws-s3-v3": "^1.0",
         "barryvdh/laravel-dompdf": "^0.7",
         "predis/predis": "^1.1",
         "gathercontent/htmldiff": "^0.2.1",
-        "barryvdh/laravel-snappy": "^0.3.1"
+        "barryvdh/laravel-snappy": "^0.3.1",
+        "laravel/browser-kit-testing": "^1.0"
     },
     "require-dev": {
         "fzaninotto/faker": "~1.4",
@@ -35,7 +36,8 @@
     },
     "autoload-dev": {
         "classmap": [
-            "tests/TestCase.php"
+            "tests/TestCase.php",
+            "tests/BrowserKitTest.php"
         ]
     },
     "scripts": {
index dcde9d9c69fca5265d4813e94878cdd604895e21..e0699361192abe004265595aff7d61ca4f7cd5f2 100644 (file)
@@ -4,21 +4,21 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "2438a2f4a02adbea5f378f9e9408eb29",
-    "content-hash": "6add8bff71ecc86e0c90858590834a26",
+    "hash": "c0bb098e9430247688c61ebd66d3d51c",
+    "content-hash": "3bb8bb2f252327c32aa40c686d1327cc",
     "packages": [
         {
             "name": "aws/aws-sdk-php",
-            "version": "3.19.11",
+            "version": "3.21.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/aws/aws-sdk-php.git",
-                "reference": "19bac3bdd7988cbf7f89d5ce8e2748d774e2cde8"
+                "reference": "6408a4904a04eca44461a65ba4a0fae53f80417b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/19bac3bdd7988cbf7f89d5ce8e2748d774e2cde8",
-                "reference": "19bac3bdd7988cbf7f89d5ce8e2748d774e2cde8",
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/6408a4904a04eca44461a65ba4a0fae53f80417b",
+                "reference": "6408a4904a04eca44461a65ba4a0fae53f80417b",
                 "shasum": ""
             },
             "require": {
                 "s3",
                 "sdk"
             ],
-            "time": "2016-09-27 19:38:36"
+            "time": "2017-01-25 00:43:08"
         },
         {
             "name": "barryvdh/laravel-debugbar",
-            "version": "v2.3.0",
+            "version": "v2.3.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/barryvdh/laravel-debugbar.git",
-                "reference": "0c87981df959c7c1943abe227baf607c92f204f9"
+                "reference": "24e4f0261e352d3fd86d0447791b56ae49398674"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/0c87981df959c7c1943abe227baf607c92f204f9",
-                "reference": "0c87981df959c7c1943abe227baf607c92f204f9",
+                "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/24e4f0261e352d3fd86d0447791b56ae49398674",
+                "reference": "24e4f0261e352d3fd86d0447791b56ae49398674",
                 "shasum": ""
             },
             "require": {
-                "illuminate/support": "5.1.*|5.2.*|5.3.*",
+                "illuminate/support": "5.1.*|5.2.*|5.3.*|5.4.*",
                 "maximebf/debugbar": "~1.13.0",
                 "php": ">=5.5.9",
                 "symfony/finder": "~2.7|~3.0"
                 "profiler",
                 "webprofiler"
             ],
-            "time": "2016-09-15 14:05:56"
+            "time": "2017-01-19 08:19:49"
         },
         {
             "name": "barryvdh/laravel-dompdf",
-            "version": "v0.7.0",
+            "version": "v0.7.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/barryvdh/laravel-dompdf.git",
-                "reference": "9b8bd179262ad6b200a11edfe7b53516afcfc42a"
+                "reference": "6cb20d3f397d739163d2d743a4600009e52cd453"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/9b8bd179262ad6b200a11edfe7b53516afcfc42a",
-                "reference": "9b8bd179262ad6b200a11edfe7b53516afcfc42a",
+                "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/6cb20d3f397d739163d2d743a4600009e52cd453",
+                "reference": "6cb20d3f397d739163d2d743a4600009e52cd453",
                 "shasum": ""
             },
             "require": {
                 "dompdf/dompdf": "^0.7",
-                "illuminate/support": "5.1.x|5.2.x|5.3.x",
+                "illuminate/support": "5.1.x|5.2.x|5.3.x|5.4.x",
                 "php": ">=5.5.9"
             },
             "type": "library",
                 "laravel",
                 "pdf"
             ],
-            "time": "2016-08-17 08:17:33"
+            "time": "2017-01-24 18:12:54"
         },
         {
             "name": "barryvdh/laravel-ide-helper",
-            "version": "v2.2.1",
+            "version": "v2.2.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/barryvdh/laravel-ide-helper.git",
-                "reference": "28af7cd19ca41cc0c63dd1de2b46c2b84d31c463"
+                "reference": "a7fc2ec489aada6062d3a63ddc915004a21e38af"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/28af7cd19ca41cc0c63dd1de2b46c2b84d31c463",
-                "reference": "28af7cd19ca41cc0c63dd1de2b46c2b84d31c463",
+                "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/a7fc2ec489aada6062d3a63ddc915004a21e38af",
+                "reference": "a7fc2ec489aada6062d3a63ddc915004a21e38af",
                 "shasum": ""
             },
             "require": {
                 "barryvdh/reflection-docblock": "^2.0.4",
-                "illuminate/console": "^5.0,<5.4",
-                "illuminate/filesystem": "^5.0,<5.4",
-                "illuminate/support": "^5.0,<5.4",
+                "illuminate/console": "^5.0,<5.5",
+                "illuminate/filesystem": "^5.0,<5.5",
+                "illuminate/support": "^5.0,<5.5",
                 "php": ">=5.4.0",
                 "symfony/class-loader": "^2.3|^3.0"
             },
                 "phpstorm",
                 "sublime"
             ],
-            "time": "2016-07-04 11:52:48"
+            "time": "2017-01-05 21:20:42"
         },
         {
             "name": "barryvdh/laravel-snappy",
-            "version": "v0.3.1",
+            "version": "v0.3.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/barryvdh/laravel-snappy.git",
-                "reference": "509a4497be63d8ee7ff464a3daf00d9edde08e21"
+                "reference": "864470e81952f8e568c93754d9d0d2c05145f773"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/barryvdh/laravel-snappy/zipball/509a4497be63d8ee7ff464a3daf00d9edde08e21",
-                "reference": "509a4497be63d8ee7ff464a3daf00d9edde08e21",
+                "url": "https://api.github.com/repos/barryvdh/laravel-snappy/zipball/864470e81952f8e568c93754d9d0d2c05145f773",
+                "reference": "864470e81952f8e568c93754d9d0d2c05145f773",
                 "shasum": ""
             },
             "require": {
-                "illuminate/filesystem": "5.0.x|5.1.x|5.2.x|5.3.x",
-                "illuminate/support": "5.0.x|5.1.x|5.2.x|5.3.x",
+                "illuminate/filesystem": "5.0.x|5.1.x|5.2.x|5.3.x|5.4.x",
+                "illuminate/support": "5.0.x|5.1.x|5.2.x|5.3.x|5.4.x",
                 "knplabs/knp-snappy": "*",
                 "php": ">=5.4.0"
             },
                 "wkhtmltoimage",
                 "wkhtmltopdf"
             ],
-            "time": "2016-08-05 13:08:28"
+            "time": "2017-01-20 06:21:34"
         },
         {
             "name": "barryvdh/reflection-docblock",
             ],
             "time": "2016-06-13 19:28:20"
         },
-        {
-            "name": "classpreloader/classpreloader",
-            "version": "3.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/ClassPreloader/ClassPreloader.git",
-                "reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/9b10b913c2bdf90c3d2e0d726b454fb7f77c552a",
-                "reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a",
-                "shasum": ""
-            },
-            "require": {
-                "nikic/php-parser": "^1.0|^2.0",
-                "php": ">=5.5.9"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.8|^5.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.0-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "ClassPreloader\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Michael Dowling",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Graham Campbell",
-                    "email": "[email protected]"
-                }
-            ],
-            "description": "Helps class loading performance by generating a single PHP file containing all of the autoloaded files for a specific use case",
-            "keywords": [
-                "autoload",
-                "class",
-                "preload"
-            ],
-            "time": "2015-11-09 22:51:51"
-        },
         {
             "name": "cogpowered/finediff",
             "version": "0.3.1",
             ],
             "time": "2014-05-19 10:25:02"
         },
-        {
-            "name": "dnoegel/php-xdg-base-dir",
-            "version": "0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/dnoegel/php-xdg-base-dir.git",
-                "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/265b8593498b997dc2d31e75b89f053b5cc9621a",
-                "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.2"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "@stable"
-            },
-            "type": "project",
-            "autoload": {
-                "psr-4": {
-                    "XdgBaseDir\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "description": "implementation of xdg base directory specification for php",
-            "time": "2014-10-24 07:27:01"
-        },
         {
             "name": "doctrine/inflector",
             "version": "v1.1.0",
             "homepage": "https://github.com/dompdf/dompdf",
             "time": "2016-05-11 00:36:29"
         },
+        {
+            "name": "erusev/parsedown",
+            "version": "1.6.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/erusev/parsedown.git",
+                "reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/erusev/parsedown/zipball/20ff8bbb57205368b4b42d094642a3e52dac85fb",
+                "reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Parsedown": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Emanuil Rusev",
+                    "email": "[email protected]",
+                    "homepage": "http://erusev.com"
+                }
+            ],
+            "description": "Parser for Markdown.",
+            "homepage": "http://parsedown.org",
+            "keywords": [
+                "markdown",
+                "parser"
+            ],
+            "time": "2016-11-02 15:56:58"
+        },
         {
             "name": "gathercontent/htmldiff",
             "version": "0.2.1",
         },
         {
             "name": "guzzlehttp/guzzle",
-            "version": "6.2.1",
+            "version": "6.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/guzzle.git",
-                "reference": "3f808fba627f2c5b69e2501217bf31af349c1427"
+                "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/3f808fba627f2c5b69e2501217bf31af349c1427",
-                "reference": "3f808fba627f2c5b69e2501217bf31af349c1427",
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ebf29dee597f02f09f4d5bbecc68230ea9b08f60",
+                "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60",
                 "shasum": ""
             },
             "require": {
                 "rest",
                 "web service"
             ],
-            "time": "2016-07-15 17:22:37"
+            "time": "2016-10-08 15:01:37"
         },
         {
             "name": "guzzlehttp/promises",
-            "version": "1.2.0",
+            "version": "v1.3.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/promises.git",
-                "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579"
+                "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579",
-                "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579",
+                "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
+                "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.5.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.0"
+                "phpunit/phpunit": "^4.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0-dev"
+                    "dev-master": "1.4-dev"
                 }
             },
             "autoload": {
             "keywords": [
                 "promise"
             ],
-            "time": "2016-05-18 16:56:05"
+            "time": "2016-12-20 10:07:11"
         },
         {
             "name": "guzzlehttp/psr7",
         },
         {
             "name": "intervention/image",
-            "version": "2.3.8",
+            "version": "2.3.9",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Intervention/image.git",
-                "reference": "4064a980324f6c3bfa2bd981dfb247afa705ec3c"
+                "reference": "2bce9a59c43b868300b02a7d31a1e4aa67a200ae"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Intervention/image/zipball/4064a980324f6c3bfa2bd981dfb247afa705ec3c",
-                "reference": "4064a980324f6c3bfa2bd981dfb247afa705ec3c",
+                "url": "https://api.github.com/repos/Intervention/image/zipball/2bce9a59c43b868300b02a7d31a1e4aa67a200ae",
+                "reference": "2bce9a59c43b868300b02a7d31a1e4aa67a200ae",
                 "shasum": ""
             },
             "require": {
                 "thumbnail",
                 "watermark"
             ],
-            "time": "2016-09-01 17:04:03"
-        },
-        {
-            "name": "jakub-onderka/php-console-color",
-            "version": "0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/JakubOnderka/PHP-Console-Color.git",
-                "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/e0b393dacf7703fc36a4efc3df1435485197e6c1",
-                "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.2"
-            },
-            "require-dev": {
-                "jakub-onderka/php-code-style": "1.0",
-                "jakub-onderka/php-parallel-lint": "0.*",
-                "jakub-onderka/php-var-dump-check": "0.*",
-                "phpunit/phpunit": "3.7.*",
-                "squizlabs/php_codesniffer": "1.*"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-0": {
-                    "JakubOnderka\\PhpConsoleColor": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-2-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jakub Onderka",
-                    "email": "[email protected]",
-                    "homepage": "http://www.acci.cz"
-                }
-            ],
-            "time": "2014-04-08 15:00:19"
-        },
-        {
-            "name": "jakub-onderka/php-console-highlighter",
-            "version": "v0.3.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git",
-                "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/7daa75df45242c8d5b75a22c00a201e7954e4fb5",
-                "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5",
-                "shasum": ""
-            },
-            "require": {
-                "jakub-onderka/php-console-color": "~0.1",
-                "php": ">=5.3.0"
-            },
-            "require-dev": {
-                "jakub-onderka/php-code-style": "~1.0",
-                "jakub-onderka/php-parallel-lint": "~0.5",
-                "jakub-onderka/php-var-dump-check": "~0.1",
-                "phpunit/phpunit": "~4.0",
-                "squizlabs/php_codesniffer": "~1.5"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-0": {
-                    "JakubOnderka\\PhpConsoleHighlighter": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Jakub Onderka",
-                    "email": "[email protected]",
-                    "homepage": "http://www.acci.cz/"
-                }
-            ],
-            "time": "2015-04-20 18:58:01"
-        },
-        {
-            "name": "jeremeamia/SuperClosure",
-            "version": "2.2.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/jeremeamia/super_closure.git",
-                "reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/29a88be2a4846d27c1613aed0c9071dfad7b5938",
-                "reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938",
-                "shasum": ""
-            },
-            "require": {
-                "nikic/php-parser": "^1.2|^2.0",
-                "php": ">=5.4",
-                "symfony/polyfill-php56": "^1.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.0|^5.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.2-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "SuperClosure\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Jeremy Lindblom",
-                    "email": "[email protected]",
-                    "homepage": "https://github.com/jeremeamia",
-                    "role": "Developer"
-                }
-            ],
-            "description": "Serialize Closure objects, including their context and binding",
-            "homepage": "https://github.com/jeremeamia/super_closure",
-            "keywords": [
-                "closure",
-                "function",
-                "lambda",
-                "parser",
-                "serializable",
-                "serialize",
-                "tokenizer"
-            ],
-            "time": "2015-12-05 17:17:57"
+            "time": "2017-01-10 14:15:56"
         },
         {
             "name": "knplabs/knp-snappy",
             ],
             "time": "2015-11-17 13:16:27"
         },
+        {
+            "name": "laravel/browser-kit-testing",
+            "version": "v1.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/laravel/browser-kit-testing.git",
+                "reference": "60e038e3dcfef2977347f9610c14b48721802278"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/laravel/browser-kit-testing/zipball/60e038e3dcfef2977347f9610c14b48721802278",
+                "reference": "60e038e3dcfef2977347f9610c14b48721802278",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9",
+                "symfony/css-selector": "3.1.*",
+                "symfony/dom-crawler": "3.1.*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Laravel\\BrowserKitTesting\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Otwell",
+                    "email": "[email protected]"
+                }
+            ],
+            "description": "Provides backwards compatibility for BrowserKit testing in Laravel 5.4.",
+            "keywords": [
+                "laravel",
+                "testing"
+            ],
+            "time": "2017-01-25 13:07:25"
+        },
         {
             "name": "laravel/framework",
-            "version": "v5.3.11",
+            "version": "v5.4.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/framework.git",
-                "reference": "ca48001b95a0543fb39fcd7219de960bbc03eaa5"
+                "reference": "9fa94bf77272ea7f920292c6f016b0f6e0853f98"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/framework/zipball/ca48001b95a0543fb39fcd7219de960bbc03eaa5",
-                "reference": "ca48001b95a0543fb39fcd7219de960bbc03eaa5",
+                "url": "https://api.github.com/repos/laravel/framework/zipball/9fa94bf77272ea7f920292c6f016b0f6e0853f98",
+                "reference": "9fa94bf77272ea7f920292c6f016b0f6e0853f98",
                 "shasum": ""
             },
             "require": {
-                "classpreloader/classpreloader": "~3.0",
                 "doctrine/inflector": "~1.0",
+                "erusev/parsedown": "~1.6",
                 "ext-mbstring": "*",
                 "ext-openssl": "*",
-                "jeremeamia/superclosure": "~2.2",
                 "league/flysystem": "~1.0",
                 "monolog/monolog": "~1.11",
                 "mtdowling/cron-expression": "~1.0",
                 "nesbot/carbon": "~1.20",
                 "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": "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.*",
+                "swiftmailer/swiftmailer": "~5.4",
+                "symfony/console": "~3.2",
+                "symfony/debug": "~3.2",
+                "symfony/finder": "~3.2",
+                "symfony/http-foundation": "~3.2",
+                "symfony/http-kernel": "~3.2",
+                "symfony/process": "~3.2",
+                "symfony/routing": "~3.2",
+                "symfony/var-dumper": "~3.2",
+                "tijsverkoyen/css-to-inline-styles": "~2.2",
                 "vlucas/phpdotenv": "~2.2"
             },
             "replace": {
             },
             "require-dev": {
                 "aws/aws-sdk-php": "~3.0",
+                "doctrine/dbal": "~2.5",
                 "mockery/mockery": "~0.9.4",
                 "pda/pheanstalk": "~3.0",
-                "phpunit/phpunit": "~5.4",
+                "phpunit/phpunit": "~5.7",
                 "predis/predis": "~1.0",
-                "symfony/css-selector": "3.1.*",
-                "symfony/dom-crawler": "3.1.*"
+                "symfony/css-selector": "~3.2",
+                "symfony/dom-crawler": "~3.2"
             },
             "suggest": {
                 "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).",
-                "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).",
+                "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.5).",
                 "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).",
-                "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~5.3|~6.0).",
+                "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~6.0).",
+                "laravel/tinker": "Required to use the tinker console command (~1.0).",
                 "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).",
                 "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).",
+                "nexmo/client": "Required to use the Nexmo transport (~1.0).",
                 "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).",
                 "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 (3.1.*).",
-                "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (3.1.*).",
+                "symfony/css-selector": "Required to use some of the crawler integration testing tools (~3.2).",
+                "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (~3.2).",
                 "symfony/psr-http-message-bridge": "Required to psr7 bridging features (0.2.*)."
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "5.3-dev"
+                    "dev-master": "5.4-dev"
                 }
             },
             "autoload": {
                 "framework",
                 "laravel"
             ],
-            "time": "2016-09-28 02:15:37"
+            "time": "2017-01-25 16:40:49"
         },
         {
             "name": "laravel/socialite",
-            "version": "v2.0.18",
+            "version": "v3.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/socialite.git",
-                "reference": "76ee5397fcdea5a062361392abca4eb397e519a3"
+                "reference": "d3aaffa5e122395e54eb2c26062fde3a848c40fd"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/socialite/zipball/76ee5397fcdea5a062361392abca4eb397e519a3",
-                "reference": "76ee5397fcdea5a062361392abca4eb397e519a3",
+                "url": "https://api.github.com/repos/laravel/socialite/zipball/d3aaffa5e122395e54eb2c26062fde3a848c40fd",
+                "reference": "d3aaffa5e122395e54eb2c26062fde3a848c40fd",
                 "shasum": ""
             },
             "require": {
-                "guzzlehttp/guzzle": "~5.0|~6.0",
-                "illuminate/contracts": "~5.0",
-                "illuminate/http": "~5.0",
-                "illuminate/support": "~5.0",
+                "guzzlehttp/guzzle": "~6.0",
+                "illuminate/contracts": "~5.4",
+                "illuminate/http": "~5.4",
+                "illuminate/support": "~5.4",
                 "league/oauth1-client": "~1.0",
                 "php": ">=5.4.0"
             },
                 "laravel",
                 "oauth"
             ],
-            "time": "2016-06-22 12:40:16"
+            "time": "2017-01-25 17:58:13"
         },
         {
             "name": "league/flysystem",
-            "version": "1.0.27",
+            "version": "1.0.33",
             "source": {
                 "type": "git",
                 "url": "https://github.com/thephpleague/flysystem.git",
-                "reference": "50e2045ed70a7e75a5e30bc3662904f3b67af8a9"
+                "reference": "5c7f98498b12d47f9de90ec9186a90000125777c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/50e2045ed70a7e75a5e30bc3662904f3b67af8a9",
-                "reference": "50e2045ed70a7e75a5e30bc3662904f3b67af8a9",
+                "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/5c7f98498b12d47f9de90ec9186a90000125777c",
+                "reference": "5c7f98498b12d47f9de90ec9186a90000125777c",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.4.0"
+                "php": ">=5.5.9"
             },
             "conflict": {
                 "league/flysystem-sftp": "<1.0.6"
                 "sftp",
                 "storage"
             ],
-            "time": "2016-08-10 08:55:11"
+            "time": "2017-01-23 10:32:09"
         },
         {
             "name": "league/flysystem-aws-s3-v3",
         },
         {
             "name": "maximebf/debugbar",
-            "version": "v1.13.0",
+            "version": "1.13.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/maximebf/php-debugbar.git",
-                "reference": "5f49a5ed6cfde81d31d89378806670d77462526e"
+                "reference": "afee79a236348e39a44cb837106b7c5b4897ac2a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/5f49a5ed6cfde81d31d89378806670d77462526e",
-                "reference": "5f49a5ed6cfde81d31d89378806670d77462526e",
+                "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/afee79a236348e39a44cb837106b7c5b4897ac2a",
+                "reference": "afee79a236348e39a44cb837106b7c5b4897ac2a",
                 "shasum": ""
             },
             "require": {
                 "debug",
                 "debugbar"
             ],
-            "time": "2016-09-15 14:01:59"
+            "time": "2017-01-05 08:46:19"
         },
         {
             "name": "monolog/monolog",
-            "version": "1.21.0",
+            "version": "1.22.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Seldaek/monolog.git",
-                "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952"
+                "reference": "bad29cb8d18ab0315e6c477751418a82c850d558"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f42fbdfd53e306bda545845e4dbfd3e72edb4952",
-                "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952",
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bad29cb8d18ab0315e6c477751418a82c850d558",
+                "reference": "bad29cb8d18ab0315e6c477751418a82c850d558",
                 "shasum": ""
             },
             "require": {
                 "psr/log-implementation": "1.0.0"
             },
             "require-dev": {
-                "aws/aws-sdk-php": "^2.4.9",
+                "aws/aws-sdk-php": "^2.4.9 || ^3.0",
                 "doctrine/couchdb": "~1.0@dev",
                 "graylog2/gelf-php": "~1.0",
                 "jakub-onderka/php-parallel-lint": "0.9",
                 "logging",
                 "psr-3"
             ],
-            "time": "2016-07-29 03:23:52"
+            "time": "2016-11-26 00:15:39"
         },
         {
             "name": "mtdowling/cron-expression",
-            "version": "v1.1.0",
+            "version": "v1.2.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/mtdowling/cron-expression.git",
-                "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5"
+                "reference": "9504fa9ea681b586028adaaa0877db4aecf32bad"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
-                "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
+                "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/9504fa9ea681b586028adaaa0877db4aecf32bad",
+                "reference": "9504fa9ea681b586028adaaa0877db4aecf32bad",
                 "shasum": ""
             },
             "require": {
             },
             "type": "library",
             "autoload": {
-                "psr-0": {
-                    "Cron": "src/"
+                "psr-4": {
+                    "Cron\\": "src/Cron/"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
                 "cron",
                 "schedule"
             ],
-            "time": "2016-01-26 21:23:30"
+            "time": "2017-01-23 04:29:33"
         },
         {
             "name": "mtdowling/jmespath.php",
-            "version": "2.3.0",
+            "version": "2.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/jmespath/jmespath.php.git",
-                "reference": "192f93e43c2c97acde7694993ab171b3de284093"
+                "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/192f93e43c2c97acde7694993ab171b3de284093",
-                "reference": "192f93e43c2c97acde7694993ab171b3de284093",
+                "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/adcc9531682cf87dfda21e1fd5d0e7a41d292fac",
+                "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac",
                 "shasum": ""
             },
             "require": {
                 "json",
                 "jsonpath"
             ],
-            "time": "2016-01-05 18:25:05"
+            "time": "2016-12-03 22:08:25"
         },
         {
             "name": "nesbot/carbon",
-            "version": "1.21.0",
+            "version": "1.22.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/briannesbitt/Carbon.git",
-                "reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7"
+                "reference": "7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7b08ec6f75791e130012f206e3f7b0e76e18e3d7",
-                "reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7",
+                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc",
+                "reference": "7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.3.0",
-                "symfony/translation": "~2.6|~3.0"
+                "symfony/translation": "~2.6 || ~3.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.0|~5.0"
+                "friendsofphp/php-cs-fixer": "~2",
+                "phpunit/phpunit": "~4.0 || ~5.0"
             },
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.23-dev"
+                }
+            },
             "autoload": {
                 "psr-4": {
                     "Carbon\\": "src/Carbon/"
                 "datetime",
                 "time"
             ],
-            "time": "2015-11-04 20:07:17"
-        },
-        {
-            "name": "nikic/php-parser",
-            "version": "v2.1.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/nikic/PHP-Parser.git",
-                "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4dd659edadffdc2143e4753df655d866dbfeedf0",
-                "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0",
-                "shasum": ""
-            },
-            "require": {
-                "ext-tokenizer": "*",
-                "php": ">=5.4"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.0"
-            },
-            "bin": [
-                "bin/php-parse"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.1-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "PhpParser\\": "lib/PhpParser"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Nikita Popov"
-                }
-            ],
-            "description": "A PHP parser written in PHP",
-            "keywords": [
-                "parser",
-                "php"
-            ],
-            "time": "2016-09-16 12:04:44"
+            "time": "2017-01-16 07:55:07"
         },
         {
             "name": "paragonie/random_compat",
-            "version": "v2.0.2",
+            "version": "v2.0.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/paragonie/random_compat.git",
-                "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf"
+                "reference": "a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf",
-                "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf",
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e",
+                "reference": "a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e",
                 "shasum": ""
             },
             "require": {
                 "pseudorandom",
                 "random"
             ],
-            "time": "2016-04-03 06:00:07"
+            "time": "2016-11-07 23:38:38"
         },
         {
             "name": "phenx/php-font-lib",
         },
         {
             "name": "psr/log",
-            "version": "1.0.1",
+            "version": "1.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/log.git",
-                "reference": "5277094ed527a1c4477177d102fe4c53551953e0"
+                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/log/zipball/5277094ed527a1c4477177d102fe4c53551953e0",
-                "reference": "5277094ed527a1c4477177d102fe4c53551953e0",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
+                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
                 "shasum": ""
             },
             "require": {
                 "psr",
                 "psr-3"
             ],
-            "time": "2016-09-19 16:02:08"
-        },
-        {
-            "name": "psy/psysh",
-            "version": "v0.7.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/bobthecow/psysh.git",
-                "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/bobthecow/psysh/zipball/e64e10b20f8d229cac76399e1f3edddb57a0f280",
-                "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280",
-                "shasum": ""
-            },
-            "require": {
-                "dnoegel/php-xdg-base-dir": "0.1",
-                "jakub-onderka/php-console-highlighter": "0.3.*",
-                "nikic/php-parser": "^1.2.1|~2.0",
-                "php": ">=5.3.9",
-                "symfony/console": "~2.3.10|^2.4.2|~3.0",
-                "symfony/var-dumper": "~2.7|~3.0"
-            },
-            "require-dev": {
-                "fabpot/php-cs-fixer": "~1.5",
-                "phpunit/phpunit": "~3.7|~4.0|~5.0",
-                "squizlabs/php_codesniffer": "~2.0",
-                "symfony/finder": "~2.1|~3.0"
-            },
-            "suggest": {
-                "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)",
-                "ext-pdo-sqlite": "The doc command requires SQLite to work.",
-                "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.",
-                "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history."
-            },
-            "bin": [
-                "bin/psysh"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-develop": "0.8.x-dev"
-                }
-            },
-            "autoload": {
-                "files": [
-                    "src/Psy/functions.php"
-                ],
-                "psr-4": {
-                    "Psy\\": "src/Psy/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Justin Hileman",
-                    "email": "[email protected]",
-                    "homepage": "http://justinhileman.com"
-                }
-            ],
-            "description": "An interactive shell for modern PHP.",
-            "homepage": "http://psysh.org",
-            "keywords": [
-                "REPL",
-                "console",
-                "interactive",
-                "shell"
-            ],
-            "time": "2016-03-09 05:03:14"
+            "time": "2016-10-10 12:19:37"
         },
         {
             "name": "ramsey/uuid",
-            "version": "3.5.0",
+            "version": "3.5.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ramsey/uuid.git",
-                "reference": "a6d15c8618ea3951fd54d34e326b68d3d0bc0786"
+                "reference": "5677cfe02397dd6b58c861870dfaa5d9007d3954"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ramsey/uuid/zipball/a6d15c8618ea3951fd54d34e326b68d3d0bc0786",
-                "reference": "a6d15c8618ea3951fd54d34e326b68d3d0bc0786",
+                "url": "https://api.github.com/repos/ramsey/uuid/zipball/5677cfe02397dd6b58c861870dfaa5d9007d3954",
+                "reference": "5677cfe02397dd6b58c861870dfaa5d9007d3954",
                 "shasum": ""
             },
             "require": {
             "require-dev": {
                 "apigen/apigen": "^4.1",
                 "codeception/aspect-mock": "1.0.0",
+                "doctrine/annotations": "~1.2.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",
+                "php-mock/php-mock-phpunit": "^0.3|^1.1",
                 "phpunit/phpunit": "^4.7|>=5.0 <5.4",
                 "satooshi/php-coveralls": "^0.6.1",
                 "squizlabs/php_codesniffer": "^2.3"
                 "identifier",
                 "uuid"
             ],
-            "time": "2016-08-02 18:39:32"
+            "time": "2016-11-22 19:21:44"
         },
         {
             "name": "swiftmailer/swiftmailer",
-            "version": "v5.4.3",
+            "version": "v5.4.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/swiftmailer/swiftmailer.git",
-                "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153"
+                "reference": "cd142238a339459b10da3d8234220963f392540c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/4cc92842069c2bbc1f28daaaf1d2576ec4dfe153",
-                "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153",
+                "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/cd142238a339459b10da3d8234220963f392540c",
+                "reference": "cd142238a339459b10da3d8234220963f392540c",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.3.3"
             },
             "require-dev": {
-                "mockery/mockery": "~0.9.1"
+                "mockery/mockery": "~0.9.1",
+                "symfony/phpunit-bridge": "~3.2"
             },
             "type": "library",
             "extra": {
                 "mail",
                 "mailer"
             ],
-            "time": "2016-07-08 11:51:25"
+            "time": "2016-12-29 10:02:40"
         },
         {
             "name": "symfony/class-loader",
-            "version": "v3.1.4",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/class-loader.git",
-                "reference": "2d0ba77c46ecc96a6641009a98f72632216811ba"
+                "reference": "0152f7a47acd564ca62c652975c2b32ac6d613a6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/class-loader/zipball/2d0ba77c46ecc96a6641009a98f72632216811ba",
-                "reference": "2d0ba77c46ecc96a6641009a98f72632216811ba",
+                "url": "https://api.github.com/repos/symfony/class-loader/zipball/0152f7a47acd564ca62c652975c2b32ac6d613a6",
+                "reference": "0152f7a47acd564ca62c652975c2b32ac6d613a6",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony ClassLoader Component",
             "homepage": "https://symfony.com",
-            "time": "2016-08-23 13:39:15"
+            "time": "2017-01-10 14:14:38"
         },
         {
             "name": "symfony/console",
-            "version": "v3.1.4",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
-                "reference": "8ea494c34f0f772c3954b5fbe00bffc5a435e563"
+                "reference": "4f9e449e76996adf310498a8ca955c6deebe29dd"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/8ea494c34f0f772c3954b5fbe00bffc5a435e563",
-                "reference": "8ea494c34f0f772c3954b5fbe00bffc5a435e563",
+                "url": "https://api.github.com/repos/symfony/console/zipball/4f9e449e76996adf310498a8ca955c6deebe29dd",
+                "reference": "4f9e449e76996adf310498a8ca955c6deebe29dd",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.5.9",
+                "symfony/debug": "~2.8|~3.0",
                 "symfony/polyfill-mbstring": "~1.0"
             },
             "require-dev": {
                 "psr/log": "~1.0",
                 "symfony/event-dispatcher": "~2.8|~3.0",
+                "symfony/filesystem": "~2.8|~3.0",
                 "symfony/process": "~2.8|~3.0"
             },
             "suggest": {
                 "psr/log": "For using the console logger",
                 "symfony/event-dispatcher": "",
+                "symfony/filesystem": "",
                 "symfony/process": ""
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Console Component",
             "homepage": "https://symfony.com",
-            "time": "2016-08-19 06:48:39"
+            "time": "2017-01-08 20:47:33"
+        },
+        {
+            "name": "symfony/css-selector",
+            "version": "v3.1.9",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/css-selector.git",
+                "reference": "722a87478a72d95dc2a3bcf41dc9c2d13fd4cb2d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/css-selector/zipball/722a87478a72d95dc2a3bcf41dc9c2d13fd4cb2d",
+                "reference": "722a87478a72d95dc2a3bcf41dc9c2d13fd4cb2d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\CssSelector\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jean-François Simon",
+                    "email": "[email protected]"
+                },
+                {
+                    "name": "Fabien Potencier",
+                    "email": "[email protected]"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony CssSelector Component",
+            "homepage": "https://symfony.com",
+            "time": "2017-01-02 20:31:54"
         },
         {
             "name": "symfony/debug",
-            "version": "v3.1.4",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/debug.git",
-                "reference": "34f6ac18c2974ca5fce68adf419ee7d15def6f11"
+                "reference": "810ba5c1c5352a4ddb15d4719e8936751dff0b05"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/debug/zipball/34f6ac18c2974ca5fce68adf419ee7d15def6f11",
-                "reference": "34f6ac18c2974ca5fce68adf419ee7d15def6f11",
+                "url": "https://api.github.com/repos/symfony/debug/zipball/810ba5c1c5352a4ddb15d4719e8936751dff0b05",
+                "reference": "810ba5c1c5352a4ddb15d4719e8936751dff0b05",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
                     "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Symfony Debug Component",
+            "description": "Symfony Debug Component",
+            "homepage": "https://symfony.com",
+            "time": "2017-01-02 20:32:22"
+        },
+        {
+            "name": "symfony/dom-crawler",
+            "version": "v3.1.9",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/dom-crawler.git",
+                "reference": "a950260ebc947578fba82a3222e2085d90682376"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/a950260ebc947578fba82a3222e2085d90682376",
+                "reference": "a950260ebc947578fba82a3222e2085d90682376",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9",
+                "symfony/polyfill-mbstring": "~1.0"
+            },
+            "require-dev": {
+                "symfony/css-selector": "~2.8|~3.0"
+            },
+            "suggest": {
+                "symfony/css-selector": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\DomCrawler\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "[email protected]"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony DomCrawler Component",
             "homepage": "https://symfony.com",
-            "time": "2016-08-23 13:39:15"
+            "time": "2017-01-02 20:31:54"
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v3.1.4",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "c0c00c80b3a69132c4e55c3e7db32b4a387615e5"
+                "reference": "9137eb3a3328e413212826d63eeeb0217836e2b6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c0c00c80b3a69132c4e55c3e7db32b4a387615e5",
-                "reference": "c0c00c80b3a69132c4e55c3e7db32b4a387615e5",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9137eb3a3328e413212826d63eeeb0217836e2b6",
+                "reference": "9137eb3a3328e413212826d63eeeb0217836e2b6",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony EventDispatcher Component",
             "homepage": "https://symfony.com",
-            "time": "2016-07-19 10:45:57"
+            "time": "2017-01-02 20:32:22"
         },
         {
             "name": "symfony/finder",
-            "version": "v3.1.4",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "e568ef1784f447a0e54dcb6f6de30b9747b0f577"
+                "reference": "8c71141cae8e2957946b403cc71a67213c0380d6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/e568ef1784f447a0e54dcb6f6de30b9747b0f577",
-                "reference": "e568ef1784f447a0e54dcb6f6de30b9747b0f577",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/8c71141cae8e2957946b403cc71a67213c0380d6",
+                "reference": "8c71141cae8e2957946b403cc71a67213c0380d6",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Finder Component",
             "homepage": "https://symfony.com",
-            "time": "2016-08-26 12:04:02"
+            "time": "2017-01-02 20:32:22"
         },
         {
             "name": "symfony/http-foundation",
-            "version": "v3.1.4",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-foundation.git",
-                "reference": "63592e00fd90632b57ee50220a1ddb29b6bf3bb4"
+                "reference": "33eb76bf1d833c705433e5361a646c164696394b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/63592e00fd90632b57ee50220a1ddb29b6bf3bb4",
-                "reference": "63592e00fd90632b57ee50220a1ddb29b6bf3bb4",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/33eb76bf1d833c705433e5361a646c164696394b",
+                "reference": "33eb76bf1d833c705433e5361a646c164696394b",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony HttpFoundation Component",
             "homepage": "https://symfony.com",
-            "time": "2016-08-22 12:11:19"
+            "time": "2017-01-08 20:47:33"
         },
         {
             "name": "symfony/http-kernel",
-            "version": "v3.1.4",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-kernel.git",
-                "reference": "aeda215d6b01f119508c090d2a09ebb5b0bc61f3"
+                "reference": "8a898e340a89022246645b1288d295f49c9381e4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aeda215d6b01f119508c090d2a09ebb5b0bc61f3",
-                "reference": "aeda215d6b01f119508c090d2a09ebb5b0bc61f3",
+                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8a898e340a89022246645b1288d295f49c9381e4",
+                "reference": "8a898e340a89022246645b1288d295f49c9381e4",
                 "shasum": ""
             },
             "require": {
                 "psr/log": "~1.0",
                 "symfony/debug": "~2.8|~3.0",
                 "symfony/event-dispatcher": "~2.8|~3.0",
-                "symfony/http-foundation": "~2.8.8|~3.0.8|~3.1.2|~3.2"
+                "symfony/http-foundation": "~2.8.13|~3.1.6|~3.2"
             },
             "conflict": {
                 "symfony/config": "<2.8"
                 "symfony/stopwatch": "~2.8|~3.0",
                 "symfony/templating": "~2.8|~3.0",
                 "symfony/translation": "~2.8|~3.0",
-                "symfony/var-dumper": "~2.8|~3.0"
+                "symfony/var-dumper": "~3.2"
             },
             "suggest": {
                 "symfony/browser-kit": "",
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony HttpKernel Component",
             "homepage": "https://symfony.com",
-            "time": "2016-09-03 15:28:24"
+            "time": "2017-01-12 21:36:33"
         },
         {
             "name": "symfony/polyfill-mbstring",
-            "version": "v1.2.0",
+            "version": "v1.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "dff51f72b0706335131b00a7f49606168c582594"
+                "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
-                "reference": "dff51f72b0706335131b00a7f49606168c582594",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4",
+                "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.2-dev"
+                    "dev-master": "1.3-dev"
                 }
             },
             "autoload": {
                 "portable",
                 "shim"
             ],
-            "time": "2016-05-18 14:26:46"
-        },
-        {
-            "name": "symfony/polyfill-php56",
-            "version": "v1.2.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-php56.git",
-                "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/3edf57a8fbf9a927533344cef65ad7e1cf31030a",
-                "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3",
-                "symfony/polyfill-util": "~1.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.2-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Php56\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "time": "2016-05-18 14:26:46"
-        },
-        {
-            "name": "symfony/polyfill-util",
-            "version": "v1.2.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-util.git",
-                "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/ef830ce3d218e622b221d6bfad42c751d974bf99",
-                "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.2-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Util\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony utilities for portability of PHP codes",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compat",
-                "compatibility",
-                "polyfill",
-                "shim"
-            ],
-            "time": "2016-05-18 14:26:46"
+            "time": "2016-11-14 01:06:16"
         },
         {
             "name": "symfony/process",
-            "version": "v3.1.4",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
-                "reference": "e64e93041c80e77197ace5ab9385dedb5a143697"
+                "reference": "350e810019fc52dd06ae844b6a6d382f8a0e8893"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/e64e93041c80e77197ace5ab9385dedb5a143697",
-                "reference": "e64e93041c80e77197ace5ab9385dedb5a143697",
+                "url": "https://api.github.com/repos/symfony/process/zipball/350e810019fc52dd06ae844b6a6d382f8a0e8893",
+                "reference": "350e810019fc52dd06ae844b6a6d382f8a0e8893",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Process Component",
             "homepage": "https://symfony.com",
-            "time": "2016-08-16 14:58:24"
+            "time": "2017-01-02 20:32:22"
         },
         {
             "name": "symfony/routing",
-            "version": "v3.1.4",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/routing.git",
-                "reference": "8edf62498a1a4c57ba317664a4b698339c10cdf6"
+                "reference": "fda2c67d47ec801726ca888c95d701d31b27b444"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/routing/zipball/8edf62498a1a4c57ba317664a4b698339c10cdf6",
-                "reference": "8edf62498a1a4c57ba317664a4b698339c10cdf6",
+                "url": "https://api.github.com/repos/symfony/routing/zipball/fda2c67d47ec801726ca888c95d701d31b27b444",
+                "reference": "fda2c67d47ec801726ca888c95d701d31b27b444",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
                 "uri",
                 "url"
             ],
-            "time": "2016-08-16 14:58:24"
+            "time": "2017-01-02 20:32:22"
         },
         {
             "name": "symfony/translation",
-            "version": "v3.1.4",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/translation.git",
-                "reference": "a35edc277513c9bc0f063ca174c36b346f974528"
+                "reference": "6520f3d4cce604d9dd1e86cac7af954984dd9bda"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/translation/zipball/a35edc277513c9bc0f063ca174c36b346f974528",
-                "reference": "a35edc277513c9bc0f063ca174c36b346f974528",
+                "url": "https://api.github.com/repos/symfony/translation/zipball/6520f3d4cce604d9dd1e86cac7af954984dd9bda",
+                "reference": "6520f3d4cce604d9dd1e86cac7af954984dd9bda",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Translation Component",
             "homepage": "https://symfony.com",
-            "time": "2016-08-05 08:37:39"
+            "time": "2017-01-02 20:32:22"
         },
         {
             "name": "symfony/var-dumper",
-            "version": "v3.1.4",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/var-dumper.git",
-                "reference": "62ee73706c421654a4c840028954510277f7dfc8"
+                "reference": "b54b23f9a19b465e76fdaac0f6732410467c83b2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/62ee73706c421654a4c840028954510277f7dfc8",
-                "reference": "62ee73706c421654a4c840028954510277f7dfc8",
+                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b54b23f9a19b465e76fdaac0f6732410467c83b2",
+                "reference": "b54b23f9a19b465e76fdaac0f6732410467c83b2",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
                 "debug",
                 "dump"
             ],
-            "time": "2016-08-31 09:05:42"
+            "time": "2017-01-03 08:53:57"
+        },
+        {
+            "name": "tijsverkoyen/css-to-inline-styles",
+            "version": "2.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git",
+                "reference": "ab03919dfd85a74ae0372f8baf9f3c7d5c03b04b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/ab03919dfd85a74ae0372f8baf9f3c7d5c03b04b",
+                "reference": "ab03919dfd85a74ae0372f8baf9f3c7d5c03b04b",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5 || ^7",
+                "symfony/css-selector": "^2.7|~3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.8|5.1.*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "TijsVerkoyen\\CssToInlineStyles\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Tijs Verkoyen",
+                    "email": "[email protected]",
+                    "role": "Developer"
+                }
+            ],
+            "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.",
+            "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles",
+            "time": "2016-09-20 12:50:39"
         },
         {
             "name": "vlucas/phpdotenv",
         },
         {
             "name": "mockery/mockery",
-            "version": "0.9.5",
+            "version": "0.9.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/padraic/mockery.git",
-                "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2"
+                "reference": "4de7969f4664da3cef1ccd83866c9f59378c3371"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/padraic/mockery/zipball/4db079511a283e5aba1b3c2fb19037c645e70fc2",
-                "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2",
+                "url": "https://api.github.com/repos/padraic/mockery/zipball/4de7969f4664da3cef1ccd83866c9f59378c3371",
+                "reference": "4de7969f4664da3cef1ccd83866c9f59378c3371",
                 "shasum": ""
             },
             "require": {
                 "test double",
                 "testing"
             ],
-            "time": "2016-05-22 21:52:33"
+            "time": "2016-12-19 14:50:55"
         },
         {
             "name": "myclabs/deep-copy",
-            "version": "1.5.4",
+            "version": "1.5.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/myclabs/DeepCopy.git",
-                "reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f"
+                "reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/ea74994a3dc7f8d2f65a06009348f2d63c81e61f",
-                "reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f",
+                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/399c1f9781e222f6eb6cc238796f5200d1b7f108",
+                "reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108",
                 "shasum": ""
             },
             "require": {
                 "object",
                 "object graph"
             ],
-            "time": "2016-09-16 13:37:59"
+            "time": "2016-10-31 17:19:45"
         },
         {
             "name": "phpdocumentor/reflection-common",
         },
         {
             "name": "phpdocumentor/reflection-docblock",
-            "version": "3.1.0",
+            "version": "3.1.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
-                "reference": "9270140b940ff02e58ec577c237274e92cd40cdd"
+                "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd",
-                "reference": "9270140b940ff02e58ec577c237274e92cd40cdd",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e",
+                "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e",
                 "shasum": ""
             },
             "require": {
                 }
             ],
             "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"
+            "time": "2016-09-30 07:12:33"
         },
         {
             "name": "phpdocumentor/type-resolver",
-            "version": "0.2",
+            "version": "0.2.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpDocumentor/TypeResolver.git",
-                "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443"
+                "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443",
-                "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443",
+                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
+                "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
                 "shasum": ""
             },
             "require": {
                     "email": "[email protected]"
                 }
             ],
-            "time": "2016-06-10 07:14:17"
+            "time": "2016-11-25 06:54:22"
         },
         {
             "name": "phpspec/prophecy",
-            "version": "v1.6.1",
+            "version": "v1.6.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpspec/prophecy.git",
-                "reference": "58a8137754bc24b25740d4281399a4a3596058e0"
+                "reference": "6c52c2722f8460122f96f86346600e1077ce22cb"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0",
-                "reference": "58a8137754bc24b25740d4281399a4a3596058e0",
+                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb",
+                "reference": "6c52c2722f8460122f96f86346600e1077ce22cb",
                 "shasum": ""
             },
             "require": {
                 "php": "^5.3|^7.0",
                 "phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
                 "sebastian/comparator": "^1.1",
-                "sebastian/recursion-context": "^1.0"
+                "sebastian/recursion-context": "^1.0|^2.0"
             },
             "require-dev": {
-                "phpspec/phpspec": "^2.0"
+                "phpspec/phpspec": "^2.0",
+                "phpunit/phpunit": "^4.8 || ^5.6.5"
             },
             "type": "library",
             "extra": {
                 "spy",
                 "stub"
             ],
-            "time": "2016-06-07 08:13:47"
+            "time": "2016-11-21 14:58:47"
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "4.0.1",
+            "version": "4.0.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "5f3f7e736d6319d5f1fc402aff8b026da26709a3"
+                "reference": "c19cfc7cbb0e9338d8c469c7eedecc2a428b0971"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5f3f7e736d6319d5f1fc402aff8b026da26709a3",
-                "reference": "5f3f7e736d6319d5f1fc402aff8b026da26709a3",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c19cfc7cbb0e9338d8c469c7eedecc2a428b0971",
+                "reference": "c19cfc7cbb0e9338d8c469c7eedecc2a428b0971",
                 "shasum": ""
             },
             "require": {
                 "testing",
                 "xunit"
             ],
-            "time": "2016-07-26 14:39:29"
+            "time": "2017-01-20 15:06:43"
         },
         {
             "name": "phpunit/php-file-iterator",
-            "version": "1.4.1",
+            "version": "1.4.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
-                "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
+                "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
-                "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
+                "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
                 "shasum": ""
             },
             "require": {
                 "filesystem",
                 "iterator"
             ],
-            "time": "2015-06-21 13:08:43"
+            "time": "2016-10-03 07:40:28"
         },
         {
             "name": "phpunit/php-text-template",
         },
         {
             "name": "phpunit/php-token-stream",
-            "version": "1.4.8",
+            "version": "1.4.9",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-token-stream.git",
-                "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
+                "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
-                "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b",
+                "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b",
                 "shasum": ""
             },
             "require": {
             "keywords": [
                 "tokenizer"
             ],
-            "time": "2015-09-15 10:49:45"
+            "time": "2016-11-15 14:06:22"
         },
         {
             "name": "phpunit/phpunit",
-            "version": "5.5.5",
+            "version": "5.7.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "a57126dc681b08289fef6ac96a48e30656f84350"
+                "reference": "caf8141b89691498d91aaac6c82e9cd5f685ae86"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a57126dc681b08289fef6ac96a48e30656f84350",
-                "reference": "a57126dc681b08289fef6ac96a48e30656f84350",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/caf8141b89691498d91aaac6c82e9cd5f685ae86",
+                "reference": "caf8141b89691498d91aaac6c82e9cd5f685ae86",
                 "shasum": ""
             },
             "require": {
                 "ext-xml": "*",
                 "myclabs/deep-copy": "~1.3",
                 "php": "^5.6 || ^7.0",
-                "phpspec/prophecy": "^1.3.1",
-                "phpunit/php-code-coverage": "^4.0.1",
+                "phpspec/prophecy": "^1.6.2",
+                "phpunit/php-code-coverage": "^4.0.4",
                 "phpunit/php-file-iterator": "~1.4",
                 "phpunit/php-text-template": "~1.2",
                 "phpunit/php-timer": "^1.0.6",
                 "phpunit/phpunit-mock-objects": "^3.2",
-                "sebastian/comparator": "~1.1",
+                "sebastian/comparator": "~1.2.2",
                 "sebastian/diff": "~1.2",
-                "sebastian/environment": "^1.3 || ^2.0",
-                "sebastian/exporter": "~1.2",
-                "sebastian/global-state": "~1.0",
-                "sebastian/object-enumerator": "~1.0",
+                "sebastian/environment": "^1.3.4 || ^2.0",
+                "sebastian/exporter": "~2.0",
+                "sebastian/global-state": "^1.0 || ^2.0",
+                "sebastian/object-enumerator": "~2.0",
                 "sebastian/resource-operations": "~1.0",
                 "sebastian/version": "~1.0|~2.0",
                 "symfony/yaml": "~2.1|~3.0"
                 "ext-pdo": "*"
             },
             "suggest": {
-                "ext-tidy": "*",
                 "ext-xdebug": "*",
                 "phpunit/php-invoker": "~1.1"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "5.5.x-dev"
+                    "dev-master": "5.7.x-dev"
                 }
             },
             "autoload": {
                 "testing",
                 "xunit"
             ],
-            "time": "2016-09-21 14:40:13"
+            "time": "2017-01-22 08:39:59"
         },
         {
             "name": "phpunit/phpunit-mock-objects",
-            "version": "3.2.7",
+            "version": "3.4.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
-                "reference": "546898a2c0c356ef2891b39dd7d07f5d82c8ed0a"
+                "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/546898a2c0c356ef2891b39dd7d07f5d82c8ed0a",
-                "reference": "546898a2c0c356ef2891b39dd7d07f5d82c8ed0a",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3ab72b65b39b491e0c011e2e09bb2206c2aa8e24",
+                "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24",
                 "shasum": ""
             },
             "require": {
                 "doctrine/instantiator": "^1.0.2",
                 "php": "^5.6 || ^7.0",
                 "phpunit/php-text-template": "^1.2",
-                "sebastian/exporter": "^1.2"
+                "sebastian/exporter": "^1.2 || ^2.0"
             },
             "conflict": {
                 "phpunit/phpunit": "<5.4.0"
                 "mock",
                 "xunit"
             ],
-            "time": "2016-09-06 16:07:45"
+            "time": "2016-12-08 20:27:08"
         },
         {
             "name": "sebastian/code-unit-reverse-lookup",
         },
         {
             "name": "sebastian/comparator",
-            "version": "1.2.0",
+            "version": "1.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/comparator.git",
-                "reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
+                "reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
-                "reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
+                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a1ed12e8b2409076ab22e3897126211ff8b1f7f",
+                "reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.3.3",
                 "sebastian/diff": "~1.2",
-                "sebastian/exporter": "~1.2"
+                "sebastian/exporter": "~1.2 || ~2.0"
             },
             "require-dev": {
                 "phpunit/phpunit": "~4.4"
                 "compare",
                 "equality"
             ],
-            "time": "2015-07-26 15:48:44"
+            "time": "2016-11-19 09:18:40"
         },
         {
             "name": "sebastian/diff",
         },
         {
             "name": "sebastian/environment",
-            "version": "1.3.8",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/environment.git",
-                "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
+                "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
-                "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
+                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
+                "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.3.3 || ^7.0"
+                "php": "^5.6 || ^7.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "^4.8 || ^5.0"
+                "phpunit/phpunit": "^5.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.3.x-dev"
+                    "dev-master": "2.0.x-dev"
                 }
             },
             "autoload": {
                 "environment",
                 "hhvm"
             ],
-            "time": "2016-08-18 05:49:44"
+            "time": "2016-11-26 07:53:53"
         },
         {
             "name": "sebastian/exporter",
-            "version": "1.2.2",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/exporter.git",
-                "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
+                "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
-                "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
+                "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.3.3",
-                "sebastian/recursion-context": "~1.0"
+                "sebastian/recursion-context": "~2.0"
             },
             "require-dev": {
                 "ext-mbstring": "*",
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.3.x-dev"
+                    "dev-master": "2.0.x-dev"
                 }
             },
             "autoload": {
                 "export",
                 "exporter"
             ],
-            "time": "2016-06-17 09:04:28"
+            "time": "2016-11-19 08:54:04"
         },
         {
             "name": "sebastian/global-state",
         },
         {
             "name": "sebastian/object-enumerator",
-            "version": "1.0.0",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/object-enumerator.git",
-                "reference": "d4ca2fb70344987502567bc50081c03e6192fb26"
+                "reference": "96f8a3f257b69e8128ad74d3a7fd464bcbaa3b35"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26",
-                "reference": "d4ca2fb70344987502567bc50081c03e6192fb26",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/96f8a3f257b69e8128ad74d3a7fd464bcbaa3b35",
+                "reference": "96f8a3f257b69e8128ad74d3a7fd464bcbaa3b35",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.6",
-                "sebastian/recursion-context": "~1.0"
+                "sebastian/recursion-context": "~2.0"
             },
             "require-dev": {
                 "phpunit/phpunit": "~5"
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0.x-dev"
+                    "dev-master": "2.0.x-dev"
                 }
             },
             "autoload": {
             ],
             "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"
+            "time": "2016-11-19 07:35:10"
         },
         {
             "name": "sebastian/recursion-context",
-            "version": "1.0.2",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/recursion-context.git",
-                "reference": "913401df809e99e4f47b27cdd781f4a258d58791"
+                "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
-                "reference": "913401df809e99e4f47b27cdd781f4a258d58791",
+                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a",
+                "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0.x-dev"
+                    "dev-master": "2.0.x-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Provides functionality to recursively process PHP variables",
             "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
-            "time": "2015-11-11 19:50:13"
+            "time": "2016-11-19 07:33:16"
         },
         {
             "name": "sebastian/resource-operations",
         },
         {
             "name": "sebastian/version",
-            "version": "2.0.0",
+            "version": "2.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/version.git",
-                "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5"
+                "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5",
-                "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5",
+                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
+                "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
                 "shasum": ""
             },
             "require": {
             ],
             "description": "Library that helps with managing the version number of Git-hosted PHP projects",
             "homepage": "https://github.com/sebastianbergmann/version",
-            "time": "2016-02-04 12:56:52"
+            "time": "2016-10-03 07:35:21"
         },
         {
-            "name": "symfony/css-selector",
-            "version": "v3.1.4",
+            "name": "symfony/yaml",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
-                "url": "https://github.com/symfony/css-selector.git",
-                "reference": "2851e1932d77ce727776154d659b232d061e816a"
+                "url": "https://github.com/symfony/yaml.git",
+                "reference": "50eadbd7926e31842893c957eca362b21592a97d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/css-selector/zipball/2851e1932d77ce727776154d659b232d061e816a",
-                "reference": "2851e1932d77ce727776154d659b232d061e816a",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/50eadbd7926e31842893c957eca362b21592a97d",
+                "reference": "50eadbd7926e31842893c957eca362b21592a97d",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.5.9"
             },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.1-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\CssSelector\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Jean-François Simon",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Fabien Potencier",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony CssSelector Component",
-            "homepage": "https://symfony.com",
-            "time": "2016-06-29 05:41:56"
-        },
-        {
-            "name": "symfony/dom-crawler",
-            "version": "v3.1.4",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/dom-crawler.git",
-                "reference": "bb7395e8b1db3654de82b9f35d019958276de4d7"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/bb7395e8b1db3654de82b9f35d019958276de4d7",
-                "reference": "bb7395e8b1db3654de82b9f35d019958276de4d7",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.5.9",
-                "symfony/polyfill-mbstring": "~1.0"
-            },
             "require-dev": {
-                "symfony/css-selector": "~2.8|~3.0"
+                "symfony/console": "~2.8|~3.0"
             },
             "suggest": {
-                "symfony/css-selector": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.1-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\DomCrawler\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "[email protected]"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony DomCrawler Component",
-            "homepage": "https://symfony.com",
-            "time": "2016-08-05 08:37:39"
-        },
-        {
-            "name": "symfony/yaml",
-            "version": "v3.1.4",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/yaml.git",
-                "reference": "f291ed25eb1435bddbe8a96caaef16469c2a092d"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/f291ed25eb1435bddbe8a96caaef16469c2a092d",
-                "reference": "f291ed25eb1435bddbe8a96caaef16469c2a092d",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.5.9"
+                "symfony/console": "For validating YAML files using the lint command"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Yaml Component",
             "homepage": "https://symfony.com",
-            "time": "2016-09-02 02:12:52"
+            "time": "2017-01-03 13:51:32"
         },
         {
             "name": "webmozart/assert",
-            "version": "1.1.0",
+            "version": "1.2.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/webmozart/assert.git",
-                "reference": "bb2d123231c095735130cc8f6d31385a44c7b308"
+                "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308",
-                "reference": "bb2d123231c095735130cc8f6d31385a44c7b308",
+                "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f",
+                "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.3.3|^7.0"
+                "php": "^5.3.3 || ^7.0"
             },
             "require-dev": {
                 "phpunit/phpunit": "^4.6",
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.2-dev"
+                    "dev-master": "1.3-dev"
                 }
             },
             "autoload": {
                 "check",
                 "validate"
             ],
-            "time": "2016-08-09 15:02:57"
+            "time": "2016-11-23 20:04:58"
         }
     ],
     "aliases": [],
index 3820d5b59eeb90e490d1bf41e8bae11067da8850..43e2143868dd0c48ecc83d45cf53837d180111bb 100644 (file)
@@ -59,4 +59,14 @@ $factory->define(BookStack\Tag::class, function ($faker) {
         'name' => $faker->city,
         'value' => $faker->sentence(3)
     ];
+});
+
+$factory->define(BookStack\Image::class, function ($faker) {
+    return [
+        'name' => $faker->slug . '.jpg',
+        'url' => $faker->url,
+        'path' => $faker->url,
+        'type' => 'gallery',
+        'uploaded_to' => 0
+    ];
 });
\ No newline at end of file
diff --git a/database/migrations/2017_01_21_163556_create_cache_table.php b/database/migrations/2017_01_21_163556_create_cache_table.php
new file mode 100644 (file)
index 0000000..1f7761c
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class CreateCacheTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('cache', function (Blueprint $table) {
+            $table->string('key')->unique();
+            $table->text('value');
+            $table->integer('expiration');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('cache');
+    }
+}
diff --git a/database/migrations/2017_01_21_163602_create_sessions_table.php b/database/migrations/2017_01_21_163602_create_sessions_table.php
new file mode 100644 (file)
index 0000000..56e76d6
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class CreateSessionsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('sessions', function (Blueprint $table) {
+            $table->string('id')->unique();
+            $table->integer('user_id')->nullable();
+            $table->string('ip_address', 45)->nullable();
+            $table->text('user_agent')->nullable();
+            $table->text('payload');
+            $table->integer('last_activity');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('sessions');
+    }
+}
index ec5911b939c0e564f7565d05360d78467973cf47..b0805c91836ff5ac9e12a1e9d1f6790fbc5c707b 100644 (file)
@@ -16,7 +16,9 @@
     "laravel-elixir": "^6.0.0-11",
     "laravel-elixir-browserify-official": "^0.1.3",
     "marked": "^0.3.5",
-    "moment": "^2.12.0",
-    "zeroclipboard": "^2.2.0"
+    "moment": "^2.12.0"
+  },
+  "dependencies": {
+    "clipboard": "^1.5.16"
   }
 }
diff --git a/public/ZeroClipboard.swf b/public/ZeroClipboard.swf
deleted file mode 100644 (file)
index 8bad6a3..0000000
Binary files a/public/ZeroClipboard.swf and /dev/null differ
index fa5c48fe08b97159cf4e4b527f2cd9f3ca4ce1ce..63d43e4b792f818b546e6e0ccc56408b8e5c128e 100644 (file)
--- a/readme.md
+++ b/readme.md
@@ -40,13 +40,19 @@ php artisan db:seed --class=DummyContentSeeder --database=mysql_testing
 
 Once done you can run `phpunit` in the application root directory to run all tests.
 
-## Website and Docs 
+## Translations
 
-The website and project docs are currently stored in the [BookStackApp/website](https://github.com/BookStackApp/website) repo. The docs are stored as markdown files in the `resources/docs` folder
+As part of BookStack v0.14 support for translations has been built in. All text strings can be found in the `resources/lang` folder where each language option has its own folder. To add a new language you should copy the `en` folder to an new folder (eg. `fr` for french) then go through and translate all text strings in those files, leaving the keys and file-names intact. If a language string is missing then the `en` translation will be used. To show the language option in the user preferences language drop-down you will need to add your language to the options found at the bottom of the `resources/lang/en/settings.php` file. A system-wide language can also be set in the `.env` file like so: `APP_LANG=en`.
+ Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time.
+
+## Website, Docs & Blog 
+
+The website project docs & Blog can be found in the [BookStackApp/website](https://github.com/BookStackApp/website) repo.
 
 ## License
 
-BookStack is provided under the MIT License.
+The BookStack source is provided under the MIT License.
 
 ## Attribution
 
index 94462ed6483de9ba64f2035c33facd642dda5308..650919f85e7c243837c02cafce0827bece3fa0ea 100644 (file)
@@ -61,10 +61,9 @@ Controllers(ngApp, window.Events);
 // Smooth scrolling
 jQuery.fn.smoothScrollTo = function () {
     if (this.length === 0) return;
-    let scrollElem = document.documentElement.scrollTop === 0 ?  document.body : document.documentElement;
-    $(scrollElem).animate({
+    $('html, body').animate({
         scrollTop: this.offset().top - 60 // Adjust to change final scroll position top margin
-    }, 800); // Adjust to change animations speed (ms)
+    }, 300); // Adjust to change animations speed (ms)
     return this;
 };
 
index e1c0cfe8f14c04345910be43c6aff3b13a732b9d..0f44b3d09a5aa45e47a787264333f45a2eb1a59e 100644 (file)
@@ -77,7 +77,7 @@ export default function() {
         extended_valid_elements: 'pre[*]',
         automatic_uploads: false,
         valid_children: "-div[p|pre|h1|h2|h3|h4|h5|h6|blockquote]",
-        plugins: "image table textcolor paste link fullscreen imagetools code customhr autosave lists",
+        plugins: "image table textcolor paste link autolink fullscreen imagetools code customhr autosave lists",
         imagetools_toolbar: 'imageoptions',
         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;}",
index 0cdde790dcdbdad18b2fdea13c144202e8579717..0f45e1987cf434959169128a0632692cc1937aa9 100644 (file)
@@ -1,13 +1,16 @@
 "use strict";
 // Configure ZeroClipboard
-import zeroClipBoard from "zeroclipboard";
+import Clipboard from "clipboard";
 
 export default window.setupPageShow = function (pageId) {
 
     // Set up pointer
     let $pointer = $('#pointer').detach();
+    let pointerShowing = false;
     let $pointerInner = $pointer.children('div.pointer').first();
     let isSelection = false;
+    let pointerModeLink = true;
+    let pointerSectionId = '';
 
     // Select all contents on input click
     $pointer.on('click', 'input', function (e) {
@@ -15,19 +18,34 @@ export default window.setupPageShow = function (pageId) {
         e.stopPropagation();
     });
 
-    // Set up copy-to-clipboard
-    zeroClipBoard.config({
-        swfPath: window.baseUrl('/ZeroClipboard.swf')
+    // Pointer mode toggle
+    $pointer.on('click', 'span.icon', event => {
+        let $icon = $(event.currentTarget);
+        pointerModeLink = !pointerModeLink;
+        $icon.html(pointerModeLink ? '<i class="zmdi zmdi-link"></i>' : '<i class="zmdi zmdi-square-down"></i>');
+        updatePointerContent();
     });
-    new zeroClipBoard($pointer.find('button').first()[0]);
+
+    // Set up clipboard
+    let clipboard = new Clipboard('#pointer button');
 
     // Hide pointer when clicking away
-    $(document.body).find('*').on('click focus', function (e) {
-        if (!isSelection) {
-            $pointer.detach();
-        }
+    $(document.body).find('*').on('click focus', event => {
+        if (!pointerShowing || isSelection) return;
+        let target = $(event.target);
+        if (target.is('.zmdi') || $(event.target).closest('#pointer').length === 1) return;
+
+        $pointer.detach();
+        pointerShowing = false;
     });
 
+    function updatePointerContent() {
+        let inputText = pointerModeLink ? window.baseUrl(`/link/${pageId}#${pointerSectionId}`) : `{{@${pageId}#${pointerSectionId}}}`;
+        if (pointerModeLink && inputText.indexOf('http') !== 0) inputText = window.location.protocol + "//" + window.location.host + inputText;
+
+        $pointer.find('input').val(inputText);
+    }
+
     // Show pointer when selecting a single block of tagged content
     $('.page-content [id^="bkmrk"]').on('mouseup keyup', function (e) {
         e.stopPropagation();
@@ -36,12 +54,12 @@ export default window.setupPageShow = function (pageId) {
 
         // Show pointer and set link
         let $elem = $(this);
-        let link = window.baseUrl('/link/' + pageId + '#' + $elem.attr('id'));
-        if (link.indexOf('http') !== 0) link = window.location.protocol + "//" + window.location.host + link;
-        $pointer.find('input').val(link);
-        $pointer.find('button').first().attr('data-clipboard-text', link);
+        pointerSectionId = $elem.attr('id');
+        updatePointerContent();
+
         $elem.before($pointer);
         $pointer.show();
+        pointerShowing = true;
 
         // Set pointer to sit near mouse-up position
         let pointerLeftOffset = (e.pageX - $elem.offset().left - ($pointerInner.width() / 2));
@@ -57,10 +75,12 @@ export default window.setupPageShow = function (pageId) {
 
     // Go to, and highlight if necessary, the specified text.
     function goToText(text) {
-        let idElem = $('.page-content #' + text).first();
-        if (idElem.length !== 0) {
-            idElem.smoothScrollTo();
-            idElem.css('background-color', 'rgba(244, 249, 54, 0.25)');
+        let idElem = document.getElementById(text);
+        $('.page-content [data-highlighted]').attr('data-highlighted', '').css('background-color', '');
+        if (idElem !== null) {
+            let $idElem = $(idElem);
+            let color = $('#custom-styles').attr('data-color-light');
+            $idElem.css('background-color', color).attr('data-highlighted', 'true').smoothScrollTo();
         } else {
             $('.page-content').find(':contains("' + text + '")').smoothScrollTo();
         }
@@ -72,6 +92,11 @@ export default window.setupPageShow = function (pageId) {
         goToText(text);
     }
 
+    // Sidebar page nav click event
+    $('.sidebar-page-nav').on('click', 'a', event => {
+        goToText(event.target.getAttribute('href').substr(1));
+    });
+
     // Make the book-tree sidebar stick in view on scroll
     let $window = $(window);
     let $bookTree = $(".book-tree");
index 7eb595d3611a5dc705d486416ca708344174080c..a2023aa37643c7e50703b4e120854bf56dab94bd 100644 (file)
   background-color: #EEE;
   padding: $-s;
   display: block;
-  > * {
-    display: inline-block;
-  }
   &:before {
     font-family: 'Material-Design-Iconic-Font';
     padding-right: $-s;
index 5de8896735aa9799ef5a4b12cf04b098c0366b42..791a5bb72a62b4eaabcd1762004559b5c1d39db5 100644 (file)
@@ -108,5 +108,4 @@ $button-border-radius: 2px;
     cursor: default;
     box-shadow: none;
   }
-}
-
+}
\ No newline at end of file
index c8fd8bcfabd56235bf392fed177898c830115d0b..5328057d9da7af1d81767d2fd1a05d8d6b486541 100644 (file)
@@ -70,9 +70,6 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
 #entity-selector-wrap .popup-body .form-group {
   margin: 0;
 }
-//body.ie #entity-selector-wrap .popup-body .form-group {
-//  min-height: 60vh;
-//}
 
 .image-manager-body {
   min-height: 70vh;
index 0052a3319fd4f47cace364dc638e5fd1651b0366..e5334c69c7d15d68fb2c43d5abf165460210143d 100755 (executable)
     font-size: 18px;
     padding-top: 4px;
   }
+  span.icon {
+    cursor: pointer;
+    user-select: none;
+  }
   .button {
     line-height: 1;
     margin: 0 0 0 -4px;
index dd2f32e1c2eb98e08d523ef95b464e8df79ebf60..74eb6875af6e23ff092c5296507b73b4dc71d5ff 100644 (file)
@@ -175,6 +175,7 @@ pre code {
   background-color: transparent;
   border: 0;
   font-size: 1em;
+  display: block;
 }
 /*
  * Text colors
index 60450f3e2e5a1436dacc4554f41c4e363030d5d6..7e1ab4e9ed5c1b7d3e8094783865af5211943af1 100644 (file)
@@ -1,4 +1,4 @@
-//@import "reset";
+@import "reset";
 @import "variables";
 @import "mixins";
 @import "html";
index 033d9614ebcf12a20065a488a54e4f0debbbe8f9..109b6ee2a50251fe0b62cc59fba2b948e271c7a8 100644 (file)
@@ -89,6 +89,7 @@ return [
      * Chapters
      */
     'chapter' => 'Chapter',
+    'chapters' => 'Chapters',
     'chapters_popular' => 'Popular Chapters',
     'chapters_new' => 'New Chapter',
     'chapters_create' => 'Create New Chapter',
index e61df19d91172738d7ef1f3783c7bb847f2e1cf2..ed8a0db43e47af93ad8c1af129274c55f4a3e552 100644 (file)
@@ -1,13 +1,13 @@
 <?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',
     'settings_save_success' => 'Settings saved',
@@ -92,7 +92,7 @@ return [
     'users_password_warning' => 'Only fill the below if you would like to change your password:',
     'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.',
     'users_delete' => 'Delete User',
-    'users_delete_named' => 'Delete ser :userName',
+    'users_delete_named' => 'Delete user :userName',
     'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.',
     'users_delete_confirm' => 'Are you sure you want to delete this user?',
     'users_delete_success' => 'Users successfully removed',
@@ -101,40 +101,23 @@ return [
     'users_edit_success' => 'User successfully updated',
     'users_avatar' => 'User Avatar',
     'users_avatar_desc' => 'This image should be approx 256px square.',
+    'users_preferred_language' => 'Preferred Language',
     'users_social_accounts' => 'Social Accounts',
     'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not previously authorized access. Revoke access from your profile settings on the connected social account.',
     'users_social_connect' => 'Connect Account',
     'users_social_disconnect' => 'Disconnect Account',
     'users_social_connected' => ':socialAccount account was successfully attached to your profile.',
     'users_social_disconnected' => ':socialAccount account was successfully disconnected from your profile.',
-];
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 
+    // Since these labels are already localized this array does not need to be
+    // translated in the language-specific files.
+    // DELETE BELOW IF COPIED FROM EN
+    ///////////////////////////////////
+    'language_select' => [
+        'en' => 'English',
+        'de' => 'Deutsch',
+        'fr' => 'Français',
+        'pt_BR' => 'Português do Brasil'
+    ]
+    ///////////////////////////////////
+];
diff --git a/resources/lang/fr/activities.php b/resources/lang/fr/activities.php
new file mode 100644 (file)
index 0000000..32f225d
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+
+return [
+
+    /**
+     * Activity text strings.
+     * Is used for all the text within activity logs & notifications.
+     */
+
+    // Pages
+    'page_create'                 => 'a créé la page',
+    'page_create_notification'    => 'Page créée avec succès',
+    'page_update'                 => 'a modifié la page',
+    'page_update_notification'    => 'Page modifiée avec succès',
+    'page_delete'                 => 'a supprimé la page',
+    'page_delete_notification'    => 'Page supprimée avec succès',
+    'page_restore'                => 'a restauré la page',
+    'page_restore_notification'   => 'Page réstaurée avec succès',
+    'page_move'                   => 'a déplacé la page',
+
+    // Chapters
+    'chapter_create'              => 'a créé le chapitre',
+    'chapter_create_notification' => 'Chapitre créé avec succès',
+    'chapter_update'              => 'a modifié le chapitre',
+    'chapter_update_notification' => 'Chapitre modifié avec succès',
+    'chapter_delete'              => 'a supprimé le chapitre',
+    'chapter_delete_notification' => 'Chapitre supprimé avec succès',
+    'chapter_move'                => 'a déplacé le chapitre',
+
+    // Books
+    'book_create'                 => 'a créé le livre',
+    'book_create_notification'    => 'Livre créé avec succès',
+    'book_update'                 => 'a modifié le livre',
+    'book_update_notification'    => 'Livre modifié avec succès',
+    'book_delete'                 => 'a supprimé le livre',
+    'book_delete_notification'    => 'Livre supprimé avec succès',
+    'book_sort'                   => 'a réordonné le livre',
+    'book_sort_notification'      => 'Livre réordonné avec succès',
+
+];
diff --git a/resources/lang/fr/auth.php b/resources/lang/fr/auth.php
new file mode 100644 (file)
index 0000000..41d051c
--- /dev/null
@@ -0,0 +1,74 @@
+<?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' => 'Ces informations ne correspondent a aucun compte.',
+    'throttle' => "Trop d'essais, veuillez réessayer dans :seconds secondes.",
+
+    /**
+     * Login & Register
+     */
+    'sign_up' => "S'inscrire",
+    'log_in' => 'Se connecter',
+    'logout' => 'Se déconnecter',
+
+    'name' => 'Nom',
+    'username' => "Nom d'utilisateur",
+    'email' => 'E-mail',
+    'password' => 'Mot de passe',
+    'password_confirm' => 'Confirmez le mot de passe',
+    'password_hint' => 'Doit faire plus de 5 caractères',
+    'forgot_password' => 'Mot de passe oublié?',
+    'remember_me' => 'Se souvenir de moi',
+    'ldap_email_hint' => "Merci d'entrer une adresse e-mail pour ce compte",
+    'create_account' => 'Créer un compte',
+    'social_login' => 'Social Login',
+    'social_registration' => 'Enregistrement Social',
+    'social_registration_text' => "S'inscrire et se connecter avec un réseau social",
+
+    'register_thanks' => 'Merci pour votre enregistrement',
+    'register_confirm' => 'Vérifiez vos e-mails et cliquer sur le lien de confirmation pour rejoindre :appName.',
+    'registrations_disabled' => "L'inscription est désactivée pour le moment",
+    'registration_email_domain_invalid' => 'Cette adresse e-mail ne peux pas adcéder Ã  l\'application',
+    'register_success' => 'Merci pour votre inscription. Vous Ãªtes maintenant inscrit(e) et connecté(e)',
+
+
+    /**
+     * Password Reset
+     */
+    'reset_password' => 'Reset Password',
+    'reset_password_send_instructions' => 'Entrez votre adresse e-mail ci-dessous et un e-mail avec un lien de réinitialisation de mot de passe vous sera envoyé',
+    'reset_password_send_button' => 'Envoyer un lien de réinitialisation',
+    'reset_password_sent_success' => 'Un lien de réinitialisation a Ã©té envoyé Ã  :email.',
+    'reset_password_success' => 'Votre mot de passe a Ã©té réinitialisé avec succès.',
+
+    'email_reset_subject' => 'Réinitialisez votre mot de passe pour :appName',
+    'email_reset_text' => 'Vous recevez cet e-mail parceque nous avons reçu une demande de réinitialisation pour votre compte',
+    'email_reset_not_requested' => 'Si vous n\'avez pas effectué cette demande, vous pouvez ignorer cet e-mail.',
+
+
+    /**
+     * Email Confirmation
+     */
+    'email_confirm_subject' => 'Confirmez votre adresse e-mail pour :appName',
+    'email_confirm_greeting' => 'Merci d\'avoir rejoint :appName!',
+    'email_confirm_text' => 'Merci de confirmer en cliquant sur le lien ci-dessous:',
+    'email_confirm_action' => 'Confirmez votre adresse e-mail',
+    'email_confirm_send_error' => 'La confirmation par e-mail est requise mais le système n\'a pas pu envoyer l\'e-mail. Contactez l\'administrateur système.',
+    'email_confirm_success' => 'Votre adresse e-mail a Ã©té confirmée!',
+    'email_confirm_resent' => 'L\'e-mail de confirmation a Ã©té ré-envoyé. Vérifiez votre boîte de récéption.',
+
+    'email_not_confirmed' => 'Adresse e-mail non confirmée',
+    'email_not_confirmed_text' => 'Votre adresse e-mail n\'a pas Ã©té confirmée.',
+    'email_not_confirmed_click_link' => 'Merci de cliquer sur le lien dans l\'e-mail qui vous a Ã©té envoyé après l\'enregistrement.',
+    'email_not_confirmed_resend' => 'Si vous ne retrouvez plus l\'e-mail, vous pouvez renvoyer un e-mail de confirmation en utilisant le formulaire ci-dessous.',
+    'email_not_confirmed_resend_button' => 'Renvoyez l\'e-mail de confirmation',
+];
diff --git a/resources/lang/fr/common.php b/resources/lang/fr/common.php
new file mode 100644 (file)
index 0000000..5eb4b8f
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+return [
+
+    /**
+     * Buttons
+     */
+    'cancel' => 'Annuler',
+    'confirm' => 'Confirmer',
+    'back' => 'Retour',
+    'save' => 'Enregistrer',
+    'continue' => 'Continuer',
+    'select' => 'Selectionner',
+
+    /**
+     * Form Labels
+     */
+    'name' => 'Nom',
+    'description' => 'Description',
+    'role' => 'Rôle',
+
+    /**
+     * Actions
+     */
+    'actions' => 'Actions',
+    'view' => 'Voir',
+    'create' => 'Créer',
+    'update' => 'Modifier',
+    'edit' => 'Editer',
+    'sort' => 'Trier',
+    'move' => 'Déplacer',
+    'delete' => 'Supprimer',
+    'search' => 'Chercher',
+    'search_clear' => 'Réinitialiser la recherche',
+    'reset' => 'Réinitialiser',
+    'remove' => 'Enlever',
+
+
+    /**
+     * Misc
+     */
+    'deleted_user' => 'Utilisateur supprimé',
+    'no_activity' => 'Aucune activité',
+    'no_items' => 'Aucun Ã©lément',
+    'back_to_top' => 'Retour en haut',
+    'toggle_details' => 'Afficher les détails',
+
+    /**
+     * Header
+     */
+    'view_profile' => 'Voir le profil',
+    'edit_profile' => 'Modifier le profil',
+
+    /**
+     * Email Content
+     */
+    'email_action_help' => 'Si vous rencontrez des problèmes pour cliquer le bouton ":actionText", copiez et collez l\'adresse ci-dessous dans votre navigateur:',
+    'email_rights' => 'Tous droits réservés',
+];
diff --git a/resources/lang/fr/components.php b/resources/lang/fr/components.php
new file mode 100644 (file)
index 0000000..7c9c4cf
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+return [
+
+    /**
+     * Image Manager
+     */
+    'image_select' => 'Selectionner une image',
+    'image_all' => 'Toutes',
+    'image_all_title' => 'Voir toutes les images',
+    'image_book_title' => 'Voir les images ajoutées Ã  ce livre',
+    'image_page_title' => 'Voir les images ajoutées Ã  cette page',
+    'image_search_hint' => 'Rechercher par nom d\'image',
+    'image_uploaded' => 'Ajoutée le :uploadedDate',
+    'image_load_more' => 'Charger plus',
+    'image_image_name' => 'Nom de l\'image',
+    'image_delete_confirm' => 'Cette image est utilisée dans les pages ci-dessous. Confirmez que vous souhaitez bien supprimer cette image.',
+    'image_select_image' => 'Selectionner l\'image',
+    'image_dropzone' => 'Glissez les images ici ou cliquez pour les ajouter',
+    'images_deleted' => 'Images supprimées',
+    'image_preview' => 'Prévisualiser l\'image',
+    'image_upload_success' => 'Image ajoutée avec succès',
+    'image_update_success' => 'Détails de l\'image mis Ã  jour',
+    'image_delete_success' => 'Image supprimée avec succès'
+];
diff --git a/resources/lang/fr/entities.php b/resources/lang/fr/entities.php
new file mode 100644 (file)
index 0000000..941259f
--- /dev/null
@@ -0,0 +1,225 @@
+<?php
+return [
+
+    /**
+     * Shared
+     */
+    'recently_created' => 'Créé récemment',
+    'recently_created_pages' => 'Pages créées récemment',
+    'recently_updated_pages' => 'Pages mises Ã  jour récemment',
+    'recently_created_chapters' => 'Chapitres créés récemment',
+    'recently_created_books' => 'Livres créés récemment',
+    'recently_update' => 'Mis Ã  jour récemment',
+    'recently_viewed' => 'Vus récemment',
+    'recent_activity' => 'Activité récente',
+    'create_now' => 'En créer un récemment',
+    'revisions' => 'Révisions',
+    'meta_created' => 'Créé :timeLength',
+    'meta_created_name' => 'Créé :timeLength par :user',
+    'meta_updated' => 'Mis Ã  jour :timeLength',
+    'meta_updated_name' => 'Mis Ã  jour :timeLength par :user',
+    'x_pages' => ':count pages',
+    'entity_select' => 'Sélectionner l\'entité',
+    'images' => 'Images',
+    'my_recent_drafts' => 'Mes brouillons récents',
+    'my_recently_viewed' => 'Vus récemment',
+    'no_pages_viewed' => 'Vous n\'avez rien visité récemment',
+    'no_pages_recently_created' => 'Aucune page créée récemment',
+    'no_pages_recently_updated' => 'Aucune page mise Ã  jour récemment',
+
+    /**
+     * Permissions and restrictions
+     */
+    'permissions' => 'Permissions',
+    'permissions_intro' => 'Une fois activées ces permission prendont la priorité sur tous les sets de permissions pré-existants.',
+    'permissions_enable' => 'Activer les permissions personnalisées',
+    'permissions_save' => 'Enregistrer les permissions',
+
+    /**
+     * Search
+     */
+    'search_results' => 'Résultats de recherche',
+    'search_results_page' => 'Résultats de recherche des pages',
+    'search_results_chapter' => 'Résultats de recherche des chapitres',
+    'search_results_book' => 'Résultats de recherche des livres',
+    'search_clear' => 'Réinitialiser la recherche',
+    'search_view_pages' => 'Voir toutes les pages correspondantes',
+    'search_view_chapters' => 'Voir tous les chapitres correspondants',
+    'search_view_books' => 'Voir tous les livres correspondants',
+    'search_no_pages' => 'Aucune page correspondant Ã  cette recherche',
+    'search_for_term' => 'recherche pour :term',
+    'search_page_for_term' => 'Recherche de page pour :term',
+    'search_chapter_for_term' => 'Recherche de chapitre pour :term',
+    'search_book_for_term' => 'Recherche de livres pour :term',
+
+    /**
+     * Books
+     */
+    'book' => 'Livre',
+    'books' => 'Livres',
+    'books_empty' => 'Aucun livre n\'a Ã©té créé',
+    'books_popular' => 'Livres populaires',
+    'books_recent' => 'Livres récents',
+    'books_popular_empty' => 'Les livres les plus populaires apparaîtront ici.',
+    'books_create' => 'Créer un nouveau livre',
+    'books_delete' => 'Supprimer un livre',
+    'books_delete_named' => 'Supprimer le livre :bookName',
+    'books_delete_explain' => 'Ceci va supprimer le livre nommé \':bookName\', Tous les chapitres et pages seront supprimés.',
+    'books_delete_confirmation' => 'Êtes-vous sûr(e) de vouloir supprimer ce livre?',
+    'books_edit' => 'Modifier le livre',
+    'books_edit_named' => 'Modifier le livre :bookName',
+    'books_form_book_name' => 'Nom du livre',
+    'books_save' => 'Enregistrer le livre',
+    'books_permissions' => 'Permissions du livre',
+    'books_permissions_updated' => 'Permissions du livre mises Ã  jour',
+    'books_empty_contents' => 'Aucune page ou chapitre n\'a Ã©té ajouté Ã  ce livre.',
+    'books_empty_create_page' => 'Créer une nouvelle page',
+    'books_empty_or' => 'ou',
+    'books_empty_sort_current_book' => 'Trier les pages du livre',
+    'books_empty_add_chapter' => 'Ajouter un chapitre',
+    'books_permissions_active' => 'Permissions personnalisées activées',
+    'books_search_this' => 'Chercher dans le livre',
+    'books_navigation' => 'Navigation dans le livre',
+    'books_sort' => 'Trier les contenus du livre',
+    'books_sort_named' => 'Trier le livre :bookName',
+    'books_sort_show_other' => 'Afficher d\'autres livres',
+    'books_sort_save' => 'Enregistrer l\'ordre',
+
+    /**
+     * Chapters
+     */
+    'chapter' => 'Chapitre',
+    'chapters' => 'Chapitres',
+    'chapters_popular' => 'Chapitres populaires',
+    'chapters_new' => 'Nouveau chapitre',
+    'chapters_create' => 'Créer un nouveau chapitre',
+    'chapters_delete' => 'Supprimer le chapitre',
+    'chapters_delete_named' => 'Supprimer le chapitre :chapterName',
+    'chapters_delete_explain' => 'Ceci va supprimer le chapitre \':chapterName\', Toutes les pages seront déplacée dans le livre parent.',
+    'chapters_delete_confirm' => 'Etes-vous sûr(e) de vouloir supprimer ce chapitre?',
+    'chapters_edit' => 'Modifier le chapitre',
+    'chapters_edit_named' => 'Modifier le chapitre :chapterName',
+    'chapters_save' => 'Enregistrer le chapitre',
+    'chapters_move' => 'Déplace le chapitre',
+    'chapters_move_named' => 'Déplacer le chapitre :chapterName',
+    'chapter_move_success' => 'Chapitre déplacé dans :bookName',
+    'chapters_permissions' => 'Permissions du chapitre',
+    'chapters_empty' => 'Il n\'y a pas de pages dans ce chapitre actuellement.',
+    'chapters_permissions_active' => 'Permissions du chapitre activées',
+    'chapters_permissions_success' => 'Permissions du chapitres mises Ã  jour',
+
+    /**
+     * Pages
+     */
+    'page' => 'Page',
+    'pages' => 'Pages',
+    'pages_popular' => 'Pages populaires',
+    'pages_new' => 'Nouvelle page',
+    'pages_attachments' => 'Fichiers joints',
+    'pages_navigation' => 'Navigation des pages',
+    'pages_delete' => 'Supprimer la page',
+    'pages_delete_named' => 'Supprimer la page :pageName',
+    'pages_delete_draft_named' => 'supprimer le brouillon de la page :pageName',
+    'pages_delete_draft' => 'Supprimer le brouillon',
+    'pages_delete_success' => 'Page supprimée',
+    'pages_delete_draft_success' => 'Brouillon supprimé',
+    'pages_delete_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer cette page?',
+    'pages_delete_draft_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer ce brouillon?',
+    'pages_editing_named' => 'Modification de la page :pageName',
+    'pages_edit_toggle_header' => 'Afficher/cacher l\'en-tête',
+    'pages_edit_save_draft' => 'Enregistrer le brouillon',
+    'pages_edit_draft' => 'Modifier le brouillon',
+    'pages_editing_draft' => 'Modification du brouillon',
+    'pages_editing_page' => 'Modification de la page',
+    'pages_edit_draft_save_at' => 'Brouillon sauvé le ',
+    'pages_edit_delete_draft' => 'Supprimer le brouillon',
+    'pages_edit_discard_draft' => 'Ecarter le brouillon',
+    'pages_edit_set_changelog' => 'Remplir le journal des changements',
+    'pages_edit_enter_changelog_desc' => 'Entrez une brève description des changements effectués',
+    'pages_edit_enter_changelog' => 'Entrez dans le journal des changements',
+    'pages_save' => 'Enregistrez la page',
+    'pages_title' => 'Titre de la page',
+    'pages_name' => 'Nom de la page',
+    'pages_md_editor' => 'Editeur',
+    'pages_md_preview' => 'Prévisualisation',
+    'pages_md_insert_image' => 'Insérer une image',
+    'pages_md_insert_link' => 'Insérer un lien',
+    'pages_not_in_chapter' => 'La page n\'est pas dans un chanpitre',
+    'pages_move' => 'Déplacer la page',
+    'pages_move_success' => 'Page déplacée Ã  ":parentName"',
+    'pages_permissions' => 'Permissions de la page',
+    'pages_permissions_success' => 'Permissions de la page mises Ã  jour',
+    'pages_revisions' => 'Révisions de la page',
+    'pages_revisions_named' => 'Révisions pour :pageName',
+    'pages_revision_named' => 'Révision pour :pageName',
+    'pages_revisions_created_by' => 'Créé par',
+    'pages_revisions_date' => 'Date de révision',
+    'pages_revisions_changelog' => 'Journal des changements',
+    'pages_revisions_changes' => 'Changements',
+    'pages_revisions_current' => 'Version courante',
+    'pages_revisions_preview' => 'Prévisualisation',
+    'pages_revisions_restore' => 'Restaurer',
+    'pages_revisions_none' => 'Cette page n\'a aucune révision',
+    'pages_export' => 'Exporter',
+    'pages_export_html' => 'Fichiers web',
+    'pages_export_pdf' => 'Fichier PDF',
+    'pages_export_text' => 'Document texte',
+    'pages_copy_link' => 'Copier le lien',
+    'pages_permissions_active' => 'Permissions de page actives',
+    'pages_initial_revision' => 'Publication initiale',
+    'pages_initial_name' => 'Nouvelle page',
+    'pages_editing_draft_notification' => 'Vous Ã©ditez actuellement un brouillon qui a Ã©té sauvé :timeDiff.',
+    'pages_draft_edited_notification' => 'La page a Ã©té mise Ã  jour depuis votre dernière visit. Vous devriez Ã©carter ce brouillon.',
+    'pages_draft_edit_active' => [
+        'start_a' => ':count utilisateurs ont commencé a Ã©diter cette page',
+        'start_b' => ':userName a commencé Ã  Ã©diter cette page',
+        'time_a' => 'depuis la dernière sauvegarde',
+        'time_b' => 'dans les :minCount dernières minutes',
+        'message' => ':start :time. Attention a ne pas Ã©craser les mises Ã  jour de quelqu\'un d\'autre!',
+    ],
+    'pages_draft_discarded' => 'Brouuillon Ã©carté, la page est dans sa version actuelle.',
+
+    /**
+     * Editor sidebar
+     */
+    'page_tags' => 'Mots-clés de la page',
+    'tag' => 'Mot-clé',
+    'tags' =>  'Mots-clé',
+    'tag_value' => 'Valeur du mot-clé (Optionnel)',
+    'tags_explain' => "Ajouter des mot-clés pour catégoriser votre contenu.",
+    'tags_add' => 'Ajouter un autre mot-clé',
+    'attachments' => 'Fichiers joints',
+    'attachments_explain' => 'Ajouter des fichiers ou des liens pour les afficher sur votre page. Ils seront affichés dans la barre latérale',
+    'attachments_explain_instant_save' => 'Ces changements sont enregistrés immédiatement.',
+    'attachments_items' => 'Fichiers joints',
+    'attachments_upload' => 'Uploader un fichier',
+    'attachments_link' => 'Attacher un lien',
+    'attachments_set_link' => 'Définir un lien',
+    'attachments_delete_confirm' => 'Cliquer une seconde fois sur supprimer pour valider la suppression.',
+    'attachments_dropzone' => 'Glissez des fichiers ou cliquez ici pour attacher des fichiers',
+    'attachments_no_files' => 'Aucun fichier ajouté',
+    'attachments_explain_link' => 'Vous pouvez attacher un lien si vous ne souhaitez pas uploader un fichier.',
+    'attachments_link_name' => 'Nom du lien',
+    'attachment_link' => 'Lien de l\'attachement',
+    'attachments_link_url' => 'Lien sur un fichier',
+    'attachments_link_url_hint' => 'URL du site ou du fichier',
+    'attach' => 'Attacher',
+    'attachments_edit_file' => 'Modifier le fichier',
+    'attachments_edit_file_name' => 'Nom du fichier',
+    'attachments_edit_drop_upload' => 'Glissez un fichier ou cliquer pour mettre Ã  jour le fichier',
+    'attachments_order_updated' => 'Ordre des fichiers joints mis Ã  jour',
+    'attachments_updated_success' => 'Détails des fichiers joints mis Ã  jour',
+    'attachments_deleted' => 'Fichier joint supprimé',
+    'attachments_file_uploaded' => 'Fichier ajouté avec succès',
+    'attachments_file_updated' => 'Fichier mis Ã  jour avec succès',
+    'attachments_link_attached' => 'Lien attaché Ã  la page avec succès',
+
+    /**
+     * Profile View
+     */
+    'profile_user_for_x' => 'Utilisateur depuis :time',
+    'profile_created_content' => 'Contenu créé',
+    'profile_not_created_pages' => ':userName n\'a pas créé de pages',
+    'profile_not_created_chapters' => ':userName n\'a pas créé de chapitres',
+    'profile_not_created_books' => ':userName n\'a pas créé de livres',
+];
diff --git a/resources/lang/fr/errors.php b/resources/lang/fr/errors.php
new file mode 100644 (file)
index 0000000..72af89f
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+
+return [
+
+    /**
+     * Error text strings.
+     */
+
+    // Permissions
+    'permission' => 'Vous n\'avez pas les droits pour accéder Ã  cette page.',
+    'permissionJson' => 'Vous n\'avez pas les droits pour exécuter cette action.',
+
+    // Auth
+    'error_user_exists_different_creds' => 'Un utilisateur avec l\'adresse :email existe déjà.',
+    'email_already_confirmed' => 'Cet e-mail a déjà Ã©té validé, vous pouvez vous connecter.',
+    'email_confirmation_invalid' => 'Cette confirmation est invalide. Veuillez essayer de vous inscrire Ã  nouveau.',
+    'email_confirmation_expired' => 'Le jeton de confirmation est perimé. Un nouvel e-mail vous a Ã©té envoyé.',
+    'ldap_fail_anonymous' => 'L\'accès LDAP anonyme n\'a pas abouti',
+    'ldap_fail_authed' => 'L\'accès LDAP n\'a pas abouti avec cet utilisateur et ce mot de passe',
+    'ldap_extension_not_installed' => 'L\'extention LDAP PHP n\'est pas installée',
+    'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed',
+    'social_no_action_defined' => 'No action defined',
+    'social_account_in_use' => 'Cet compte :socialAccount est déjà utilisé. Essayez de vous connecter via :socialAccount.',
+    'social_account_email_in_use' => 'L\'email :email Est déjà utilisé. Si vous avez déjà un compte :socialAccount, vous pouvez le joindre Ã  votre profil existant.',
+    'social_account_existing' => 'Ce compte :socialAccount est déjà rattaché Ã  votre profil.',
+    'social_account_already_used_existing' => 'Ce compte :socialAccount est déjà utilisé par un autre utilisateur.',
+    'social_account_not_used' => 'Ce compte :socialAccount n\'est lié Ã  aucun utilisateur. ',
+    'social_account_register_instructions' => 'Si vous n\'avez pas encore de compte, vous pouvez le lier avec l\'option :socialAccount.',
+    'social_driver_not_found' => 'Social driver not found',
+    'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.',
+
+    // System
+    'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.',
+    'cannot_get_image_from_url' => 'Impossible de récupérer l\'image depuis :url',
+    'cannot_create_thumbs' => 'Le serveur ne peux pas créer de miniatures, vérifier que l\extensions GD PHP est installée.',
+    'server_upload_limit' => 'La taille du fichier est trop grande.',
+    'image_upload_error' => 'Une erreur est survenue pendant l\'envoi de l\'image',
+
+    // Attachments
+    'attachment_page_mismatch' => 'Page mismatch during attachment update',
+
+    // Pages
+    'page_draft_autosave_fail' => 'Le brouillon n\'a pas pu Ãªtre sauvé. Vérifiez votre connexion internet',
+
+    // Entities
+    'entity_not_found' => 'Entité non trouvée',
+    'book_not_found' => 'Livre non trouvé',
+    'page_not_found' => 'Page non trouvée',
+    'chapter_not_found' => 'Chapitre non trouvé',
+    'selected_book_not_found' => 'Ce livre n\'a pas Ã©té trouvé',
+    'selected_book_chapter_not_found' => 'Ce livre ou chapitre n\'a pas Ã©té trouvé',
+    'guests_cannot_save_drafts' => 'Les invités ne peuvent pas sauver de brouillons',
+
+    // Users
+    'users_cannot_delete_only_admin' => 'Vous ne pouvez pas supprimer le dernier admin',
+    'users_cannot_delete_guest' => 'Vous ne pouvez pas supprimer l\'utilisateur invité',
+
+    // Roles
+    'role_cannot_be_edited' => 'Ce rôle ne peut pas Ãªtre modifié',
+    'role_system_cannot_be_deleted' => 'Ceci est un rôle du système et on ne peut pas le supprimer',
+    'role_registration_default_cannot_delete' => 'Ce rôle ne peut pas Ãªtre supprimé tant qu\'il est le rôle par défaut',
+
+    // Error pages
+    '404_page_not_found' => 'Page non trouvée',
+    'sorry_page_not_found' => 'Désolé, cette page n\'a pas pu Ãªtre trouvée.',
+    'return_home' => 'Retour Ã  l\'accueil',
+    'error_occurred' => 'Une erreur est survenue',
+    'app_down' => ':appName n\'est pas en service pour le moment',
+    'back_soon' => 'Nous serons bientôt de retour.',
+];
diff --git a/resources/lang/fr/pagination.php b/resources/lang/fr/pagination.php
new file mode 100644 (file)
index 0000000..9f07a5f
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+
+return [
+
+    /*
+    |--------------------------------------------------------------------------
+    | Pagination Language Lines
+    |--------------------------------------------------------------------------
+    |
+    | The following language lines are used by the paginator library to build
+    | the simple pagination links. You are free to change them to anything
+    | you want to customize your views to better match your application.
+    |
+    */
+
+    'previous' => '&laquo; Précédent',
+    'next'     => 'Suivant &raquo;',
+
+];
diff --git a/resources/lang/fr/passwords.php b/resources/lang/fr/passwords.php
new file mode 100644 (file)
index 0000000..7be81da
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+
+return [
+
+    /*
+    |--------------------------------------------------------------------------
+    | Password Reminder Language Lines
+    |--------------------------------------------------------------------------
+    |
+    | The following language lines are the default lines which match reasons
+    | that are given by the password broker for a password update attempt
+    | has failed, such as for an invalid token or invalid new password.
+    |
+    */
+
+    'password' => 'Les mots de passe doivent faire au moins 6 caractères et correspondre Ã  la confirmation.',
+    'user' => "Nous n'avons pas trouvé d'utilisateur avec cette adresse.",
+    'token' => 'Le jeton de réinitialisation est invalide.',
+    'sent' => 'Nous vous avons envoyé un lien de réinitialisation de mot de passe!',
+    'reset' => 'Votre mot de passe a Ã©té réinitialisé!',
+
+];
diff --git a/resources/lang/fr/settings.php b/resources/lang/fr/settings.php
new file mode 100644 (file)
index 0000000..8a37565
--- /dev/null
@@ -0,0 +1,112 @@
+<?php
+
+return [
+
+    /**
+     * Settings text strings
+     * Contains all text strings used in the general settings sections of BookStack
+     * including users and roles.
+     */
+
+    'settings' => 'Préférences',
+    'settings_save' => 'Enregistrer les préférences',
+    'settings_save_success' => 'Préférences enregistrées',
+
+    /**
+     * App settings
+     */
+
+    'app_settings' => 'Préférences de l\'application',
+    'app_name' => 'Nom de l\'application',
+    'app_name_desc' => 'Ce nom est affiché dans l\'en-tête et les e-mails.',
+    'app_name_header' => 'Afficher le nom dans l\'en-tête?',
+    'app_public_viewing' => 'Accepter le visionnage public des pages?',
+    'app_secure_images' => 'Activer l\'ajout d\'image sécurisé?',
+    'app_secure_images_desc' => 'Pour des questions de performances, toutes les images sont publiques. Cette option ajoute une chaîne aléatoire difficile Ã  deviner dans les URLs des images.',
+    'app_editor' => 'Editeur des pages',
+    'app_editor_desc' => 'Sélectionnez l\'éditeur qui sera utilisé pour modifier les pages.',
+    'app_custom_html' => 'HTML personnalisé dans l\'en-tête',
+    'app_custom_html_desc' => 'Le contenu inséré ici sera jouté en bas de la balise <head> de toutes les pages. Vous pouvez l\'utiliser pour ajouter du CSS personnalisé ou un tracker analytique.',
+    'app_logo' => 'Logo de l\'Application',
+    'app_logo_desc' => 'Cette image doit faire 43px de hauteur. <br>Les images plus larges seront réduites.',
+    'app_primary_color' => 'Couleur principale de l\'application',
+    'app_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.',
+
+    /**
+     * Registration settings
+     */
+
+    'reg_settings' => 'Préférence pour l\'inscription',
+    'reg_allow' => 'Accepter l\'inscription?',
+    'reg_default_role' => 'Rôle par défaut lors de l\'inscription',
+    'reg_confirm_email' => 'Obliger la confirmation par e-mail?',
+    'reg_confirm_email_desc' => 'Si la restriction de domaine est activée, la confirmation sera automatiquement obligatoire et cette valeur sera ignorée.',
+    'reg_confirm_restrict_domain' => 'Restreindre l\'inscription Ã  un domaine',
+    'reg_confirm_restrict_domain_desc' => 'Entrez une liste de domaines acceptés lors de l\'inscription, séparés par une virgule. Les utilisateur recevront un e-mail de confirmation Ã  cette adresse. <br> Les utilisateurs pourront changer leur adresse après inscription s\'ils le souhaitent.',
+    'reg_confirm_restrict_domain_placeholder' => 'Aucune restriction en place',
+
+    /**
+     * Role settings
+     */
+
+    'roles' => 'Rôles',
+    'role_user_roles' => 'Rôles des utilisateurs',
+    'role_create' => 'Créer un nouveau rôle',
+    'role_create_success' => 'Rôle créé avec succès',
+    'role_delete' => 'Supprimer le rôle',
+    'role_delete_confirm' => 'Ceci va supprimer le rôle \':roleName\'.',
+    'role_delete_users_assigned' => 'Ce rôle a :userCount utilisateurs assignés. Vous pouvez choisir un rôle de remplacement pour ces utilisateurs.',
+    'role_delete_no_migration' => "Ne pas assigner de nouveau rôle",
+    'role_delete_sure' => 'Êtes vous sûr(e) de vouloir supprimer ce rôle?',
+    'role_delete_success' => 'Le rôle a Ã©té supprimé avec succès',
+    'role_edit' => 'Modifier le rôle',
+    'role_details' => 'Détails du rôle',
+    'role_name' => 'Nom du Rôle',
+    'role_desc' => 'Courte description du rôle',
+    'role_system' => 'Permissions système',
+    'role_manage_users' => 'Gérer les utilisateurs',
+    'role_manage_roles' => 'Gérer les rôles et permissions',
+    'role_manage_entity_permissions' => 'Gérer les permissions sur les livres, chapitres et pages',
+    'role_manage_own_entity_permissions' => 'Gérer les permissions de ses propres livres chapitres et pages',
+    'role_manage_settings' => 'Gérer les préférences de l\'application',
+    'role_asset' => 'Asset Permissions',
+    'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.',
+    'role_all' => 'Tous',
+    'role_own' => 'Propres',
+    'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to',
+    'role_save' => 'Enregistrer le rôle',
+    'role_update_success' => 'Rôle mis Ã  jour avec succès',
+    'role_users' => 'Utilisateurs ayant ce rôle',
+    'role_users_none' => 'Aucun utilisateur avec ce rôle actuellement',
+
+    /**
+     * Users
+     */
+
+    'users' => 'Utilisateurs',
+    'user_profile' => 'Profil d\'utilisateur',
+    'users_add_new' => 'Ajouter un nouvel utilisateur',
+    'users_search' => 'Chercher les utilisateurs',
+    'users_role' => 'Rôles des utilisateurs',
+    'users_external_auth_id' => 'Identifiant d\'authentification externe',
+    'users_password_warning' => 'Remplissez ce fomulaire uniquement si vous souhaitez changer de mot de passe:',
+    'users_system_public' => 'Cet utilisateur représente les invités visitant votre instance. Il est assigné automatiquement aux invités.',
+    'users_delete' => 'Supprimer un utilisateur',
+    'users_delete_named' => 'Supprimer l\'utilisateur :userName',
+    'users_delete_warning' => 'Ceci va supprimer \':userName\' du système.',
+    'users_delete_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer cet utilisateur?',
+    'users_delete_success' => 'Utilisateurs supprimés avec succès',
+    'users_edit' => 'Modifier l\'utilisateur',
+    'users_edit_profile' => 'Modifier le profil',
+    'users_edit_success' => 'Utilisateur mis Ã  jour avec succès',
+    'users_avatar' => 'Avatar de l\'utilisateur',
+    'users_avatar_desc' => 'Cette image doit Ãªtre un carré d\'environ 256px.',
+    'users_preferred_language' => 'Langue préférée',
+    'users_social_accounts' => 'Comptes sociaux',
+    'users_social_accounts_info' => 'Vous pouvez connecter des réseaux sociaux Ã  votre compte pour vous connecter plus rapidement. Déconnecter un compte n\'enlèvera pas les accès autorisés précédemment sur votre compte de réseau social.',
+    'users_social_connect' => 'Connecter le compte',
+    'users_social_disconnect' => 'Déconnecter le compte',
+    'users_social_connected' => 'Votre compte :socialAccount a Ã©lté ajouté avec succès.',
+    'users_social_disconnected' => 'Votre compte :socialAccount a Ã©té déconnecté avec succès',
+
+];
diff --git a/resources/lang/fr/validation.php b/resources/lang/fr/validation.php
new file mode 100644 (file)
index 0000000..9204f4e
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+
+return [
+
+    /*
+    |--------------------------------------------------------------------------
+    | Validation Language Lines
+    |--------------------------------------------------------------------------
+    |
+    | The following language lines contain the default error messages used by
+    | the validator class. Some of these rules have multiple versions such
+    | as the size rules. Feel free to tweak each of these messages here.
+    |
+    */
+
+    'accepted'             => ':attribute doit Ãªtre accepté.',
+    'active_url'           => ':attribute n\'est pas une URL valide.',
+    'after'                => ':attribute doit Ãªtre supérieur Ã  :date.',
+    'alpha'                => ':attribute ne doit contenir que des lettres.',
+    'alpha_dash'           => ':attribute doit contenir uniquement des lettres, chiffres et traits d\'union.',
+    'alpha_num'            => ':attribute doit contenir uniquement des chiffres et des lettres.',
+    'array'                => ':attribute doit Ãªtre un tableau.',
+    'before'               => ':attribute doit Ãªtre inférieur Ã  :date.',
+    'between'              => [
+        'numeric' => ':attribute doit Ãªtre compris entre :min et :max.',
+        'file'    => ':attribute doit Ãªtre compris entre :min et :max kilobytes.',
+        'string'  => ':attribute doit Ãªtre compris entre :min et :max caractères.',
+        'array'   => ':attribute doit Ãªtre compris entre :min et :max Ã©léments.',
+    ],
+    'boolean'              => ':attribute doit Ãªtre vrai ou faux.',
+    'confirmed'            => ':attribute la confirmation n\'est pas valide.',
+    'date'                 => ':attribute n\'est pas une date valide.',
+    'date_format'          => ':attribute ne correspond pas au format :format.',
+    'different'            => ':attribute et :other doivent Ãªtre différents l\'un de l\'autre.',
+    'digits'               => ':attribute doit Ãªtre de longueur :digits.',
+    'digits_between'       => ':attribute doit avoir une longueur entre :min et :max.',
+    'email'                => ':attribute doit Ãªtre une adresse e-mail valide.',
+    'filled'               => ':attribute est un champ requis.',
+    'exists'               => 'L\'attribut :attribute est invalide.',
+    'image'                => ':attribute doit Ãªtre une image.',
+    'in'                   => 'L\'attribut :attribute est invalide.',
+    'integer'              => ':attribute doit Ãªtre un chiffre entier.',
+    'ip'                   => ':attribute doit Ãªtre une adresse IP valide.',
+    'max'                  => [
+        'numeric' => ':attribute ne doit pas excéder :max.',
+        'file'    => ':attribute ne doit pas excéder :max kilobytes.',
+        'string'  => ':attribute ne doit pas excéder :max caractères.',
+        'array'   => ':attribute ne doit pas contenir plus de :max Ã©léments.',
+    ],
+    'mimes'                => ':attribute doit Ãªtre un fichier de type :values.',
+    'min'                  => [
+        'numeric' => ':attribute doit Ãªtre au moins :min.',
+        'file'    => ':attribute doit faire au moins :min kilobytes.',
+        'string'  => ':attribute doit contenir au moins :min caractères.',
+        'array'   => ':attribute doit contenir au moins :min Ã©léments.',
+    ],
+    'not_in'               => 'L\'attribut sélectionné :attribute est invalide.',
+    'numeric'              => ':attribute doit Ãªtre un nombre.',
+    'regex'                => ':attribute a un format invalide.',
+    'required'             => ':attribute est un champ requis.',
+    'required_if'          => ':attribute est requis si :other est :value.',
+    'required_with'        => ':attribute est requis si :values est présent.',
+    'required_with_all'    => ':attribute est requis si :values est présent.',
+    'required_without'     => ':attribute est requis si:values n\'est pas présent.',
+    'required_without_all' => ':attribute est requis si aucun des valeurs :values n\'est présente.',
+    'same'                 => ':attribute et :other doivent Ãªtre identiques.',
+    'size'                 => [
+        'numeric' => ':attribute doit avoir la taille :size.',
+        'file'    => ':attribute doit peser :size kilobytes.',
+        'string'  => ':attribute doit contenir :size caractères.',
+        'array'   => ':attribute doit contenir :size Ã©léments.',
+    ],
+    'string'               => ':attribute doit Ãªtre une chaîne de caractères.',
+    'timezone'             => ':attribute doit Ãªtre une zone valide.',
+    'unique'               => ':attribute est déjà utilisé.',
+    'url'                  => ':attribute a un format invalide.',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Custom Validation Language Lines
+    |--------------------------------------------------------------------------
+    |
+    | Here you may specify custom validation messages for attributes using the
+    | convention "attribute.rule" to name the lines. This makes it quick to
+    | specify a specific custom language line for a given attribute rule.
+    |
+    */
+
+    'custom' => [
+        'password-confirm' => [
+            'required_with' => 'La confirmation du mot de passe est requise',
+        ],
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Custom Validation Attributes
+    |--------------------------------------------------------------------------
+    |
+    | The following language lines are used to swap attribute place-holders
+    | with something more reader friendly such as E-Mail Address instead
+    | of "email". This simply helps us make messages a little cleaner.
+    |
+    */
+
+    'attributes' => [],
+
+];
diff --git a/resources/lang/pt_BR/activities.php b/resources/lang/pt_BR/activities.php
new file mode 100644 (file)
index 0000000..1f5bc35
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+
+return [
+
+    /**
+     * Activity text strings.
+     * Is used for all the text within activity logs & notifications.
+     */
+
+    // Pages
+    'page_create'                 => 'página criada',
+    'page_create_notification'    => 'Página criada com sucesso',
+    'page_update'                 => 'página atualizada',
+    'page_update_notification'    => 'Página atualizada com sucesso',
+    'page_delete'                 => 'página excluída',
+    'page_delete_notification'    => 'Página excluída com sucesso',
+    'page_restore'                => 'página restaurada',
+    'page_restore_notification'   => 'Página restaurada com sucesso',
+    'page_move'                   => 'página movida',
+
+    // Chapters
+    'chapter_create'              => 'capítulo criado',
+    'chapter_create_notification' => 'Capítulo criado com sucesso',
+    'chapter_update'              => 'capítulo atualizado',
+    'chapter_update_notification' => 'capítulo atualizado com sucesso',
+    'chapter_delete'              => 'capítulo excluído',
+    'chapter_delete_notification' => 'Capítulo excluído com sucesso',
+    'chapter_move'                => 'capitulo movido',
+
+    // Books
+    'book_create'                 => 'livro criado',
+    'book_create_notification'    => 'Livro criado com sucesso',
+    'book_update'                 => 'livro atualizado',
+    'book_update_notification'    => 'Livro atualizado com sucesso',
+    'book_delete'                 => 'livro excluído',
+    'book_delete_notification'    => 'Livro excluído com sucesso',
+    'book_sort'                   => 'livro classificado',
+    'book_sort_notification'      => 'Livro reclassificado com sucesso',
+];
diff --git a/resources/lang/pt_BR/auth.php b/resources/lang/pt_BR/auth.php
new file mode 100644 (file)
index 0000000..ec3b92d
--- /dev/null
@@ -0,0 +1,74 @@
+<?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' => 'As credenciais fornecidas não puderam ser validadas em nossos registros..',
+    'throttle' => 'Muitas tentativas de login. Por favor, tente novamente em :seconds segundos.',
+
+    /**
+     * Login & Register
+     */
+    'sign_up' => 'Registrar-se',
+    'log_in' => 'Entrar',
+    'logout' => 'Sair',
+
+    'name' => 'Nome',
+    'username' => 'Nome de Usuário',
+    'email' => 'E-mail',
+    'password' => 'Senha',
+    'password_confirm' => 'Confirmar Senha',
+    'password_hint' => 'Senha deverá ser maior que 5 caracteres',
+    'forgot_password' => 'Esqueceu a senha?',
+    'remember_me' => 'Lembrar de mim',
+    'ldap_email_hint' => 'Por favor, digite um e-mail para essa conta.',
+    'create_account' => 'Criar conta',
+    'social_login' => 'Login social',
+    'social_registration' => 'Registro social',
+    'social_registration_text' => 'Registre e entre usando outro serviço.',
+
+    'register_thanks' => 'Obrigado por efetuar o registro!',
+    'register_confirm' => 'Por favor, verifique seu e-mail e clique no botão de confirmação para acessar :appName.',
+    'registrations_disabled' => 'Registros estão temporariamente desabilitados',
+    'registration_email_domain_invalid' => 'O domínio de e-mail usado não tem acesso permitido a essa aplicação',
+    'register_success' => 'Obrigado por se registrar! Você agora encontra-se registrado e logado..',
+
+
+    /**
+     * Password Reset
+     */
+    'reset_password' => 'Resetar senha',
+    'reset_password_send_instructions' => 'Digite seu e-mail abaixo e o sistema enviará uma mensagem com o link de reset de senha.',
+    'reset_password_send_button' => 'Enviar o link de reset de senha',
+    'reset_password_sent_success' => 'Um link de reset de senha foi enviado para :email.',
+    'reset_password_success' => 'Sua senha foi resetada com sucesso.',
+
+    'email_reset_subject' => 'Resetar a senha de :appName',
+    'email_reset_text' => 'Você recebeu esse e-mail pois recebemos uma solicitação de reset de senha para sua conta.',
+    'email_reset_not_requested' => 'Caso não tenha sido você a solicitar o reset de senha, ignore esse e-mail.',
+
+
+    /**
+     * Email Confirmation
+     */
+    'email_confirm_subject' => 'Confirme seu e-mail para :appName',
+    'email_confirm_greeting' => 'Obrigado por se registrar em :appName!',
+    'email_confirm_text' => 'Por favor, confirme seu endereço de e-mail clicando no botão abaixo:',
+    'email_confirm_action' => 'Confirmar E-mail',
+    'email_confirm_send_error' => 'E-mail de confirmação Ã© requerido, mas o sistema não pôde enviar a mensagem. Por favor, entre em contato com o admin para se certificar que o serviço de envio de e-mails está corretamente configurado.',
+    'email_confirm_success' => 'Seu e-mail foi confirmado!',
+    'email_confirm_resent' => 'E-mail de confirmação reenviado. Por favor, cheque sua caixa postal.',
+
+    'email_not_confirmed' => 'Endereço de e-mail não foi confirmado',
+    'email_not_confirmed_text' => 'Seu endereço de e-mail ainda não foi confirmado.',
+    'email_not_confirmed_click_link' => 'Por favor, clique no link no e-mail que foi enviado após o registro.',
+    'email_not_confirmed_resend' => 'Caso não encontre o e-mail você poderá reenviar a confirmação usando o formulário abaixo.',
+    'email_not_confirmed_resend_button' => 'Reenviar o e-mail de confirmação',
+];
\ No newline at end of file
diff --git a/resources/lang/pt_BR/common.php b/resources/lang/pt_BR/common.php
new file mode 100644 (file)
index 0000000..820ba21
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+return [
+
+    /**
+     * Buttons
+     */
+    'cancel' => 'Cancelar',
+    'confirm' => 'Confirmar',
+    'back' => 'Voltar',
+    'save' => 'Salvar',
+    'continue' => 'Continuar',
+    'select' => 'Selecionar',
+
+    /**
+     * Form Labels
+     */
+    'name' => 'Nome',
+    'description' => 'Descrição',
+    'role' => 'Regra',
+
+    /**
+     * Actions
+     */
+    'actions' => 'Ações',
+    'view' => 'Visualizar',
+    'create' => 'Criar',
+    'update' => 'Atualizar',
+    'edit' => 'Editar',
+    'sort' => 'Ordenar',
+    'move' => 'Mover',
+    'delete' => 'Excluir',
+    'search' => 'Pesquisar',
+    'search_clear' => 'Limpar Pesquisa',
+    'reset' => 'Resetar',
+    'remove' => 'Remover',
+
+
+    /**
+     * Misc
+     */
+    'deleted_user' => 'Usuário excluído',
+    'no_activity' => 'Nenhuma atividade a mostrar',
+    'no_items' => 'Nenhum item disponível',
+    'back_to_top' => 'Voltar ao topo',
+    'toggle_details' => 'Alternar Detalhes',
+
+    /**
+     * Header
+     */
+    'view_profile' => 'Visualizar Perfil',
+    'edit_profile' => 'Editar Perfil',
+
+    /**
+     * Email Content
+     */
+    'email_action_help' => 'Se você estiver tendo problemas ao clicar o botão ":actionText", copie e cole a URL abaixo no seu navegador:',
+    'email_rights' => 'Todos os direitos reservados',
+];
\ No newline at end of file
diff --git a/resources/lang/pt_BR/components.php b/resources/lang/pt_BR/components.php
new file mode 100644 (file)
index 0000000..5c1ec42
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+return [
+
+    /**
+     * Image Manager
+     */
+    'image_select' => 'Selecionar imagem',
+    'image_all' => 'Todos',
+    'image_all_title' => 'Visualizar todas as imagens',
+    'image_book_title' => 'Visualizar imagens relacionadas a esse livro',
+    'image_page_title' => 'visualizar imagens relacionadas a essa página',
+    'image_search_hint' => 'Pesquisar imagem por nome',
+    'image_uploaded' => 'Carregado :uploadedDate',
+    'image_load_more' => 'Carregar Mais',
+    'image_image_name' => 'Nome da Imagem',
+    'image_delete_confirm' => 'Essa imagem Ã© usada nas páginas abaixo. Clique em Excluir novamente para confirmar que você deseja mesmo eliminar a imagem.',
+    'image_select_image' => 'Selecionar Imagem',
+    'image_dropzone' => 'Arraste imagens ou clique aqui para fazer upload',
+    'images_deleted' => 'Imagens excluídas',
+    'image_preview' => 'Virtualização de Imagem',
+    'image_upload_success' => 'Upload de imagem efetuado com sucesso',
+    'image_update_success' => 'Upload de detalhes da imagem efetuado com sucesso',
+    'image_delete_success' => 'Imagem excluída com sucesso'
+];
\ No newline at end of file
diff --git a/resources/lang/pt_BR/entities.php b/resources/lang/pt_BR/entities.php
new file mode 100644 (file)
index 0000000..a6e6703
--- /dev/null
@@ -0,0 +1,226 @@
+<?php
+return [
+
+    /**
+     * Shared
+     */
+    'recently_created' => 'Recentemente criado',
+    'recently_created_pages' => 'Páginas recentemente criadas',
+    'recently_updated_pages' => 'Páginas recentemente atualizadas',
+    'recently_created_chapters' => 'Capítulos recentemente criados',
+    'recently_created_books' => 'Livros recentemente criados',
+    'recently_update' => 'Recentemente atualizado',
+    'recently_viewed' => 'Recentemente visualizado',
+    'recent_activity' => 'Atividade recente',
+    'create_now' => 'Criar um agora',
+    'revisions' => 'Revisões',
+    'meta_created' => 'Criado em :timeLength',
+    'meta_created_name' => 'Criado em :timeLength por :user',
+    'meta_updated' => 'Atualizado em :timeLength',
+    'meta_updated_name' => 'Atualizado em :timeLength por :user',
+    'x_pages' => ':count Páginas',
+    'entity_select' => 'Seleção de Entidade',
+    'images' => 'Imagens',
+    'my_recent_drafts' => 'Meus rascunhos recentes',
+    'my_recently_viewed' => 'Meus itens recentemente visto',
+    'no_pages_viewed' => 'Você não visualizou nenhuma página',
+    'no_pages_recently_created' => 'Nenhuma página recentemente criada',
+    'no_pages_recently_updated' => 'Nenhuma página recentemente atualizada',
+
+    /**
+     * Permissions and restrictions
+     */
+    'permissions' => 'Permissões',
+    'permissions_intro' => 'Uma vez habilitado, as permissões terão prioridade sobre outro conjunto de permissões.',
+    'permissions_enable' => 'Habilitar Permissões Customizadas',
+    'permissions_save' => 'Salvar Permissões',
+
+    /**
+     * Search
+     */
+    'search_results' => 'Resultado(s) da Pesquisa',
+    'search_results_page' => 'Resultado(s) de Pesquisa de Página',
+    'search_results_chapter' => 'Resultado(s) de Pesquisa de Capítulo',
+    'search_results_book' => 'Resultado(s) de Pesquisa de Livro',
+    'search_clear' => 'Limpar Pesquisa',
+    'search_view_pages' => 'Visualizar todas as páginas correspondentes',
+    'search_view_chapters' => 'Visualizar todos os capítulos correspondentes',
+    'search_view_books' => 'Visualizar todos os livros correspondentes',
+    'search_no_pages' => 'Nenhuma página corresponde Ã  pesquisa',
+    'search_for_term' => 'Pesquisar por :term',
+    'search_page_for_term' => 'Pesquisar Página por :term',
+    'search_chapter_for_term' => 'Pesquisar Capítulo por :term',
+    'search_book_for_term' => 'Pesquisar Livros por :term',
+
+    /**
+     * Books
+     */
+    'book' => 'Livro',
+    'books' => 'Livros',
+    'books_empty' => 'Nenhum livro foi criado',
+    'books_popular' => 'Livros populares',
+    'books_recent' => 'Livros recentes',
+    'books_popular_empty' => 'Os livros mais populares aparecerão aqui.',
+    'books_create' => 'Criar novo Livro',
+    'books_delete' => 'Excluir Livro',
+    'books_delete_named' => 'Excluir Livro :bookName',
+    'books_delete_explain' => 'A ação vai excluír o livro com o nome \':bookName\'. Todas as páginas e capítulos serão removidos.',
+    'books_delete_confirmation' => 'Você tem certeza que quer excluír o Livro?',
+    'books_edit' => 'Editar Livro',
+    'books_edit_named' => 'Editar Livro :bookName',
+    'books_form_book_name' => 'Nome do Livro',
+    'books_save' => 'Salvar Livro',
+    'books_permissions' => 'Permissões do Livro',
+    'books_permissions_updated' => 'Permissões do Livro Atualizadas',
+    'books_empty_contents' => 'Nenhuma página ou capítulo criado para esse livro.',
+    'books_empty_create_page' => 'Criar uma nova página',
+    'books_empty_or' => 'ou',
+    'books_empty_sort_current_book' => 'Ordenar o livro atual',
+    'books_empty_add_chapter' => 'Adicionar um capítulo',
+    'books_permissions_active' => 'Permissões do Livro ativadas',
+    'books_search_this' => 'Pesquisar esse livro',
+    'books_navigation' => 'Navegação do Livro',
+    'books_sort' => 'Ordenar conteúdos do Livro',
+    'books_sort_named' => 'Ordenar Livro :bookName',
+    'books_sort_show_other' => 'Mostrar outros livros',
+    'books_sort_save' => 'Salvar nova ordenação',
+
+    /**
+     * Chapters
+     */
+    'chapter' => 'Capitulo',
+    'chapters' => 'Capítulos',
+    'chapters_popular' => 'Capítulos Populares',
+    'chapters_new' => 'Novo Capítulo',
+    'chapters_create' => 'Criar novo Capítulo',
+    'chapters_delete' => 'Excluír Capítulo',
+    'chapters_delete_named' => 'Excluir Capítulo :chapterName',
+    'chapters_delete_explain' => 'A ação vai excluír o capítulo de nome \':chapterName\'. Todas as páginas do capítulo serão removidas
+        e adicionadas diretamente ao livro pai.',
+    'chapters_delete_confirm' => 'Tem certeza que deseja excluír o capitulo?',
+    'chapters_edit' => 'Editar Capítulo',
+    'chapters_edit_named' => 'Editar capitulo :chapterName',
+    'chapters_save' => 'Salvar Capítulo',
+    'chapters_move' => 'Mover Capítulo',
+    'chapters_move_named' => 'Mover Capítulo :chapterName',
+    'chapter_move_success' => 'Capítulo movido para :bookName',
+    'chapters_permissions' => 'Permissões do Capítulo',
+    'chapters_empty' => 'Nenhuma página existente nesse capítulo.',
+    'chapters_permissions_active' => 'Permissões de Capítulo ativadas',
+    'chapters_permissions_success' => 'Permissões de Capítulo atualizadas',
+
+    /**
+     * Pages
+     */
+    'page' => 'Página',
+    'pages' => 'Páginas',
+    'pages_popular' => 'Páginas Popular',
+    'pages_new' => 'Nova Página',
+    'pages_attachments' => 'Anexos',
+    'pages_navigation' => 'Página de Navegação',
+    'pages_delete' => 'Excluír Página',
+    'pages_delete_named' => 'Excluír Página :pageName',
+    'pages_delete_draft_named' => 'Excluir rascunho de Página de nome :pageName',
+    'pages_delete_draft' => 'Excluir rascunho de Página',
+    'pages_delete_success' => 'Página excluída',
+    'pages_delete_draft_success' => 'Página de rascunho excluída',
+    'pages_delete_confirm' => 'Tem certeza que deseja excluir a página?',
+    'pages_delete_draft_confirm' => 'Tem certeza que deseja excluir o rascunho de página?',
+    'pages_editing_named' => 'Editando a Página :pageName',
+    'pages_edit_toggle_header' => 'Alternar cabeçalho',
+    'pages_edit_save_draft' => 'Salvar Rascunho',
+    'pages_edit_draft' => 'Editar rascunho de Página',
+    'pages_editing_draft' => 'Editando Rascunho',
+    'pages_editing_page' => 'Editando Página',
+    'pages_edit_draft_save_at' => 'Rascunho salvo em ',
+    'pages_edit_delete_draft' => 'Excluir rascunho',
+    'pages_edit_discard_draft' => 'Descartar rascunho',
+    'pages_edit_set_changelog' => 'Definir Changelog',
+    'pages_edit_enter_changelog_desc' => 'Digite uma breve descrição das mudanças efetuadas por você',
+    'pages_edit_enter_changelog' => 'Entrar no  Changelog',
+    'pages_save' => 'Salvar Página',
+    'pages_title' => 'Título de Página',
+    'pages_name' => 'Nome da Página',
+    'pages_md_editor' => 'Editor',
+    'pages_md_preview' => 'Preview',
+    'pages_md_insert_image' => 'Inserir Imagem',
+    'pages_md_insert_link' => 'Inserir Link para Entidade',
+    'pages_not_in_chapter' => 'Página não está dentro de um Capítulo',
+    'pages_move' => 'Mover Página',
+    'pages_move_success' => 'Pagina movida para ":parentName"',
+    'pages_permissions' => 'Permissões de Página',
+    'pages_permissions_success' => 'Permissões de Página atualizadas',
+    'pages_revisions' => 'Revisões de Página',
+    'pages_revisions_named' => 'Revisões de Página para :pageName',
+    'pages_revision_named' => 'Revisão de Página para :pageName',
+    'pages_revisions_created_by' => 'Criado por',
+    'pages_revisions_date' => 'Data da Revisão',
+    'pages_revisions_changelog' => 'Changelog',
+    'pages_revisions_changes' => 'Mudanças',
+    'pages_revisions_current' => 'Versão atual',
+    'pages_revisions_preview' => 'Preview',
+    'pages_revisions_restore' => 'Restaurar',
+    'pages_revisions_none' => 'Essa página não tem revisões',
+    'pages_export' => 'Exportar',
+    'pages_export_html' => 'Arquivo Web Contained',
+    'pages_export_pdf' => 'Arquivo PDF',
+    'pages_export_text' => 'Arquivo Texto',
+    'pages_copy_link' => 'Copia Link',
+    'pages_permissions_active' => 'Permissões de Página Ativas',
+    'pages_initial_revision' => 'Publicação Inicial',
+    'pages_initial_name' => 'Nova Página',
+    'pages_editing_draft_notification' => 'Você está atualmente editando um rascunho que foi salvo da Ãºltima vez em :timeDiff.',
+    'pages_draft_edited_notification' => 'Essa página foi atualizada desde então. Ã‰ recomendado que você descarte esse rascunho.',
+    'pages_draft_edit_active' => [
+        'start_a' => ':count usuários que iniciaram edição dessa página',
+        'start_b' => ':userName iniciou a edição dessa página',
+        'time_a' => 'desde que a página foi atualizada pela Ãºltima vez',
+        'time_b' => 'nos Ãºltimos :minCount minutos',
+        'message' => ':start :time. Tome cuidado para não sobrescrever atualizações de outras pessoas!',
+    ],
+    'pages_draft_discarded' => 'Rascunho descartado. O editor foi atualizado com a página atualizada',
+
+    /**
+     * Editor sidebar
+     */
+    'page_tags' => 'Tags de Página',
+    'tag' => 'Tag',
+    'tags' =>  '',
+    'tag_value' => 'Valor da Tag (Opcional)',
+    'tags_explain' => "Adicione algumas tags para melhor categorizar seu conteúdo. \n Você pode atrelar um valor para uma tag para uma organização mais consistente.",
+    'tags_add' => 'Adicionar outra tag',
+    'attachments' => 'Anexos',
+    'attachments_explain' => 'Faça o Upload de alguns arquivos ou anexo algum link para ser mostrado na sua página. Eles estarão visíveis na barra lateral Ã  direita da página.',
+    'attachments_explain_instant_save' => 'Mudanças são salvas instantaneamente.',
+    'attachments_items' => 'Itens Anexados',
+    'attachments_upload' => 'Upload de arquivos',
+    'attachments_link' => 'Links Anexados',
+    'attachments_set_link' => 'Definir Link',
+    'attachments_delete_confirm' => 'Clique novamente em Excluir para confirmar a exclusão desse anexo.',
+    'attachments_dropzone' => 'Arraste arquivos para cá ou clique para anexar arquivos',
+    'attachments_no_files' => 'Nenhum arquivo foi enviado',
+    'attachments_explain_link' => 'Você pode anexar um link se preferir não fazer o upload do arquivo. O link poderá ser para uma outra página ou link para um arquivo na nuvem.',
+    'attachments_link_name' => 'Nome do Link',
+    'attachment_link' => 'Link para o Anexo',
+    'attachments_link_url' => 'Link para o Arquivo',
+    'attachments_link_url_hint' => 'URL do site ou arquivo',
+    'attach' => 'Anexar',
+    'attachments_edit_file' => 'Editar Arquivo',
+    'attachments_edit_file_name' => 'Nome do Arquivo',
+    'attachments_edit_drop_upload' => 'Arraste arquivos para cá ou clique para anexar arquivos e sobrescreve-lo',
+    'attachments_order_updated' => 'Ordem dos anexos atualizada',
+    'attachments_updated_success' => 'Detalhes dos anexos atualizados',
+    'attachments_deleted' => 'Anexo excluído',
+    'attachments_file_uploaded' => 'Upload de arquivo efetuado com sucesso',
+    'attachments_file_updated' => 'Arquivo atualizado com sucesso',
+    'attachments_link_attached' => 'Link anexado com sucesso Ã  página',
+
+    /**
+     * Profile View
+     */
+    'profile_user_for_x' => 'Usuário por :time',
+    'profile_created_content' => 'Conteúdo Criado',
+    'profile_not_created_pages' => ':userName não criou páginas',
+    'profile_not_created_chapters' => ':userName não criou capítulos',
+    'profile_not_created_books' => ':userName não criou livros',
+];
\ No newline at end of file
diff --git a/resources/lang/pt_BR/errors.php b/resources/lang/pt_BR/errors.php
new file mode 100644 (file)
index 0000000..91b85e3
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+
+return [
+
+    /**
+     * Error text strings.
+     */
+
+    // Permissions
+    'permission' => 'Você não tem permissões para acessar a página requerida.',
+    'permissionJson' => 'Você não tem permissão para realizar a ação requerida.',
+
+    // Auth
+    'error_user_exists_different_creds' => 'Um usuário com o e-mail :email já existe mas com credenciais diferentes.',
+    'email_already_confirmed' => 'E-mail já foi confirmado. Tente efetuar o login.',
+    'email_confirmation_invalid' => 'Esse token de confirmação não Ã© válido ou já foi utilizado. Por favor, tente efetuar o registro novamente.',
+    'email_confirmation_expired' => 'O token de confirmação já expirou. Um novo e-mail foi enviado.',
+    'ldap_fail_anonymous' => 'O acesso LDAP falhou ao tentar usar o anonymous bind',
+    'ldap_fail_authed' => 'O acesso LDAPfalou ao tentar os detalhes do dn e senha fornecidos',
+    'ldap_extension_not_installed' => 'As extensões LDAP PHP não estão instaladas',
+    'ldap_cannot_connect' => 'Não foi possível conectar ao servidor LDAP. Conexão inicial falhou',
+    'social_no_action_defined' => 'Nenhuma ação definida',
+    'social_account_in_use' => 'Essa conta :socialAccount já está em uso. Por favor, tente se logar usando a opção :socialAccount',
+    'social_account_email_in_use' => 'O e-mail :email já está e muso. Se você já tem uma conta você poderá se conectar a conta :socialAccount a partir das configurações de seu perfil.',
+    'social_account_existing' => 'Essa conta :socialAccount já está atrelada a esse perfil.',
+    'social_account_already_used_existing' => 'Essa conta :socialAccount já está sendo usada por outro usuário.',
+    'social_account_not_used' => 'Essa conta :socialAccount não está atrelada a nenhum usuário. Por favor, faça o link da conta com suas configurações de perfil. ',
+    'social_account_register_instructions' => 'Se você não tem uma conta, você poderá fazer o registro usando a opção :socialAccount',
+    'social_driver_not_found' => 'Social driver não encontrado',
+    'social_driver_not_configured' => 'Seus parâmetros socials de :socialAccount não estão configurados corretamente.',
+
+    // System
+    'path_not_writable' => 'O caminho de destino (:filePath) de upload de arquivo não possui permissão de escrita. Certifique-se que ele possui direitos de escrita no servidor.',
+    'cannot_get_image_from_url' => 'Não foi possivel capturar a imagem a partir de :url',
+    'cannot_create_thumbs' => 'O servidor não pôde criar as miniaturas de imagem. Por favor, verifique se a extensão GD PHP está instalada.',
+    'server_upload_limit' => 'O servidor não permite o upload de arquivos com esse tamanho. Por favor, tente fazer o upload de arquivos de menor tamanho.',
+    'image_upload_error' => 'Um erro aconteceu enquanto o servidor tentava efetuar o upload da imagem',
+
+    // Attachments
+    'attachment_page_mismatch' => 'Erro de \'Page mismatch\' durante a atualização do anexo',
+
+    // Pages
+    'page_draft_autosave_fail' => 'Falou ao tentar salvar o rascunho. Certifique-se que a conexão de internet está funcional antes de tentar salvar essa página',
+
+    // Entities
+    'entity_not_found' => 'Entidade não encontrada',
+    'book_not_found' => 'Livro não encontrado',
+    'page_not_found' => 'Página não encontrada',
+    'chapter_not_found' => 'Capítulo não encontrado',
+    'selected_book_not_found' => 'O livro selecionado não foi encontrado',
+    'selected_book_chapter_not_found' => 'O Livro selecionado ou Capítulo não foi encontrado',
+    'guests_cannot_save_drafts' => 'Convidados não podem salvar rascunhos',
+
+    // Users
+    'users_cannot_delete_only_admin' => 'Você não pode excluir o conteúdo, apenas o admin.',
+    'users_cannot_delete_guest' => 'Você não pode excluir o usuário convidado',
+
+    // Roles
+    'role_cannot_be_edited' => 'Esse perfil não poed ser editado',
+    'role_system_cannot_be_deleted' => 'Esse perfil Ã© um perfil de sistema e não pode ser excluído',
+    'role_registration_default_cannot_delete' => 'Esse perfil não poderá se excluído enquando estiver registrado como o perfil padrão',
+
+    // Error pages
+    '404_page_not_found' => 'Página não encontrada',
+    'sorry_page_not_found' => 'Desculpe, a página que você está procurando não pôde ser encontrada.',
+    'return_home' => 'Retornar Ã  página principal',
+    'error_occurred' => 'Um erro ocorreu',
+    'app_down' => ':appName está fora do ar no momento',
+    'back_soon' => 'Voltaremos em seguida.',
+];
\ No newline at end of file
diff --git a/resources/lang/pt_BR/pagination.php b/resources/lang/pt_BR/pagination.php
new file mode 100644 (file)
index 0000000..6a32f34
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+
+return [
+
+    /*
+    |--------------------------------------------------------------------------
+    | Pagination Language Lines
+    |--------------------------------------------------------------------------
+    |
+    | The following language lines are used by the paginator library to build
+    | the simple pagination links. You are free to change them to anything
+    | you want to customize your views to better match your application.
+    |
+    */
+
+    'previous' => '&laquo; Anterior',
+    'next'     => 'Próximo &raquo;',
+
+];
diff --git a/resources/lang/pt_BR/passwords.php b/resources/lang/pt_BR/passwords.php
new file mode 100644 (file)
index 0000000..f75c24e
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+
+return [
+
+    /*
+    |--------------------------------------------------------------------------
+    | Password Reminder Language Lines
+    |--------------------------------------------------------------------------
+    |
+    | The following language lines are the default lines which match reasons
+    | that are given by the password broker for a password update attempt
+    | has failed, such as for an invalid token or invalid new password.
+    |
+    */
+
+    'password' => 'Senhas devem ter ao menos 6 caraceres e combinar com os atributos mínimos para a senha.',
+    'user' => "Não pudemos encontrar um usuário com o e-mail fornecido.",
+    'token' => 'O token de reset de senha Ã© inválido.',
+    'sent' => 'Enviamos para seu e-mail o link de reset de senha!',
+    'reset' => 'Sua senha foi resetada com sucesso!',
+
+];
diff --git a/resources/lang/pt_BR/settings.php b/resources/lang/pt_BR/settings.php
new file mode 100644 (file)
index 0000000..b8d062b
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+
+return [
+    
+    /**
+     * Settings text strings
+     * Contains all text strings used in the general settings sections of BookStack
+     * including users and roles.
+     */
+    
+    'settings' => 'Configurações',
+    'settings_save' => 'Salvar Configurações',
+    'settings_save_success' => 'Configurações Salvas',
+
+    /**
+     * App settings
+     */
+
+    'app_settings' => 'Configurações do App',
+    'app_name' => 'Nome da Aplicação',
+    'app_name_desc' => 'Esse nome será mostrado no cabeçalho e em e-mails.',
+    'app_name_header' => 'Mostrar o nome da Aplicação no cabeçalho?',
+    'app_public_viewing' => 'Permitir visualização pública?',
+    'app_secure_images' => 'Permitir upload de imagens com maior segurança?',
+    'app_secure_images_desc' => 'Por questões de performance, todas as imagens são públicas. Essa opção adiciona uma string randômica na frente da imagem. Certifique-se de que os Ã­ndices do diretórios permitem o acesso fácil.',
+    'app_editor' => 'Editor de Página',
+    'app_editor_desc' => 'Selecione qual editor a ser usado pelos usuários para editar páginas.',
+    'app_custom_html' => 'Conteúdo para tag HTML HEAD customizado',
+    'app_custom_html_desc' => 'Quaisquer conteúdos aqui inseridos serão inseridos no final da seção <head> do HTML de cada página. Essa Ã© uma maneira Ãºtil de sobrescrever estilos e adicionar códigos de análise de site.',
+    'app_logo' => 'Logo da Aplicação',
+    'app_logo_desc' => 'A imagem deve ter 43px de altura. <br>Imagens mais largas devem ser reduzidas.',
+    'app_primary_color' => 'Cor primária da Aplicação',
+    'app_primary_color_desc' => 'Esse valor deverá ser Hexadecimal. <br>Deixe em branco para que o Bookstack assuma a cor padrão.',
+
+    /**
+     * Registration settings
+     */
+
+    'reg_settings' => 'Parâmetros de Registro',
+    'reg_allow' => 'Permitir Registro?',
+    'reg_default_role' => 'Perfil padrão para usuários após o registro',
+    'reg_confirm_email' => 'Requerer confirmação por e-mail?',
+    'reg_confirm_email_desc' => 'Se restrições de domínio são usadas a confirmação por e-mail será requerida e o valor abaixo será ignorado.',
+    'reg_confirm_restrict_domain' => 'Restringir registro ao domínio',
+    'reg_confirm_restrict_domain_desc' => 'Entre com uma lista de domínios de e-mails separados por vírgula para os quais você deseja restringir os registros. Será enviado um e-mail de confirmação para o usuário validar o e-mail antes de ser permitido interação com a aplicação. <br> Note que os usuários serão capazes de alterar o e-mail cadastrado após o sucesso na confirmação do registro.',
+    'reg_confirm_restrict_domain_placeholder' => 'Nenhuma restrição configurada',
+
+    /**
+     * Role settings
+     */
+
+    'roles' => 'Perfis',
+    'role_user_roles' => 'Perfis de Usuário',
+    'role_create' => 'Criar novo Perfil',
+    'role_create_success' => 'Perfil criado com sucesso',
+    'role_delete' => 'Excluir Perfil',
+    'role_delete_confirm' => 'A ação vai excluír o Perfil de nome \':roleName\'.',
+    'role_delete_users_assigned' => 'Esse Perfil tem :userCount usuários assinalados a ele. Se quiser migrar usuários desse Perfil para outro, selecione um novo Perfil.',
+    'role_delete_no_migration' => "Não migre os usuários",
+    'role_delete_sure' => 'Tem certeza que deseja excluir esse Perfil?',
+    'role_delete_success' => 'Perfil excluído com sucesso',
+    'role_edit' => 'Editar Perfil',
+    'role_details' => 'Detalhes do Perfil',
+    'role_name' => 'Nome do Perfil',
+    'role_desc' => 'Descrição Curta do Perfil',
+    'role_system' => 'Permissões do Sistema',
+    'role_manage_users' => 'Gerenciar Usuários',
+    'role_manage_roles' => 'Gerenciar Perfis & Permissões de Perfis',
+    'role_manage_entity_permissions' => 'Gerenciar todos os livros, capítulos e permissões de páginas',
+    'role_manage_own_entity_permissions' => 'Gerenciar permissões de seu próprio livro, capítulo e paginas',
+    'role_manage_settings' => 'Gerenciar configurações de app',
+    'role_asset' => 'Permissões de Ativos',
+    'role_asset_desc' => 'Essas permissões controlam o acesso padrão para os ativos dentro do sistema. Permissões em Livros, Capítulos e Páginas serão sobrescritas por essas permissões.',
+    'role_all' => 'Todos',
+    'role_own' => 'Próprio',
+    'role_controlled_by_asset' => 'Controlado pelos ativos que você fez upload',
+    'role_save' => 'Salvar Perfil',
+    'role_update_success' => 'Perfil atualizado com sucesso',
+    'role_users' => 'Usuários neste Perfil',
+    'role_users_none' => 'Nenhum usuário está atualmente atrelado a esse Perfil',
+
+    /**
+     * Users
+     */
+
+    'users' => 'Usuários',
+    'user_profile' => 'Perfil de Usuário',
+    'users_add_new' => 'Adicionar Novo Usuário',
+    'users_search' => 'Pesquisar Usuários',
+    'users_role' => 'Perfis de Usuário',
+    'users_external_auth_id' => 'ID de Autenticação Externa',
+    'users_password_warning' => 'Preencha os dados abaixo caso queira modificar a sua senha:',
+    'users_system_public' => 'Esse usuário representa quaisquer convidados que visitam o aplicativo. Ele não pode ser usado para login.',
+    'users_delete' => 'Excluir Usuário',
+    'users_delete_named' => 'Excluir :userName',
+    'users_delete_warning' => 'A ação vai excluir completamente o usuário de nome \':userName\' do sistema.',
+    'users_delete_confirm' => 'Tem certeza que deseja excluir esse usuário?',
+    'users_delete_success' => 'Usuários excluídos com sucesso',
+    'users_edit' => 'Editar usuário',
+    'users_edit_profile' => 'Editar Perfil',
+    'users_edit_success' => 'Usuário atualizado com sucesso',
+    'users_avatar' => 'Imagem de Usuário',
+    'users_avatar_desc' => 'Essa imagem deve ser um quadrado com aproximadamente 256px de altura e largura.',
+    'users_social_accounts' => 'Contas Sociais',
+    'users_social_accounts_info' => 'Aqui você pode conectar outras contas para acesso mais rápido. Desconectar uma conta não retira a possibilidade de acesso usando-a. Para revogar o acesso ao perfil através da conta social, você deverá fazê-lo na sua conta social.',
+    'users_social_connect' => 'Contas conectadas',
+    'users_social_disconnect' => 'Desconectar Conta',
+    'users_social_connected' => 'Conta :socialAccount foi conectada com sucesso ao seu perfil.',
+    'users_social_disconnected' => 'Conta :socialAccount foi desconectada com sucesso de seu perfil.',
+];
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/lang/pt_BR/validation.php b/resources/lang/pt_BR/validation.php
new file mode 100644 (file)
index 0000000..451dbe9
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+
+return [
+
+    /*
+    |--------------------------------------------------------------------------
+    | Validation Language Lines
+    |--------------------------------------------------------------------------
+    |
+    | The following language lines contain the default error messages used by
+    | the validator class. Some of these rules have multiple versions such
+    | as the size rules. Feel free to tweak each of these messages here.
+    |
+    */
+
+    'accepted'             => 'O :attribute deve ser aceito.',
+    'active_url'           => 'O :attribute não Ã© uma URL válida.',
+    'after'                => 'O :attribute deve ser uma data posterior Ã  data :date.',
+    'alpha'                => 'O :attribute deve conter apenas letras.',
+    'alpha_dash'           => 'O :attribute deve conter apenas letras, números e traços.',
+    'alpha_num'            => 'O :attribute deve conter apenas letras e números.',
+    'array'                => 'O :attribute deve ser uma array.',
+    'before'               => 'O :attribute deve ser uma data anterior Ã  data :date.',
+    'between'              => [
+        'numeric' => 'O :attribute deve ter tamanho entre :min e :max.',
+        'file'    => 'O :attribute deve ter entre :min e :max kilobytes.',
+        'string'  => 'O :attribute deve ter entre :min e :max caracteres.',
+        'array'   => 'O :attribute deve ter entre :min e :max itens.',
+    ],
+    'boolean'              => 'O campo :attribute deve ser verdadeiro ou falso.',
+    'confirmed'            => 'O campo :attribute de confirmação não Ã© igual.',
+    'date'                 => 'O campo :attribute não está em um formato de data válido.',
+    'date_format'          => 'O campo :attribute não tem a formatação :format.',
+    'different'            => 'O campo :attribute e o campo :other devem ser diferentes.',
+    'digits'               => 'O campo :attribute deve ter :digits dígitos.',
+    'digits_between'       => 'O campo :attribute deve ter entre :min e :max dígitos.',
+    'email'                => 'O campo :attribute deve ser um e-mail válido.',
+    'filled'               => 'O campo :attribute Ã© requerido.',
+    'exists'               => 'O atributo :attribute selecionado não Ã© válido.',
+    'image'                => 'O campo :attribute deve ser uma imagem.',
+    'in'                   => 'The selected :attribute is invalid.',
+    'integer'              => 'O campo :attribute deve ser um número inteiro.',
+    'ip'                   => 'O campo :attribute deve ser um IP válido.',
+    'max'                  => [
+        'numeric' => 'O valor para o campo :attribute não deve ser maior que :max.',
+        'file'    => 'O valor para o campo :attribute não deve ter tamanho maior que :max kilobytes.',
+        'string'  => 'O valor para o campo :attribute não deve ter mais que :max caracteres.',
+        'array'   => 'O valor para o campo :attribute não deve ter mais que :max itens.',
+    ],
+    'mimes'                => 'O :attribute deve ser do tipo type: :values.',
+    'min'                  => [
+        'numeric' => 'O valor para o campo :attribute não deve ser menor que :min.',
+        'file'    => 'O valor para o campo :attribute não deve ter tamanho menor que :min kilobytes.',
+        'string'  => 'O valor para o campo :attribute não deve ter menos que :min caracteres.',
+        'array'   => 'O valor para o campo :attribute não deve ter menos que :min itens.',
+    ],
+    'not_in'               => 'O campo selecionado :attribute Ã© inválido.',
+    'numeric'              => 'O campo :attribute deve ser um número.',
+    'regex'                => 'O formato do campo :attribute Ã© inválido.',
+    'required'             => 'O campo :attribute Ã© requerido.',
+    'required_if'          => 'O campo :attribute Ã© requerido quando o campo :other tem valor :value.',
+    'required_with'        => 'O campo :attribute Ã© requerido quando os valores :values estiverem presentes.',
+    'required_with_all'    => 'O campo :attribute Ã© requerido quando os valores :values estiverem presentes.',
+    'required_without'     => 'O campo :attribute Ã© requerido quando os valores :values não estiverem presentes.',
+    'required_without_all' => 'O campo :attribute Ã© requerido quando nenhum dos valores :values estiverem presentes.',
+    'same'                 => 'O campo :attribute e o campo :other devem ser iguais.',
+    'size'                 => [
+        'numeric' => 'O tamanho do campo :attribute deve ser :size.',
+        'file'    => 'O tamanho do arquivo :attribute deve ser de :size kilobytes.',
+        'string'  => 'O tamanho do campo :attribute deve ser de :size caracteres.',
+        'array'   => 'O campo :attribute deve conter :size itens.',
+    ],
+    'string'               => 'O campo :attribute deve ser uma string.',
+    'timezone'             => 'O campo :attribute deve conter uma timezone válida.',
+    'unique'               => 'Já existe um campo/dado de nome :attribute.',
+    'url'                  => 'O formato da URL :attribute Ã© inválido.',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Custom Validation Language Lines
+    |--------------------------------------------------------------------------
+    |
+    | Here you may specify custom validation messages for attributes using the
+    | convention "attribute.rule" to name the lines. This makes it quick to
+    | specify a specific custom language line for a given attribute rule.
+    |
+    */
+
+    'custom' => [
+        'password-confirm' => [
+            'required_with' => 'Confirmação de senha requerida',
+        ],
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Custom Validation Attributes
+    |--------------------------------------------------------------------------
+    |
+    | The following language lines are used to swap attribute place-holders
+    | with something more reader friendly such as E-Mail Address instead
+    | of "email". This simply helps us make messages a little cleaner.
+    |
+    */
+
+    'attributes' => [],
+
+];
index 0d97a6a4b4434ccb5a11fb203a8309d466c09941..49cd2a75a75e14fa6af96a2e35861fe47a33c9bf 100644 (file)
@@ -51,7 +51,7 @@
                     @include('partials/entity-list', [
                     'entities' => $recentlyUpdatedPages,
                     'style' => 'compact',
-                    'emptyText' => trans('entites.no_pages_recently_updated')
+                    'emptyText' => trans('entities.no_pages_recently_updated')
                     ])
                 </div>
             </div>
@@ -65,4 +65,4 @@
     </div>
 
 
-@stop
\ No newline at end of file
+@stop
index fb6ca30451e35df171ac5b843612d1d347a5b102..6eb927687cc765df7976746f502be7bb1b1f4b67 100644 (file)
@@ -7,6 +7,6 @@
     @if (isset($diff) && $diff)
         {!! $diff !!}
     @else
-        {!! $page->html !!}
+        {!! isset($pageContent) ? $pageContent : $page->html !!}
     @endif
 </div>
\ No newline at end of file
index a734b1b9526bb75525fbc0d71e5c148c71637824..fd6cebf4130bcaea45fdddfb898f21c38acbb03f 100644 (file)
@@ -53,9 +53,9 @@
 
                     <div class="pointer-container" id="pointer">
                         <div class="pointer anim">
-                            <i class="zmdi zmdi-link"></i>
-                            <input readonly="readonly" type="text" placeholder="url">
-                            <button class="button icon" title="{{ trans('entities.pages_copy_link') }}" data-clipboard-text=""><i class="zmdi zmdi-copy"></i></button>
+                            <span class="icon text-primary"><i class="zmdi zmdi-link"></i></span>
+                            <input readonly="readonly" type="text" id="pointer-url" placeholder="url">
+                            <button class="button icon" data-clipboard-target="#pointer-url" type="button" title="{{ trans('entities.pages_copy_link') }}"><i class="zmdi zmdi-copy"></i></button>
                         </div>
                     </div>
 
index 0fb97369e94480d9eb6e25d3fbcc4034547e2679..f366e9e9b8a29c79a9f6563a4437a98a3a1364ad 100644 (file)
@@ -26,7 +26,7 @@
         @endforeach
     @endif
 
-    @if (isset($pageNav) && $pageNav)
+    @if (isset($pageNav) && count($pageNav))
         <h6 class="text-muted">{{ trans('entities.pages_navigation') }}</h6>
         <div class="sidebar-page-nav menu">
             @foreach($pageNav as $navItem)
index 319f3a2df9dea8bed1310a5d0e7b3db9847c8d13..71b8f551fc97b22a083a82639421cae9fa53966a 100644 (file)
@@ -18,7 +18,7 @@
                 <label>@include('settings/roles/checkbox', ['permission' => 'users-manage']) {{ trans('settings.role_manage_users') }}</label>
                 <label>@include('settings/roles/checkbox', ['permission' => 'user-roles-manage']) {{ trans('settings.role_manage_roles') }}</label>
                 <label>@include('settings/roles/checkbox', ['permission' => 'restrictions-manage-all']) {{ trans('settings.role_manage_entity_permissions') }}</label>
-                <label>@include('settings/roles/checkbox', ['permission' => 'permissions']) {{ trans('settings.role_manage_own_entity_permissions') }}</label>
+                <label>@include('settings/roles/checkbox', ['permission' => 'restrictions-manage-own']) {{ trans('settings.role_manage_own_entity_permissions') }}</label>
                 <label>@include('settings/roles/checkbox', ['permission' => 'settings-manage']) {{ trans('settings.role_manage_settings') }}</label>
             </div>
 
index bff79820a664ede3b7f5fb3e51a0a19d1500f58f..de3a3151fab189d612d59742a8a9c62092eb0dfa 100644 (file)
@@ -8,7 +8,7 @@
             <div class="row">
                 <div class="col-sm-12 faded">
                     <div class="breadcrumbs">
-                        <a href="{{ baseUrl('/settings/users') }}" class="text-button"><i class="zmdi zmdi-accounts"></i>Users</a>
+                        <a href="{{ baseUrl('/settings/users') }}" class="text-button"><i class="zmdi zmdi-accounts"></i>{{ trans('settings.users') }}</a>
                     </div>
                 </div>
             </div>
@@ -16,7 +16,7 @@
     </div>
 
     <div class="container small" ng-non-bindable>
-        <h1>Create User</h1>
+        <h1>{{ trans('settings.users_add_new') }}</h1>
 
         <form action="{{ baseUrl("/settings/users/create") }}" method="post">
             {!! csrf_field() !!}
index 4db00e31f932fb8157fa63d8c085b25ead1a2b24..c5d512725ba7ab82a952172f85aa791285afb0ab 100644 (file)
@@ -5,8 +5,6 @@
 
     @include('settings/navbar', ['selected' => 'users'])
 
-
-
     <div class="container small">
         <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="post">
             <div class="row">
                           'name' => 'image_id',
                           'imageClass' => 'avatar large'
                       ])
-
+                </div>
+                <div class="form-group">
+                    <label for="user-language">{{ trans('settings.users_preferred_language') }}</label>
+                    <select name="setting[language]" id="user-language">
+                        @foreach(trans('settings.language_select') as $lang => $label)
+                            <option @if(setting()->getUser($user, 'language') === $lang) selected @endif value="{{ $lang }}">{{ $label }}</option>
+                        @endforeach
+                    </select>
                 </div>
             </div>
         </div>
index 8ee20ab6bcb76039c8d6bc4f81fa07035fb4a8c3..1373179966f1e7c3b97c685d5c88f00fc09d2009 100644 (file)
@@ -1,10 +1,7 @@
 <?php
 
-use Illuminate\Foundation\Testing\WithoutMiddleware;
-use Illuminate\Foundation\Testing\DatabaseMigrations;
-use Illuminate\Foundation\Testing\DatabaseTransactions;
 
-class ActivityTrackingTest extends TestCase
+class ActivityTrackingTest extends BrowserKitTest
 {
 
     public function test_recently_viewed_books()
index df625bcc9da4b56e9ec17d609b36fccdf683fae0..f99051a72a569fdcc680e71314d7b09fbbf05bbb 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-class AttachmentTest extends TestCase
+class AttachmentTest extends BrowserKitTest
 {
     /**
      * Get a test file that can be uploaded
index 664ec297a0bff766368b4d5c92d1ec6bb11fee42..f7595883853aee417e87d08c489beef6e55a4269 100644 (file)
@@ -3,7 +3,7 @@
 use BookStack\Notifications\ConfirmEmail;
 use Illuminate\Support\Facades\Notification;
 
-class AuthTest extends TestCase
+class AuthTest extends BrowserKitTest
 {
 
     public function test_auth_working()
@@ -220,6 +220,9 @@ class AuthTest extends TestCase
 
     public function test_reset_password_flow()
     {
+
+        Notification::fake();
+
         $this->visit('/login')->click('Forgot Password?')
             ->seePageIs('/password/email')
             ->type('[email protected]', 'email')
@@ -230,8 +233,13 @@ class AuthTest extends TestCase
             'email' => '[email protected]'
         ]);
 
+        $user = \BookStack\User::where('email', '=', '[email protected]')->first();
+
+        Notification::assertSentTo($user, \BookStack\Notifications\ResetPassword::class);
+        $n = Notification::sent($user, \BookStack\Notifications\ResetPassword::class);
+
         $reset = DB::table('password_resets')->where('email', '=', '[email protected]')->first();
-        $this->visit('/password/reset/' . $reset->token)
+        $this->visit('/password/reset/' . $n->first()->token)
             ->see('Reset Password')
             ->submitForm('Reset Password', [
                 'email' => '[email protected]',
index 45e46fe81796b1a2051691c7d08db87470a1ff79..80d0c9fe29ef5ff542340c3b05633063857d5216 100644 (file)
@@ -1,9 +1,7 @@
 <?php
-
-use BookStack\Services\LdapService;
 use BookStack\User;
 
-class LdapTest extends \TestCase
+class LdapTest extends BrowserKitTest
 {
 
     protected $mockLdap;
index 5739f9a7d4cf3989683b48d4ad499773be15bec8..aff86a81e853b2ce23729bc9adfb03c785a395d7 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-class SocialAuthTest extends TestCase
+class SocialAuthTest extends BrowserKitTest
 {
 
     public function test_social_registration()
diff --git a/tests/BrowserKitTest.php b/tests/BrowserKitTest.php
new file mode 100644 (file)
index 0000000..0a97c12
--- /dev/null
@@ -0,0 +1,234 @@
+<?php
+
+use Illuminate\Foundation\Testing\DatabaseTransactions;
+use Symfony\Component\DomCrawler\Crawler;
+
+abstract class BrowserKitTest extends \Laravel\BrowserKitTesting\TestCase
+{
+
+    use DatabaseTransactions;
+
+    /**
+     * The base URL to use while testing the application.
+     *
+     * @var string
+     */
+    protected $baseUrl = 'http://localhost';
+
+    // Local user instances
+    private $admin;
+    private $editor;
+
+    /**
+     * Creates the application.
+     *
+     * @return \Illuminate\Foundation\Application
+     */
+    public function createApplication()
+    {
+        $app = require __DIR__.'/../bootstrap/app.php';
+
+        $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
+
+        return $app;
+    }
+
+    /**
+     * Set the current user context to be an admin.
+     * @return $this
+     */
+    public function asAdmin()
+    {
+        return $this->actingAs($this->getAdmin());
+    }
+
+    /**
+     * Get the current admin user.
+     * @return mixed
+     */
+    public function getAdmin() {
+        if($this->admin === null) {
+            $adminRole = \BookStack\Role::getRole('admin');
+            $this->admin = $adminRole->users->first();
+        }
+        return $this->admin;
+    }
+
+    /**
+     * Set the current editor context to be an editor.
+     * @return $this
+     */
+    public function asEditor()
+    {
+        if ($this->editor === null) {
+            $this->editor = $this->getEditor();
+        }
+        return $this->actingAs($this->editor);
+    }
+
+    /**
+     * Get a user that's not a system user such as the guest user.
+     */
+    public function getNormalUser()
+    {
+        return \BookStack\User::where('system_name', '=', null)->get()->last();
+    }
+
+    /**
+     * Quickly sets an array of settings.
+     * @param $settingsArray
+     */
+    protected function setSettings($settingsArray)
+    {
+        $settings = app('BookStack\Services\SettingService');
+        foreach ($settingsArray as $key => $value) {
+            $settings->put($key, $value);
+        }
+    }
+
+    /**
+     * Create a group of entities that belong to a specific user.
+     * @param $creatorUser
+     * @param $updaterUser
+     * @return array
+     */
+    protected function createEntityChainBelongingToUser($creatorUser, $updaterUser = false)
+    {
+        if ($updaterUser === false) $updaterUser = $creatorUser;
+        $book = factory(BookStack\Book::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id]);
+        $chapter = factory(BookStack\Chapter::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id]);
+        $page = factory(BookStack\Page::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id, 'book_id' => $book->id]);
+        $book->chapters()->saveMany([$chapter]);
+        $chapter->pages()->saveMany([$page]);
+        $restrictionService = $this->app[\BookStack\Services\PermissionService::class];
+        $restrictionService->buildJointPermissionsForEntity($book);
+        return [
+            'book' => $book,
+            'chapter' => $chapter,
+            'page' => $page
+        ];
+    }
+
+    /**
+     * Quick way to create a new user
+     * @param array $attributes
+     * @return mixed
+     */
+    protected function getEditor($attributes = [])
+    {
+        $user = factory(\BookStack\User::class)->create($attributes);
+        $role = \BookStack\Role::getRole('editor');
+        $user->attachRole($role);;
+        return $user;
+    }
+
+    /**
+     * Quick way to create a new user without any permissions
+     * @param array $attributes
+     * @return mixed
+     */
+    protected function getNewBlankUser($attributes = [])
+    {
+        $user = factory(\BookStack\User::class)->create($attributes);
+        return $user;
+    }
+
+    /**
+     * Assert that a given string is seen inside an element.
+     *
+     * @param  bool|string|null $element
+     * @param  integer          $position
+     * @param  string           $text
+     * @param  bool             $negate
+     * @return $this
+     */
+    protected function seeInNthElement($element, $position, $text, $negate = false)
+    {
+        $method = $negate ? 'assertNotRegExp' : 'assertRegExp';
+
+        $rawPattern = preg_quote($text, '/');
+
+        $escapedPattern = preg_quote(e($text), '/');
+
+        $content = $this->crawler->filter($element)->eq($position)->html();
+
+        $pattern = $rawPattern == $escapedPattern
+            ? $rawPattern : "({$rawPattern}|{$escapedPattern})";
+
+        $this->$method("/$pattern/i", $content);
+
+        return $this;
+    }
+
+    /**
+     * Assert that the current page matches a given URI.
+     *
+     * @param  string  $uri
+     * @return $this
+     */
+    protected function seePageUrlIs($uri)
+    {
+        $this->assertEquals(
+            $uri, $this->currentUri, "Did not land on expected page [{$uri}].\n"
+        );
+
+        return $this;
+    }
+
+    /**
+     * Do a forced visit that does not error out on exception.
+     * @param string $uri
+     * @param array $parameters
+     * @param array $cookies
+     * @param array $files
+     * @return $this
+     */
+    protected function forceVisit($uri, $parameters = [], $cookies = [], $files = [])
+    {
+        $method = 'GET';
+        $uri = $this->prepareUrlForRequest($uri);
+        $this->call($method, $uri, $parameters, $cookies, $files);
+        $this->clearInputs()->followRedirects();
+        $this->currentUri = $this->app->make('request')->fullUrl();
+        $this->crawler = new Crawler($this->response->getContent(), $uri);
+        return $this;
+    }
+
+    /**
+     * Click the text within the selected element.
+     * @param $parentElement
+     * @param $linkText
+     * @return $this
+     */
+    protected function clickInElement($parentElement, $linkText)
+    {
+        $elem = $this->crawler->filter($parentElement);
+        $link = $elem->selectLink($linkText);
+        $this->visit($link->link()->getUri());
+        return $this;
+    }
+
+    /**
+     * Check if the page contains the given element.
+     * @param  string  $selector
+     * @return bool
+     */
+    protected function pageHasElement($selector)
+    {
+        $elements = $this->crawler->filter($selector);
+        $this->assertTrue(count($elements) > 0, "The page does not contain an element matching " . $selector);
+        return $this;
+    }
+
+    /**
+     * Check if the page contains the given element.
+     * @param  string  $selector
+     * @return bool
+     */
+    protected function pageNotHasElement($selector)
+    {
+        $elements = $this->crawler->filter($selector);
+        $this->assertFalse(count($elements) > 0, "The page contains " . count($elements) . " elements matching " . $selector);
+        return $this;
+    }
+}
index 3f60f9c36126b559b027a0d84f39cda03a5080b6..23351e5462837e2384b7b7c71c5d78eb3ee6447b 100644 (file)
@@ -1,8 +1,6 @@
 <?php
 
-use Illuminate\Support\Facades\DB;
-
-class EntitySearchTest extends TestCase
+class EntitySearchTest extends BrowserKitTest
 {
 
     public function test_page_search()
index 9fd4eb9ad299bcee4528cbf97e9e581744fd14fe..1b115ad65112cf3a600660959840af3afb06fd57 100644 (file)
@@ -1,8 +1,6 @@
 <?php
 
-use Illuminate\Support\Facades\DB;
-
-class EntityTest extends TestCase
+class EntityTest extends BrowserKitTest
 {
 
     public function test_entity_creation()
index eaf4d62c3ec9d964f38e91c1bc5db7f47c2086ef..03f3aa12fecc2fd2ccd30c19320c6a6202712cc7 100644 (file)
@@ -1,7 +1,6 @@
 <?php
 
-
-class MarkdownTest extends TestCase
+class MarkdownTest extends BrowserKitTest
 {
     protected $page;
 
diff --git a/tests/Entity/PageContentTest.php b/tests/Entity/PageContentTest.php
new file mode 100644 (file)
index 0000000..3a005bc
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+class PageContentTest extends BrowserKitTest
+{
+
+    public function test_page_includes()
+    {
+        $page = \BookStack\Page::first();
+        $secondPage = \BookStack\Page::all()->get(2);
+
+        $secondPage->html = "<p id='section1'>Hello, This is a test</p><p id='section2'>This is a second block of content</p>";
+        $secondPage->save();
+
+        $this->asAdmin()->visit($page->getUrl())
+            ->dontSee('Hello, This is a test');
+
+        $originalHtml = $page->html;
+        $page->html .= "{{@{$secondPage->id}}}";
+        $page->save();
+
+        $this->asAdmin()->visit($page->getUrl())
+            ->see('Hello, This is a test')
+            ->see('This is a second block of content');
+
+        $page->html = $originalHtml . " Well {{@{$secondPage->id}#section2}}";
+        $page->save();
+
+        $this->asAdmin()->visit($page->getUrl())
+            ->dontSee('Hello, This is a test')
+            ->see('Well This is a second block of content');
+    }
+
+}
index 233f300ee339a7fed34fb6eeb64c587c2006ee65..de875c3f3b09b2dbd2acc9f0cf0966c29976e935 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 
-class PageDraftTest extends TestCase
+class PageDraftTest extends BrowserKitTest
 {
     protected $page;
     protected $entityRepo;
index 4784297a2e804d7f0e2f74c91ddf60314670d4ae..3c6400d5817a26e3493cb61e3506e83c81a01d2c 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-class SortTest extends TestCase
+class SortTest extends BrowserKitTest
 {
     protected $book;
 
similarity index 59%
rename from tests/Entity/TagTests.php
rename to tests/Entity/TagTest.php
index 0520e1a00a3a7137e4d303797c37c629c042a76e..f4ce581e3f93d49571213b0cbeb34fe24a457ce1 100644 (file)
@@ -1,10 +1,10 @@
-<?php namespace Entity;
+<?php
 
 use BookStack\Tag;
 use BookStack\Page;
 use BookStack\Services\PermissionService;
 
-class TagTests extends \TestCase
+class TagTest extends BrowserKitTest
 {
 
     protected $defaultTagCount = 20;
@@ -86,61 +86,16 @@ class TagTests extends \TestCase
         $attrs = $attrs->merge(factory(Tag::class, 5)->make(['name' => 'color']));
         $page = $this->getPageWithTags($attrs);
 
-        $this->asAdmin()->get('/ajax/tags/suggest?search=co')->seeJsonEquals(['color', 'country']);
-        $this->asEditor()->get('/ajax/tags/suggest?search=co')->seeJsonEquals(['color', 'country']);
+        $this->asAdmin()->get('/ajax/tags/suggest/names?search=co')->seeJsonEquals(['color', 'country']);
+        $this->asEditor()->get('/ajax/tags/suggest/names?search=co')->seeJsonEquals(['color', 'country']);
 
         // Set restricted permission the page
         $page->restricted = true;
         $page->save();
         $permissionService->buildJointPermissionsForEntity($page);
 
-        $this->asAdmin()->get('/ajax/tags/suggest?search=co')->seeJsonEquals(['color', 'country']);
-        $this->asEditor()->get('/ajax/tags/suggest?search=co')->seeJsonEquals([]);
-    }
-
-    public function test_entity_tag_updating()
-    {
-        $page = $this->getPageWithTags();
-
-        $testJsonData = [
-            ['name' => 'color', 'value' => 'red'],
-            ['name' => 'color', 'value' => ' blue '],
-            ['name' => 'city', 'value' => 'London '],
-            ['name' => 'country', 'value' => ' England'],
-        ];
-        $testResponseJsonData = [
-            ['name' => 'color', 'value' => 'red'],
-            ['name' => 'color', 'value' => 'blue'],
-            ['name' => 'city', 'value' => 'London'],
-            ['name' => 'country', 'value' => 'England'],
-        ];
-
-        // Do update request
-        $this->asAdmin()->json("POST", "/ajax/tags/update/page/" . $page->id, ['tags' => $testJsonData]);
-        $updateData = json_decode($this->response->getContent());
-        // Check data is correct
-        $testDataCorrect = true;
-        foreach ($updateData->tags as $data) {
-            $testItem = ['name' => $data->name, 'value' => $data->value];
-            if (!in_array($testItem, $testResponseJsonData)) $testDataCorrect = false;
-        }
-        $testMessage = "Expected data was not found in the response.\nExpected Data: %s\nRecieved Data: %s";
-        $this->assertTrue($testDataCorrect, sprintf($testMessage, json_encode($testResponseJsonData), json_encode($updateData)));
-        $this->assertTrue(isset($updateData->message), "No message returned in tag update response");
-
-        // Do get request
-        $this->asAdmin()->get("/ajax/tags/get/page/" . $page->id);
-        $getResponseData = json_decode($this->response->getContent());
-        // Check counts
-        $this->assertTrue(count($getResponseData) === count($testJsonData), "The received tag count is incorrect");
-        // Check data is correct
-        $testDataCorrect = true;
-        foreach ($getResponseData as $data) {
-            $testItem = ['name' => $data->name, 'value' => $data->value];
-            if (!in_array($testItem, $testResponseJsonData)) $testDataCorrect = false;
-        }
-        $testMessage = "Expected data was not found in the response.\nExpected Data: %s\nRecieved Data: %s";
-        $this->assertTrue($testDataCorrect, sprintf($testMessage, json_encode($testResponseJsonData), json_encode($getResponseData)));
+        $this->asAdmin()->get('/ajax/tags/suggest/names?search=co')->seeJsonEquals(['color', 'country']);
+        $this->asEditor()->get('/ajax/tags/suggest/names?search=co')->seeJsonEquals([]);
     }
 
 }
index 9da12d36bb049531f88dbc2665ad951f3812db74..debde848c00422e0df0cdc85bcbd431cca63ac02 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-class ImageTest extends TestCase
+class ImageTest extends BrowserKitTest
 {
 
     /**
index cddd3206a36921abe7b1bb4f9c7940c505d81d4e..e874fccaeb2b73ea47badbcf7eba697cd9927737 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-class RestrictionsTest extends TestCase
+class RestrictionsTest extends BrowserKitTest
 {
     protected $user;
     protected $viewer;
index 500dd3b6772f5d4d2b62ff93bacea80eb34722fa..a4b5029150f26ff8099f65dae0015d0a51372ed4 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-class RolesTest extends TestCase
+class RolesTest extends BrowserKitTest
 {
     protected $user;
 
@@ -578,4 +578,44 @@ class RolesTest extends TestCase
             ->see('Cannot be deleted');
     }
 
+
+
+    public function test_image_delete_own_permission()
+    {
+        $this->giveUserPermissions($this->user, ['image-update-all']);
+        $page = \BookStack\Page::first();
+        $image = factory(\BookStack\Image::class)->create(['uploaded_to' => $page->id, 'created_by' => $this->user->id, 'updated_by' => $this->user->id]);
+
+        $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
+            ->seeStatusCode(403);
+
+        $this->giveUserPermissions($this->user, ['image-delete-own']);
+
+        $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
+            ->seeStatusCode(200)
+            ->dontSeeInDatabase('images', ['id' => $image->id]);
+    }
+
+    public function test_image_delete_all_permission()
+    {
+        $this->giveUserPermissions($this->user, ['image-update-all']);
+        $admin = $this->getAdmin();
+        $page = \BookStack\Page::first();
+        $image = factory(\BookStack\Image::class)->create(['uploaded_to' => $page->id, 'created_by' => $admin->id, 'updated_by' => $admin->id]);
+
+        $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
+            ->seeStatusCode(403);
+
+        $this->giveUserPermissions($this->user, ['image-delete-own']);
+
+        $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
+            ->seeStatusCode(403);
+
+        $this->giveUserPermissions($this->user, ['image-delete-all']);
+
+        $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
+            ->seeStatusCode(200)
+            ->dontSeeInDatabase('images', ['id' => $image->id]);
+    }
+
 }
index 2ea5fbfed428e89a3f02cfac45b73a8a9ec90257..6127e1cd40bdd8a878f6f219e1f2e622b54baf9e 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-class PublicActionTest extends TestCase
+class PublicActionTest extends BrowserKitTest
 {
 
     public function test_app_not_public()
index d3620eae0b9d1d985d8baaa988ca69c49c52a5f8..e0455f44712cd424c2ddea4d8f5dd670251c516f 100644 (file)
@@ -9,15 +9,11 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
     use DatabaseTransactions;
 
     /**
-     * The base URL to use while testing the application.
+     * The base URL of the application.
      *
      * @var string
      */
-    protected $baseUrl = 'http://localhost';
-
-    // Local user instances
-    private $admin;
-    private $editor;
+    public $baseUrl = 'http://localhost';
 
     /**
      * Creates the application.
@@ -28,207 +24,8 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
     {
         $app = require __DIR__.'/../bootstrap/app.php';
 
-        $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
+        $app->make(Kernel::class)->bootstrap();
 
         return $app;
     }
-
-    /**
-     * Set the current user context to be an admin.
-     * @return $this
-     */
-    public function asAdmin()
-    {
-        return $this->actingAs($this->getAdmin());
-    }
-
-    /**
-     * Get the current admin user.
-     * @return mixed
-     */
-    public function getAdmin() {
-        if($this->admin === null) {
-            $adminRole = \BookStack\Role::getRole('admin');
-            $this->admin = $adminRole->users->first();
-        }
-        return $this->admin;
-    }
-
-    /**
-     * Set the current editor context to be an editor.
-     * @return $this
-     */
-    public function asEditor()
-    {
-        if($this->editor === null) {
-            $this->editor = $this->getEditor();
-        }
-        return $this->actingAs($this->editor);
-    }
-
-    /**
-     * Get a user that's not a system user such as the guest user.
-     */
-    public function getNormalUser()
-    {
-        return \BookStack\User::where('system_name', '=', null)->get()->last();
-    }
-
-    /**
-     * Quickly sets an array of settings.
-     * @param $settingsArray
-     */
-    protected function setSettings($settingsArray)
-    {
-        $settings = app('BookStack\Services\SettingService');
-        foreach ($settingsArray as $key => $value) {
-            $settings->put($key, $value);
-        }
-    }
-
-    /**
-     * Create a group of entities that belong to a specific user.
-     * @param $creatorUser
-     * @param $updaterUser
-     * @return array
-     */
-    protected function createEntityChainBelongingToUser($creatorUser, $updaterUser = false)
-    {
-        if ($updaterUser === false) $updaterUser = $creatorUser;
-        $book = factory(BookStack\Book::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id]);
-        $chapter = factory(BookStack\Chapter::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id]);
-        $page = factory(BookStack\Page::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id, 'book_id' => $book->id]);
-        $book->chapters()->saveMany([$chapter]);
-        $chapter->pages()->saveMany([$page]);
-        $restrictionService = $this->app[\BookStack\Services\PermissionService::class];
-        $restrictionService->buildJointPermissionsForEntity($book);
-        return [
-            'book' => $book,
-            'chapter' => $chapter,
-            'page' => $page
-        ];
-    }
-
-    /**
-     * Quick way to create a new user
-     * @param array $attributes
-     * @return mixed
-     */
-    protected function getEditor($attributes = [])
-    {
-        $user = factory(\BookStack\User::class)->create($attributes);
-        $role = \BookStack\Role::getRole('editor');
-        $user->attachRole($role);;
-        return $user;
-    }
-
-    /**
-     * Quick way to create a new user without any permissions
-     * @param array $attributes
-     * @return mixed
-     */
-    protected function getNewBlankUser($attributes = [])
-    {
-        $user = factory(\BookStack\User::class)->create($attributes);
-        return $user;
-    }
-
-    /**
-     * Assert that a given string is seen inside an element.
-     *
-     * @param  bool|string|null $element
-     * @param  integer          $position
-     * @param  string           $text
-     * @param  bool             $negate
-     * @return $this
-     */
-    protected function seeInNthElement($element, $position, $text, $negate = false)
-    {
-        $method = $negate ? 'assertNotRegExp' : 'assertRegExp';
-
-        $rawPattern = preg_quote($text, '/');
-
-        $escapedPattern = preg_quote(e($text), '/');
-
-        $content = $this->crawler->filter($element)->eq($position)->html();
-
-        $pattern = $rawPattern == $escapedPattern
-            ? $rawPattern : "({$rawPattern}|{$escapedPattern})";
-
-        $this->$method("/$pattern/i", $content);
-
-        return $this;
-    }
-
-    /**
-     * Assert that the current page matches a given URI.
-     *
-     * @param  string  $uri
-     * @return $this
-     */
-    protected function seePageUrlIs($uri)
-    {
-        $this->assertEquals(
-            $uri, $this->currentUri, "Did not land on expected page [{$uri}].\n"
-        );
-
-        return $this;
-    }
-
-    /**
-     * Do a forced visit that does not error out on exception.
-     * @param string $uri
-     * @param array $parameters
-     * @param array $cookies
-     * @param array $files
-     * @return $this
-     */
-    protected function forceVisit($uri, $parameters = [], $cookies = [], $files = [])
-    {
-        $method = 'GET';
-        $uri = $this->prepareUrlForRequest($uri);
-        $this->call($method, $uri, $parameters, $cookies, $files);
-        $this->clearInputs()->followRedirects();
-        $this->currentUri = $this->app->make('request')->fullUrl();
-        $this->crawler = new Crawler($this->response->getContent(), $uri);
-        return $this;
-    }
-
-    /**
-     * Click the text within the selected element.
-     * @param $parentElement
-     * @param $linkText
-     * @return $this
-     */
-    protected function clickInElement($parentElement, $linkText)
-    {
-        $elem = $this->crawler->filter($parentElement);
-        $link = $elem->selectLink($linkText);
-        $this->visit($link->link()->getUri());
-        return $this;
-    }
-
-    /**
-     * Check if the page contains the given element.
-     * @param  string  $selector
-     * @return bool
-     */
-    protected function pageHasElement($selector)
-    {
-        $elements = $this->crawler->filter($selector);
-        $this->assertTrue(count($elements) > 0, "The page does not contain an element matching " . $selector);
-        return $this;
-    }
-
-    /**
-     * Check if the page contains the given element.
-     * @param  string  $selector
-     * @return bool
-     */
-    protected function pageNotHasElement($selector)
-    {
-        $elements = $this->crawler->filter($selector);
-        $this->assertFalse(count($elements) > 0, "The page contains " . count($elements) . " elements matching " . $selector);
-        return $this;
-    }
 }
index 9543adc1d3bc3f6752bffa1eadd27eb26387f064..a448e3a9f6429de1f28ac954b616454550759abd 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-class UserProfileTest extends TestCase
+class UserProfileTest extends BrowserKitTest
 {
     protected $user;
 
diff --git a/version b/version
index 8287f2896ba8c550d34ec5a27953c0a958c0de74..c7f762861ccd51ccbe6920cdee90c1993d353988 100644 (file)
--- a/version
+++ b/version
@@ -1 +1 @@
-v0.13-dev
+v0.15-dev