Merge branch 'master' into release
This commit is contained in:
		
						commit
						14b131e850
					
				| 
						 | 
				
			
			@ -98,7 +98,7 @@ abstract class Entity extends Model
 | 
			
		|||
     * @param string[] array $wheres
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public static function fullTextSearch($fieldsToSearch, $terms, $wheres = [])
 | 
			
		||||
    public static function fullTextSearchQuery($fieldsToSearch, $terms, $wheres = [])
 | 
			
		||||
    {
 | 
			
		||||
        $termString = '';
 | 
			
		||||
        foreach ($terms as $term) {
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +107,7 @@ abstract class Entity extends Model
 | 
			
		|||
        $fields = implode(',', $fieldsToSearch);
 | 
			
		||||
        $termStringEscaped = \DB::connection()->getPdo()->quote($termString);
 | 
			
		||||
        $search = static::addSelect(\DB::raw('*, MATCH(name) AGAINST('.$termStringEscaped.' IN BOOLEAN MODE) AS title_relevance'));
 | 
			
		||||
        $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termStringEscaped]);
 | 
			
		||||
        $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]);
 | 
			
		||||
 | 
			
		||||
        // Add additional where terms
 | 
			
		||||
        foreach ($wheres as $whereTerm) {
 | 
			
		||||
| 
						 | 
				
			
			@ -115,10 +115,13 @@ abstract class Entity extends Model
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        // Load in relations
 | 
			
		||||
        if (!static::isA('book')) $search = $search->with('book');
 | 
			
		||||
        if (static::isA('page'))  $search = $search->with('chapter');
 | 
			
		||||
        if (static::isA('page'))  {
 | 
			
		||||
            $search = $search->with('book', 'chapter', 'createdBy', 'updatedBy');
 | 
			
		||||
        } else if (static::isA('chapter')) {
 | 
			
		||||
            $search = $search->with('book');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $search->orderBy('title_relevance', 'desc')->get();
 | 
			
		||||
        return $search->orderBy('title_relevance', 'desc');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -157,7 +157,7 @@ class BookController extends Controller
 | 
			
		|||
        $this->checkPermission('book-update');
 | 
			
		||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
			
		||||
        $bookChildren = $this->bookRepo->getChildren($book);
 | 
			
		||||
        $books = $this->bookRepo->getAll();
 | 
			
		||||
        $books = $this->bookRepo->getAll(false);
 | 
			
		||||
        $this->setPageTitle('Sort Book ' . $book->getShortName());
 | 
			
		||||
        return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books, 'bookChildren' => $bookChildren]);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,25 +3,21 @@
 | 
			
		|||
namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use Activity;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
 | 
			
		||||
use BookStack\Repos\EntityRepo;
 | 
			
		||||
use BookStack\Http\Requests;
 | 
			
		||||
use BookStack\Repos\BookRepo;
 | 
			
		||||
use Views;
 | 
			
		||||
 | 
			
		||||
class HomeController extends Controller
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    protected $activityService;
 | 
			
		||||
    protected $bookRepo;
 | 
			
		||||
    protected $entityRepo;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * HomeController constructor.
 | 
			
		||||
     * @param BookRepo        $bookRepo
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(BookRepo $bookRepo)
 | 
			
		||||
    public function __construct(EntityRepo $entityRepo)
 | 
			
		||||
    {
 | 
			
		||||
        $this->bookRepo = $bookRepo;
 | 
			
		||||
        $this->entityRepo = $entityRepo;
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -33,9 +29,16 @@ class HomeController extends Controller
 | 
			
		|||
     */
 | 
			
		||||
    public function index()
 | 
			
		||||
    {
 | 
			
		||||
        $activity = Activity::latest();
 | 
			
		||||
        $recents = $this->signedIn ? Views::getUserRecentlyViewed(10, 0) : $this->bookRepo->getLatest(10);
 | 
			
		||||
        return view('home', ['activity' => $activity, 'recents' => $recents]);
 | 
			
		||||
        $activity = Activity::latest(10);
 | 
			
		||||
        $recents = $this->signedIn ? Views::getUserRecentlyViewed(12, 0) : $this->entityRepo->getRecentlyCreatedBooks(10);
 | 
			
		||||
        $recentlyCreatedPages = $this->entityRepo->getRecentlyCreatedPages(5);
 | 
			
		||||
        $recentlyUpdatedPages = $this->entityRepo->getRecentlyUpdatedPages(5);
 | 
			
		||||
        return view('home', [
 | 
			
		||||
            'activity' => $activity,
 | 
			
		||||
            'recents' => $recents,
 | 
			
		||||
            'recentlyCreatedPages' => $recentlyCreatedPages,
 | 
			
		||||
            'recentlyUpdatedPages' => $recentlyUpdatedPages
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ use BookStack\Http\Requests;
 | 
			
		|||
use BookStack\Repos\BookRepo;
 | 
			
		||||
use BookStack\Repos\ChapterRepo;
 | 
			
		||||
use BookStack\Repos\PageRepo;
 | 
			
		||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 | 
			
		||||
use Views;
 | 
			
		||||
 | 
			
		||||
class PageController extends Controller
 | 
			
		||||
| 
						 | 
				
			
			@ -81,6 +82,8 @@ class PageController extends Controller
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Display the specified page.
 | 
			
		||||
     * If the page is not found via the slug the
 | 
			
		||||
     * revisions are searched for a match.
 | 
			
		||||
     *
 | 
			
		||||
     * @param $bookSlug
 | 
			
		||||
     * @param $pageSlug
 | 
			
		||||
| 
						 | 
				
			
			@ -89,7 +92,15 @@ class PageController extends Controller
 | 
			
		|||
    public function show($bookSlug, $pageSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
			
		||||
        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
			
		||||
        } catch (NotFoundHttpException $e) {
 | 
			
		||||
            $page = $this->pageRepo->findPageUsingOldSlug($pageSlug, $bookSlug);
 | 
			
		||||
            if ($page === null) abort(404);
 | 
			
		||||
            return redirect($page->getUrl());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $sidebarTree = $this->bookRepo->getChildren($book);
 | 
			
		||||
        Views::add($page);
 | 
			
		||||
        $this->setPageTitle($page->getShortName());
 | 
			
		||||
| 
						 | 
				
			
			@ -278,4 +289,30 @@ class PageController extends Controller
 | 
			
		|||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show a listing of recently created pages
 | 
			
		||||
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
			
		||||
     */
 | 
			
		||||
    public function showRecentlyCreated()
 | 
			
		||||
    {
 | 
			
		||||
        $pages = $this->pageRepo->getRecentlyCreatedPaginated(20);
 | 
			
		||||
        return view('pages/detailed-listing', [
 | 
			
		||||
            'title' => 'Recently Created Pages',
 | 
			
		||||
            'pages' => $pages
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show a listing of recently created pages
 | 
			
		||||
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
			
		||||
     */
 | 
			
		||||
    public function showRecentlyUpdated()
 | 
			
		||||
    {
 | 
			
		||||
        $pages = $this->pageRepo->getRecentlyUpdatedPaginated(20);
 | 
			
		||||
        return view('pages/detailed-listing', [
 | 
			
		||||
            'title' => 'Recently Updated Pages',
 | 
			
		||||
            'pages' => $pages
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,11 +42,77 @@ class SearchController extends Controller
 | 
			
		|||
            return redirect()->back();
 | 
			
		||||
        }
 | 
			
		||||
        $searchTerm = $request->get('term');
 | 
			
		||||
        $pages = $this->pageRepo->getBySearch($searchTerm);
 | 
			
		||||
        $books = $this->bookRepo->getBySearch($searchTerm);
 | 
			
		||||
        $chapters = $this->chapterRepo->getBySearch($searchTerm);
 | 
			
		||||
        $paginationAppends = $request->only('term');
 | 
			
		||||
        $pages = $this->pageRepo->getBySearch($searchTerm, [], 20, $paginationAppends);
 | 
			
		||||
        $books = $this->bookRepo->getBySearch($searchTerm, 10, $paginationAppends);
 | 
			
		||||
        $chapters = $this->chapterRepo->getBySearch($searchTerm, [], 10, $paginationAppends);
 | 
			
		||||
        $this->setPageTitle('Search For ' . $searchTerm);
 | 
			
		||||
        return view('search/all', ['pages' => $pages, 'books' => $books, 'chapters' => $chapters, 'searchTerm' => $searchTerm]);
 | 
			
		||||
        return view('search/all', [
 | 
			
		||||
            'pages' => $pages,
 | 
			
		||||
            'books' => $books,
 | 
			
		||||
            'chapters' => $chapters,
 | 
			
		||||
            'searchTerm' => $searchTerm
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Search only the pages in the system.
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
 | 
			
		||||
     */
 | 
			
		||||
    public function searchPages(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        if (!$request->has('term')) return redirect()->back();
 | 
			
		||||
 | 
			
		||||
        $searchTerm = $request->get('term');
 | 
			
		||||
        $paginationAppends = $request->only('term');
 | 
			
		||||
        $pages = $this->pageRepo->getBySearch($searchTerm, [], 20, $paginationAppends);
 | 
			
		||||
        $this->setPageTitle('Page Search For ' . $searchTerm);
 | 
			
		||||
        return view('search/entity-search-list', [
 | 
			
		||||
            'entities' => $pages,
 | 
			
		||||
            'title' => 'Page Search Results',
 | 
			
		||||
            'searchTerm' => $searchTerm
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Search only the chapters in the system.
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
 | 
			
		||||
     */
 | 
			
		||||
    public function searchChapters(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        if (!$request->has('term')) return redirect()->back();
 | 
			
		||||
 | 
			
		||||
        $searchTerm = $request->get('term');
 | 
			
		||||
        $paginationAppends = $request->only('term');
 | 
			
		||||
        $chapters = $this->chapterRepo->getBySearch($searchTerm, [], 20, $paginationAppends);
 | 
			
		||||
        $this->setPageTitle('Chapter Search For ' . $searchTerm);
 | 
			
		||||
        return view('search/entity-search-list', [
 | 
			
		||||
            'entities' => $chapters,
 | 
			
		||||
            'title' => 'Chapter Search Results',
 | 
			
		||||
            'searchTerm' => $searchTerm
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Search only the books in the system.
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
 | 
			
		||||
     */
 | 
			
		||||
    public function searchBooks(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        if (!$request->has('term')) return redirect()->back();
 | 
			
		||||
 | 
			
		||||
        $searchTerm = $request->get('term');
 | 
			
		||||
        $paginationAppends = $request->only('term');
 | 
			
		||||
        $books = $this->bookRepo->getBySearch($searchTerm, 20, $paginationAppends);
 | 
			
		||||
        $this->setPageTitle('Book Search For ' . $searchTerm);
 | 
			
		||||
        return view('search/entity-search-list', [
 | 
			
		||||
            'entities' => $books,
 | 
			
		||||
            'title' => 'Book Search Results',
 | 
			
		||||
            'searchTerm' => $searchTerm
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use BookStack\Activity;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
| 
						 | 
				
			
			@ -92,10 +93,9 @@ class UserController extends Controller
 | 
			
		|||
            $user->save();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return redirect('/users');
 | 
			
		||||
        return redirect('/settings/users');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show the form for editing the specified user.
 | 
			
		||||
     * @param  int              $id
 | 
			
		||||
| 
						 | 
				
			
			@ -159,7 +159,7 @@ class UserController extends Controller
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        $user->save();
 | 
			
		||||
        return redirect('/users');
 | 
			
		||||
        return redirect('/settings/users');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -197,6 +197,25 @@ class UserController extends Controller
 | 
			
		|||
        }
 | 
			
		||||
        $this->userRepo->destroy($user);
 | 
			
		||||
 | 
			
		||||
        return redirect('/users');
 | 
			
		||||
        return redirect('/settings/users');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show the user profile page
 | 
			
		||||
     * @param $id
 | 
			
		||||
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
			
		||||
     */
 | 
			
		||||
    public function showProfilePage($id)
 | 
			
		||||
    {
 | 
			
		||||
        $user = $this->userRepo->getById($id);
 | 
			
		||||
        $userActivity = $this->userRepo->getActivity($user);
 | 
			
		||||
        $recentlyCreated = $this->userRepo->getRecentlyCreated($user, 5, 0);
 | 
			
		||||
        $assetCounts = $this->userRepo->getAssetCounts($user);
 | 
			
		||||
        return view('users/profile', [
 | 
			
		||||
            'user' => $user,
 | 
			
		||||
            'activity' => $userActivity,
 | 
			
		||||
            'recentlyCreated' => $recentlyCreated,
 | 
			
		||||
            'assetCounts' => $assetCounts
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,11 @@
 | 
			
		|||
// Authenticated routes...
 | 
			
		||||
Route::group(['middleware' => 'auth'], function () {
 | 
			
		||||
 | 
			
		||||
    Route::group(['prefix' => 'pages'], function() {
 | 
			
		||||
        Route::get('/recently-created', 'PageController@showRecentlyCreated');
 | 
			
		||||
        Route::get('/recently-updated', 'PageController@showRecentlyUpdated');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    Route::group(['prefix' => 'books'], function () {
 | 
			
		||||
 | 
			
		||||
        // Books
 | 
			
		||||
| 
						 | 
				
			
			@ -47,14 +52,8 @@ Route::group(['middleware' => 'auth'], function () {
 | 
			
		|||
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Users
 | 
			
		||||
    Route::get('/users', 'UserController@index');
 | 
			
		||||
    Route::get('/users/create', 'UserController@create');
 | 
			
		||||
    Route::get('/users/{id}/delete', 'UserController@delete');
 | 
			
		||||
    Route::post('/users/create', 'UserController@store');
 | 
			
		||||
    Route::get('/users/{id}', 'UserController@edit');
 | 
			
		||||
    Route::put('/users/{id}', 'UserController@update');
 | 
			
		||||
    Route::delete('/users/{id}', 'UserController@destroy');
 | 
			
		||||
    // User Profile routes
 | 
			
		||||
    Route::get('/user/{userId}', 'UserController@showProfilePage');
 | 
			
		||||
 | 
			
		||||
    // Image routes
 | 
			
		||||
    Route::group(['prefix' => 'images'], function() {
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +74,9 @@ Route::group(['middleware' => 'auth'], function () {
 | 
			
		|||
 | 
			
		||||
    // Search
 | 
			
		||||
    Route::get('/search/all', 'SearchController@searchAll');
 | 
			
		||||
    Route::get('/search/pages', 'SearchController@searchPages');
 | 
			
		||||
    Route::get('/search/books', 'SearchController@searchBooks');
 | 
			
		||||
    Route::get('/search/chapters', 'SearchController@searchChapters');
 | 
			
		||||
    Route::get('/search/book/{bookId}', 'SearchController@searchBook');
 | 
			
		||||
 | 
			
		||||
    // Other Pages
 | 
			
		||||
| 
						 | 
				
			
			@ -82,8 +84,18 @@ Route::group(['middleware' => 'auth'], function () {
 | 
			
		|||
    Route::get('/home', 'HomeController@index');
 | 
			
		||||
 | 
			
		||||
    // Settings
 | 
			
		||||
    Route::get('/settings', 'SettingController@index');
 | 
			
		||||
    Route::post('/settings', 'SettingController@update');
 | 
			
		||||
    Route::group(['prefix' => 'settings'], function() {
 | 
			
		||||
        Route::get('/', 'SettingController@index');
 | 
			
		||||
        Route::post('/', 'SettingController@update');
 | 
			
		||||
        // Users
 | 
			
		||||
        Route::get('/users', 'UserController@index');
 | 
			
		||||
        Route::get('/users/create', 'UserController@create');
 | 
			
		||||
        Route::get('/users/{id}/delete', 'UserController@delete');
 | 
			
		||||
        Route::post('/users/create', 'UserController@store');
 | 
			
		||||
        Route::get('/users/{id}', 'UserController@edit');
 | 
			
		||||
        Route::put('/users/{id}', 'UserController@update');
 | 
			
		||||
        Route::delete('/users/{id}', 'UserController@destroy');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,8 @@ class Page extends Entity
 | 
			
		|||
 | 
			
		||||
    public function getExcerpt($length = 100)
 | 
			
		||||
    {
 | 
			
		||||
        return strlen($this->text) > $length ? substr($this->text, 0, $length-3) . '...' : $this->text;
 | 
			
		||||
        $text = strlen($this->text) > $length ? substr($this->text, 0, $length-3) . '...' : $this->text;
 | 
			
		||||
        return mb_convert_encoding($text, 'UTF-8');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,8 +14,8 @@ class BookRepo
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * BookRepo constructor.
 | 
			
		||||
     * @param Book        $book
 | 
			
		||||
     * @param PageRepo    $pageRepo
 | 
			
		||||
     * @param Book $book
 | 
			
		||||
     * @param PageRepo $pageRepo
 | 
			
		||||
     * @param ChapterRepo $chapterRepo
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(Book $book, PageRepo $pageRepo, ChapterRepo $chapterRepo)
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +42,9 @@ class BookRepo
 | 
			
		|||
     */
 | 
			
		||||
    public function getAll($count = 10)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->book->orderBy('name', 'asc')->take($count)->get();
 | 
			
		||||
        $bookQuery = $this->book->orderBy('name', 'asc');
 | 
			
		||||
        if (!$count) return $bookQuery->get();
 | 
			
		||||
        return $bookQuery->take($count)->get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -159,7 +161,7 @@ class BookRepo
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param string     $slug
 | 
			
		||||
     * @param string $slug
 | 
			
		||||
     * @param bool|false $currentId
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -175,7 +177,7 @@ class BookRepo
 | 
			
		|||
    /**
 | 
			
		||||
     * Provides a suitable slug for the given book name.
 | 
			
		||||
     * Ensures the returned slug is unique in the system.
 | 
			
		||||
     * @param string     $name
 | 
			
		||||
     * @param string $name
 | 
			
		||||
     * @param bool|false $currentId
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -218,12 +220,15 @@ class BookRepo
 | 
			
		|||
    /**
 | 
			
		||||
     * Get books by search term.
 | 
			
		||||
     * @param $term
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @param array $paginationAppends
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function getBySearch($term)
 | 
			
		||||
    public function getBySearch($term, $count = 20, $paginationAppends = [])
 | 
			
		||||
    {
 | 
			
		||||
        $terms = explode(' ', $term);
 | 
			
		||||
        $books = $this->book->fullTextSearch(['name', 'description'], $terms);
 | 
			
		||||
        $books = $this->book->fullTextSearchQuery(['name', 'description'], $terms)
 | 
			
		||||
            ->paginate($count)->appends($paginationAppends);
 | 
			
		||||
        $words = join('|', explode(' ', preg_quote(trim($term), '/')));
 | 
			
		||||
        foreach ($books as $book) {
 | 
			
		||||
            //highlight
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -125,12 +125,15 @@ class ChapterRepo
 | 
			
		|||
     * Get chapters by the given search term.
 | 
			
		||||
     * @param       $term
 | 
			
		||||
     * @param array $whereTerms
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @param array $paginationAppends
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function getBySearch($term, $whereTerms = [])
 | 
			
		||||
    public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = [])
 | 
			
		||||
    {
 | 
			
		||||
        $terms = explode(' ', $term);
 | 
			
		||||
        $chapters = $this->chapter->fullTextSearch(['name', 'description'], $terms, $whereTerms);
 | 
			
		||||
        $chapters = $this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms)
 | 
			
		||||
            ->paginate($count)->appends($paginationAppends);
 | 
			
		||||
        $words = join('|', explode(' ', preg_quote(trim($term), '/')));
 | 
			
		||||
        foreach ($chapters as $chapter) {
 | 
			
		||||
            //highlight
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
<?php namespace BookStack\Repos;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
use BookStack\Book;
 | 
			
		||||
use BookStack\Chapter;
 | 
			
		||||
use BookStack\Page;
 | 
			
		||||
 | 
			
		||||
class EntityRepo
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    public $book;
 | 
			
		||||
    public $chapter;
 | 
			
		||||
    public $page;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * EntityService constructor.
 | 
			
		||||
     * @param $book
 | 
			
		||||
     * @param $chapter
 | 
			
		||||
     * @param $page
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(Book $book, Chapter $chapter, Page $page)
 | 
			
		||||
    {
 | 
			
		||||
        $this->book = $book;
 | 
			
		||||
        $this->chapter = $chapter;
 | 
			
		||||
        $this->page = $page;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the latest books added to the system.
 | 
			
		||||
     * @param $count
 | 
			
		||||
     * @param $page
 | 
			
		||||
     */
 | 
			
		||||
    public function getRecentlyCreatedBooks($count = 20, $page = 0)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->book->orderBy('created_at', 'desc')->skip($page*$count)->take($count)->get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the most recently updated books.
 | 
			
		||||
     * @param $count
 | 
			
		||||
     * @param int $page
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function getRecentlyUpdatedBooks($count = 20, $page = 0)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->book->orderBy('updated_at', 'desc')->skip($page*$count)->take($count)->get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the latest pages added to the system.
 | 
			
		||||
     * @param $count
 | 
			
		||||
     * @param $page
 | 
			
		||||
     */
 | 
			
		||||
    public function getRecentlyCreatedPages($count = 20, $page = 0)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->page->orderBy('created_at', 'desc')->skip($page*$count)->take($count)->get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the most recently updated pages.
 | 
			
		||||
     * @param $count
 | 
			
		||||
     * @param int $page
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function getRecentlyUpdatedPages($count = 20, $page = 0)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->page->orderBy('updated_at', 'desc')->skip($page*$count)->take($count)->get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ use Illuminate\Support\Facades\Log;
 | 
			
		|||
use Illuminate\Support\Str;
 | 
			
		||||
use BookStack\Page;
 | 
			
		||||
use BookStack\PageRevision;
 | 
			
		||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 | 
			
		||||
 | 
			
		||||
class PageRepo
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -65,11 +66,28 @@ class PageRepo
 | 
			
		|||
    public function getBySlug($slug, $bookId)
 | 
			
		||||
    {
 | 
			
		||||
        $page = $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
 | 
			
		||||
        if ($page === null) abort(404);
 | 
			
		||||
        if ($page === null) throw new NotFoundHttpException('Page not found');
 | 
			
		||||
        return $page;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Search through page revisions and retrieve
 | 
			
		||||
     * the last page in the current book that
 | 
			
		||||
     * has a slug equal to the one given.
 | 
			
		||||
     * @param $pageSlug
 | 
			
		||||
     * @param $bookSlug
 | 
			
		||||
     * @return null | Page
 | 
			
		||||
     */
 | 
			
		||||
    public function findPageUsingOldSlug($pageSlug, $bookSlug)
 | 
			
		||||
    {
 | 
			
		||||
        $revision = $this->pageRevision->where('slug', '=', $pageSlug)
 | 
			
		||||
            ->where('book_slug', '=', $bookSlug)->orderBy('created_at', 'desc')
 | 
			
		||||
            ->with('page')->first();
 | 
			
		||||
        return $revision !== null ? $revision->page : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a new Page instance from the given input.
 | 
			
		||||
     * @param $input
 | 
			
		||||
     * @return Page
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -125,21 +143,20 @@ class PageRepo
 | 
			
		|||
        if($htmlText == '') return $htmlText;
 | 
			
		||||
        libxml_use_internal_errors(true);
 | 
			
		||||
        $doc = new \DOMDocument();
 | 
			
		||||
        $doc->loadHTML($htmlText);
 | 
			
		||||
        $doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8'));
 | 
			
		||||
 | 
			
		||||
        $container = $doc->documentElement;
 | 
			
		||||
        $body = $container->childNodes->item(0);
 | 
			
		||||
        $childNodes = $body->childNodes;
 | 
			
		||||
 | 
			
		||||
        // Ensure no duplicate ids are used
 | 
			
		||||
        $lastId = false;
 | 
			
		||||
        $idArray = [];
 | 
			
		||||
 | 
			
		||||
        foreach ($childNodes as $index => $childNode) {
 | 
			
		||||
            /** @var \DOMElement $childNode */
 | 
			
		||||
            if (get_class($childNode) !== 'DOMElement') continue;
 | 
			
		||||
 | 
			
		||||
            // Overwrite id if not a bookstack custom id
 | 
			
		||||
            // Overwrite id if not a BookStack custom id
 | 
			
		||||
            if ($childNode->hasAttribute('id')) {
 | 
			
		||||
                $id = $childNode->getAttribute('id');
 | 
			
		||||
                if (strpos($id, 'bkmrk') === 0 && array_search($id, $idArray) === false) {
 | 
			
		||||
| 
						 | 
				
			
			@ -149,13 +166,18 @@ class PageRepo
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            // Create an unique id for the element
 | 
			
		||||
            do {
 | 
			
		||||
                $id = 'bkmrk-' . substr(uniqid(), -5);
 | 
			
		||||
            } while ($id == $lastId);
 | 
			
		||||
            $lastId = $id;
 | 
			
		||||
            // Uses the content as a basis to ensure output is the same every time
 | 
			
		||||
            // the same content is passed through.
 | 
			
		||||
            $contentId = 'bkmrk-' . substr(strtolower(preg_replace('/\s+/', '-', trim($childNode->nodeValue))), 0, 20);
 | 
			
		||||
            $newId = urlencode($contentId);
 | 
			
		||||
            $loopIndex = 0;
 | 
			
		||||
            while (in_array($newId, $idArray)) {
 | 
			
		||||
                $newId = urlencode($contentId . '-' . $loopIndex);
 | 
			
		||||
                $loopIndex++;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $childNode->setAttribute('id', $id);
 | 
			
		||||
            $idArray[] = $id;
 | 
			
		||||
            $childNode->setAttribute('id', $newId);
 | 
			
		||||
            $idArray[] = $newId;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Generate inner html as a string
 | 
			
		||||
| 
						 | 
				
			
			@ -171,14 +193,17 @@ class PageRepo
 | 
			
		|||
    /**
 | 
			
		||||
     * Gets pages by a search term.
 | 
			
		||||
     * Highlights page content for showing in results.
 | 
			
		||||
     * @param string      $term
 | 
			
		||||
     * @param string $term
 | 
			
		||||
     * @param array $whereTerms
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @param array $paginationAppends
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function getBySearch($term, $whereTerms = [])
 | 
			
		||||
    public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = [])
 | 
			
		||||
    {
 | 
			
		||||
        $terms = explode(' ', $term);
 | 
			
		||||
        $pages = $this->page->fullTextSearch(['name', 'text'], $terms, $whereTerms);
 | 
			
		||||
        $pages = $this->page->fullTextSearchQuery(['name', 'text'], $terms, $whereTerms)
 | 
			
		||||
            ->paginate($count)->appends($paginationAppends);
 | 
			
		||||
 | 
			
		||||
        // Add highlights to page text.
 | 
			
		||||
        $words = join('|', explode(' ', preg_quote(trim($term), '/')));
 | 
			
		||||
| 
						 | 
				
			
			@ -238,9 +263,13 @@ class PageRepo
 | 
			
		|||
            $this->saveRevision($page);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Prevent slug being updated if no name change
 | 
			
		||||
        if ($page->name !== $input['name']) {
 | 
			
		||||
            $page->slug = $this->findSuitableSlug($input['name'], $book_id, $page->id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Update with new details
 | 
			
		||||
        $page->fill($input);
 | 
			
		||||
        $page->slug = $this->findSuitableSlug($page->name, $book_id, $page->id);
 | 
			
		||||
        $page->html = $this->formatHtml($input['html']);
 | 
			
		||||
        $page->text = strip_tags($page->html);
 | 
			
		||||
        $page->updated_by = auth()->user()->id;
 | 
			
		||||
| 
						 | 
				
			
			@ -276,6 +305,8 @@ class PageRepo
 | 
			
		|||
    {
 | 
			
		||||
        $revision = $this->pageRevision->fill($page->toArray());
 | 
			
		||||
        $revision->page_id = $page->id;
 | 
			
		||||
        $revision->slug = $page->slug;
 | 
			
		||||
        $revision->book_slug = $page->book->slug;
 | 
			
		||||
        $revision->created_by = auth()->user()->id;
 | 
			
		||||
        $revision->created_at = $page->updated_at;
 | 
			
		||||
        $revision->save();
 | 
			
		||||
| 
						 | 
				
			
			@ -358,5 +389,22 @@ class PageRepo
 | 
			
		|||
        $page->delete();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the latest pages added to the system.
 | 
			
		||||
     * @param $count
 | 
			
		||||
     */
 | 
			
		||||
    public function getRecentlyCreatedPaginated($count = 20)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->page->orderBy('created_at', 'desc')->paginate($count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the latest pages added to the system.
 | 
			
		||||
     * @param $count
 | 
			
		||||
     */
 | 
			
		||||
    public function getRecentlyUpdatedPaginated($count = 20)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->page->orderBy('updated_at', 'desc')->paginate($count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,5 @@
 | 
			
		|||
<?php namespace BookStack\Repos;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
use BookStack\Role;
 | 
			
		||||
use BookStack\User;
 | 
			
		||||
use Setting;
 | 
			
		||||
| 
						 | 
				
			
			@ -10,15 +9,19 @@ class UserRepo
 | 
			
		|||
 | 
			
		||||
    protected $user;
 | 
			
		||||
    protected $role;
 | 
			
		||||
    protected $entityRepo;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * UserRepo constructor.
 | 
			
		||||
     * @param $user
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param Role $role
 | 
			
		||||
     * @param EntityRepo $entityRepo
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(User $user, Role $role)
 | 
			
		||||
    public function __construct(User $user, Role $role, EntityRepo $entityRepo)
 | 
			
		||||
    {
 | 
			
		||||
        $this->user = $user;
 | 
			
		||||
        $this->role = $role;
 | 
			
		||||
        $this->entityRepo = $entityRepo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -112,4 +115,49 @@ class UserRepo
 | 
			
		|||
        $user->socialAccounts()->delete();
 | 
			
		||||
        $user->delete();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the latest activity for a user.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @param int $page
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function getActivity(User $user, $count = 20, $page = 0)
 | 
			
		||||
    {
 | 
			
		||||
        return \Activity::userActivity($user, $count, $page);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the recently created content for this given user.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function getRecentlyCreated(User $user, $count = 20)
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'pages' => $this->entityRepo->page->where('created_by', '=', $user->id)->orderBy('created_at', 'desc')
 | 
			
		||||
                ->take($count)->get(),
 | 
			
		||||
            'chapters' => $this->entityRepo->chapter->where('created_by', '=', $user->id)->orderBy('created_at', 'desc')
 | 
			
		||||
                ->take($count)->get(),
 | 
			
		||||
            'books' => $this->entityRepo->book->where('created_by', '=', $user->id)->orderBy('created_at', 'desc')
 | 
			
		||||
                ->take($count)->get()
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get asset created counts for the give user.
 | 
			
		||||
     * @param User $user
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function getAssetCounts(User $user)
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'pages' => $this->entityRepo->page->where('created_by', '=', $user->id)->count(),
 | 
			
		||||
            'chapters' => $this->entityRepo->chapter->where('created_by', '=', $user->id)->count(),
 | 
			
		||||
            'books' => $this->entityRepo->book->where('created_by', '=', $user->id)->count(),
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -29,18 +29,19 @@ class ActivityService
 | 
			
		|||
     */
 | 
			
		||||
    public function add(Entity $entity, $activityKey, $bookId = 0, $extra = false)
 | 
			
		||||
    {
 | 
			
		||||
        $this->activity->user_id = $this->user->id;
 | 
			
		||||
        $this->activity->book_id = $bookId;
 | 
			
		||||
        $this->activity->key = strtolower($activityKey);
 | 
			
		||||
        $activity = $this->activity->newInstance();
 | 
			
		||||
        $activity->user_id = $this->user->id;
 | 
			
		||||
        $activity->book_id = $bookId;
 | 
			
		||||
        $activity->key = strtolower($activityKey);
 | 
			
		||||
        if ($extra !== false) {
 | 
			
		||||
            $this->activity->extra = $extra;
 | 
			
		||||
            $activity->extra = $extra;
 | 
			
		||||
        }
 | 
			
		||||
        $entity->activity()->save($this->activity);
 | 
			
		||||
        $entity->activity()->save($activity);
 | 
			
		||||
        $this->setNotification($activityKey);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a activity history with a message & without binding to a entitiy.
 | 
			
		||||
     * Adds a activity history with a message & without binding to a entity.
 | 
			
		||||
     * @param            $activityKey
 | 
			
		||||
     * @param int        $bookId
 | 
			
		||||
     * @param bool|false $extra
 | 
			
		||||
| 
						 | 
				
			
			@ -91,14 +92,14 @@ class ActivityService
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the latest activity for an entitiy, Filtering out similar
 | 
			
		||||
     * Gets the latest activity for an entity, Filtering out similar
 | 
			
		||||
     * items to prevent a message activity list.
 | 
			
		||||
     * @param Entity $entity
 | 
			
		||||
     * @param int    $count
 | 
			
		||||
     * @param int    $page
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    function entityActivity($entity, $count = 20, $page = 0)
 | 
			
		||||
    public function entityActivity($entity, $count = 20, $page = 0)
 | 
			
		||||
    {
 | 
			
		||||
        $activity = $entity->hasMany('BookStack\Activity')->orderBy('created_at', 'desc')
 | 
			
		||||
            ->skip($count * $page)->take($count)->get();
 | 
			
		||||
| 
						 | 
				
			
			@ -107,15 +108,30 @@ class ActivityService
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters out similar activity.
 | 
			
		||||
     * @param Activity[] $activity
 | 
			
		||||
     * Get latest activity for a user, Filtering out similar
 | 
			
		||||
     * items.
 | 
			
		||||
     * @param $user
 | 
			
		||||
     * @param int $count
 | 
			
		||||
     * @param int $page
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    protected function filterSimilar($activity)
 | 
			
		||||
    public function userActivity($user, $count = 20, $page = 0)
 | 
			
		||||
    {
 | 
			
		||||
        $activity = $this->activity->where('user_id', '=', $user->id)
 | 
			
		||||
            ->orderBy('created_at', 'desc')->skip($count * $page)->take($count)->get();
 | 
			
		||||
        return $this->filterSimilar($activity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters out similar activity.
 | 
			
		||||
     * @param Activity[] $activities
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    protected function filterSimilar($activities)
 | 
			
		||||
    {
 | 
			
		||||
        $newActivity = [];
 | 
			
		||||
        $previousItem = false;
 | 
			
		||||
        foreach ($activity as $activityItem) {
 | 
			
		||||
        foreach ($activities as $activityItem) {
 | 
			
		||||
            if ($previousItem === false) {
 | 
			
		||||
                $previousItem = $activityItem;
 | 
			
		||||
                $newActivity[] = $activityItem;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -164,6 +164,6 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
 | 
			
		|||
     */
 | 
			
		||||
    public function getEditUrl()
 | 
			
		||||
    {
 | 
			
		||||
        return '/users/' . $this->id;
 | 
			
		||||
        return '/settings/users/' . $this->id;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,16 +9,16 @@
 | 
			
		|||
    "packages": [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "aws/aws-sdk-php",
 | 
			
		||||
            "version": "3.14.2",
 | 
			
		||||
            "version": "3.15.1",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/aws/aws-sdk-php.git",
 | 
			
		||||
                "reference": "2970cb63e7b7b37dd8c07a4fa4e4e18a110ed4e2"
 | 
			
		||||
                "reference": "5e6078913293576de969703481994b77c380ca30"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2970cb63e7b7b37dd8c07a4fa4e4e18a110ed4e2",
 | 
			
		||||
                "reference": "2970cb63e7b7b37dd8c07a4fa4e4e18a110ed4e2",
 | 
			
		||||
                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5e6078913293576de969703481994b77c380ca30",
 | 
			
		||||
                "reference": "5e6078913293576de969703481994b77c380ca30",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -40,7 +40,8 @@
 | 
			
		|||
                "ext-simplexml": "*",
 | 
			
		||||
                "ext-spl": "*",
 | 
			
		||||
                "nette/neon": "^2.3",
 | 
			
		||||
                "phpunit/phpunit": "~4.0|~5.0"
 | 
			
		||||
                "phpunit/phpunit": "~4.0|~5.0",
 | 
			
		||||
                "psr/cache": "^1.0"
 | 
			
		||||
            },
 | 
			
		||||
            "suggest": {
 | 
			
		||||
                "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications",
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +85,7 @@
 | 
			
		|||
                "s3",
 | 
			
		||||
                "sdk"
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2016-01-28 21:33:18"
 | 
			
		||||
            "time": "2016-02-11 23:23:31"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "barryvdh/laravel-debugbar",
 | 
			
		||||
| 
						 | 
				
			
			@ -918,16 +919,16 @@
 | 
			
		|||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "laravel/framework",
 | 
			
		||||
            "version": "v5.2.12",
 | 
			
		||||
            "version": "v5.2.16",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/laravel/framework.git",
 | 
			
		||||
                "reference": "6b6255ad7bfbdb721b8d00b09d52b146c5d363d7"
 | 
			
		||||
                "reference": "39e89553c124dce266da03ee3c0260bdd62f1848"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/laravel/framework/zipball/6b6255ad7bfbdb721b8d00b09d52b146c5d363d7",
 | 
			
		||||
                "reference": "6b6255ad7bfbdb721b8d00b09d52b146c5d363d7",
 | 
			
		||||
                "url": "https://api.github.com/repos/laravel/framework/zipball/39e89553c124dce266da03ee3c0260bdd62f1848",
 | 
			
		||||
                "reference": "39e89553c124dce266da03ee3c0260bdd62f1848",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -1042,7 +1043,7 @@
 | 
			
		|||
                "framework",
 | 
			
		||||
                "laravel"
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2016-01-26 04:15:37"
 | 
			
		||||
            "time": "2016-02-15 17:46:58"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "laravel/socialite",
 | 
			
		||||
| 
						 | 
				
			
			@ -1629,16 +1630,16 @@
 | 
			
		|||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "paragonie/random_compat",
 | 
			
		||||
            "version": "1.1.6",
 | 
			
		||||
            "version": "v1.2.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/paragonie/random_compat.git",
 | 
			
		||||
                "reference": "e6f80ab77885151908d0ec743689ca700886e8b0"
 | 
			
		||||
                "reference": "b0e69d10852716b2ccbdff69c75c477637220790"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/e6f80ab77885151908d0ec743689ca700886e8b0",
 | 
			
		||||
                "reference": "e6f80ab77885151908d0ec743689ca700886e8b0",
 | 
			
		||||
                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/b0e69d10852716b2ccbdff69c75c477637220790",
 | 
			
		||||
                "reference": "b0e69d10852716b2ccbdff69c75c477637220790",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -1673,7 +1674,7 @@
 | 
			
		|||
                "pseudorandom",
 | 
			
		||||
                "random"
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2016-01-29 16:19:52"
 | 
			
		||||
            "time": "2016-02-06 03:52:05"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "phenx/php-font-lib",
 | 
			
		||||
| 
						 | 
				
			
			@ -2024,16 +2025,16 @@
 | 
			
		|||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/console",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/console.git",
 | 
			
		||||
                "reference": "ebcdc507829df915f4ca23067bd59ee4ef61f6c3"
 | 
			
		||||
                "reference": "5a02eaadaa285e2bb727eb6bbdfb8201fcd971b0"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/console/zipball/ebcdc507829df915f4ca23067bd59ee4ef61f6c3",
 | 
			
		||||
                "reference": "ebcdc507829df915f4ca23067bd59ee4ef61f6c3",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/console/zipball/5a02eaadaa285e2bb727eb6bbdfb8201fcd971b0",
 | 
			
		||||
                "reference": "5a02eaadaa285e2bb727eb6bbdfb8201fcd971b0",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -2080,20 +2081,20 @@
 | 
			
		|||
            ],
 | 
			
		||||
            "description": "Symfony Console Component",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "time": "2015-12-22 10:39:06"
 | 
			
		||||
            "time": "2016-02-02 13:44:19"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/debug",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/debug.git",
 | 
			
		||||
                "reference": "73612266ac709769effdbfc0762e5b07cfd2ac2a"
 | 
			
		||||
                "reference": "29606049ced1ec715475f88d1bbe587252a3476e"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/debug/zipball/73612266ac709769effdbfc0762e5b07cfd2ac2a",
 | 
			
		||||
                "reference": "73612266ac709769effdbfc0762e5b07cfd2ac2a",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/debug/zipball/29606049ced1ec715475f88d1bbe587252a3476e",
 | 
			
		||||
                "reference": "29606049ced1ec715475f88d1bbe587252a3476e",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -2137,20 +2138,20 @@
 | 
			
		|||
            ],
 | 
			
		||||
            "description": "Symfony Debug Component",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "time": "2015-12-26 13:39:53"
 | 
			
		||||
            "time": "2016-01-27 05:14:46"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/event-dispatcher",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/event-dispatcher.git",
 | 
			
		||||
                "reference": "d36355e026905fa5229e1ed7b4e9eda2e67adfcf"
 | 
			
		||||
                "reference": "4dd5df31a28c0f82b41cb1e1599b74b5dcdbdafa"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d36355e026905fa5229e1ed7b4e9eda2e67adfcf",
 | 
			
		||||
                "reference": "d36355e026905fa5229e1ed7b4e9eda2e67adfcf",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4dd5df31a28c0f82b41cb1e1599b74b5dcdbdafa",
 | 
			
		||||
                "reference": "4dd5df31a28c0f82b41cb1e1599b74b5dcdbdafa",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -2197,20 +2198,20 @@
 | 
			
		|||
            ],
 | 
			
		||||
            "description": "Symfony EventDispatcher Component",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "time": "2015-10-30 23:35:59"
 | 
			
		||||
            "time": "2016-01-27 05:14:46"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/finder",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/finder.git",
 | 
			
		||||
                "reference": "8617895eb798b6bdb338321ce19453dc113e5675"
 | 
			
		||||
                "reference": "623bda0abd9aa29e529c8e9c08b3b84171914723"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/finder/zipball/8617895eb798b6bdb338321ce19453dc113e5675",
 | 
			
		||||
                "reference": "8617895eb798b6bdb338321ce19453dc113e5675",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/finder/zipball/623bda0abd9aa29e529c8e9c08b3b84171914723",
 | 
			
		||||
                "reference": "623bda0abd9aa29e529c8e9c08b3b84171914723",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -2246,20 +2247,20 @@
 | 
			
		|||
            ],
 | 
			
		||||
            "description": "Symfony Finder Component",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "time": "2015-12-05 11:13:14"
 | 
			
		||||
            "time": "2016-01-27 05:14:46"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/http-foundation",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/http-foundation.git",
 | 
			
		||||
                "reference": "939c8c28a5b1e4ab7317bc30c1f9aa881c4b06b5"
 | 
			
		||||
                "reference": "9344a87ceedfc50354a39653e54257ee9aa6a77d"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/939c8c28a5b1e4ab7317bc30c1f9aa881c4b06b5",
 | 
			
		||||
                "reference": "939c8c28a5b1e4ab7317bc30c1f9aa881c4b06b5",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9344a87ceedfc50354a39653e54257ee9aa6a77d",
 | 
			
		||||
                "reference": "9344a87ceedfc50354a39653e54257ee9aa6a77d",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -2298,20 +2299,20 @@
 | 
			
		|||
            ],
 | 
			
		||||
            "description": "Symfony HttpFoundation Component",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "time": "2015-12-18 15:43:53"
 | 
			
		||||
            "time": "2016-02-02 13:44:19"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/http-kernel",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/http-kernel.git",
 | 
			
		||||
                "reference": "f7933e9f19e26e7baba7ec04735b466fedd3a6db"
 | 
			
		||||
                "reference": "cec02604450481ac26710ca4249cc61b57b23942"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f7933e9f19e26e7baba7ec04735b466fedd3a6db",
 | 
			
		||||
                "reference": "f7933e9f19e26e7baba7ec04735b466fedd3a6db",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/cec02604450481ac26710ca4249cc61b57b23942",
 | 
			
		||||
                "reference": "cec02604450481ac26710ca4249cc61b57b23942",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -2380,7 +2381,7 @@
 | 
			
		|||
            ],
 | 
			
		||||
            "description": "Symfony HttpKernel Component",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "time": "2015-12-26 16:46:13"
 | 
			
		||||
            "time": "2016-02-03 12:38:44"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/polyfill-mbstring",
 | 
			
		||||
| 
						 | 
				
			
			@ -2551,16 +2552,16 @@
 | 
			
		|||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/process",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/process.git",
 | 
			
		||||
                "reference": "f4794f1d00f0746621be3020ffbd8c5e0b217ee3"
 | 
			
		||||
                "reference": "dfecef47506179db2501430e732adbf3793099c8"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/process/zipball/f4794f1d00f0746621be3020ffbd8c5e0b217ee3",
 | 
			
		||||
                "reference": "f4794f1d00f0746621be3020ffbd8c5e0b217ee3",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/process/zipball/dfecef47506179db2501430e732adbf3793099c8",
 | 
			
		||||
                "reference": "dfecef47506179db2501430e732adbf3793099c8",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -2596,20 +2597,20 @@
 | 
			
		|||
            ],
 | 
			
		||||
            "description": "Symfony Process Component",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "time": "2015-12-23 11:04:02"
 | 
			
		||||
            "time": "2016-02-02 13:44:19"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/routing",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/routing.git",
 | 
			
		||||
                "reference": "3b1bac52f42cb0f54df1a2dbabd55a1d214e2a59"
 | 
			
		||||
                "reference": "4686baa55a835e1c1ede9b86ba02415c8c8d6166"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/routing/zipball/3b1bac52f42cb0f54df1a2dbabd55a1d214e2a59",
 | 
			
		||||
                "reference": "3b1bac52f42cb0f54df1a2dbabd55a1d214e2a59",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/routing/zipball/4686baa55a835e1c1ede9b86ba02415c8c8d6166",
 | 
			
		||||
                "reference": "4686baa55a835e1c1ede9b86ba02415c8c8d6166",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -2670,20 +2671,20 @@
 | 
			
		|||
                "uri",
 | 
			
		||||
                "url"
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2015-12-23 08:00:11"
 | 
			
		||||
            "time": "2016-01-27 05:14:46"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/translation",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/translation.git",
 | 
			
		||||
                "reference": "dff0867826a7068d673801b7522f8e2634016ef9"
 | 
			
		||||
                "reference": "2de0b6f7ebe43cffd8a06996ebec6aab79ea9e91"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/translation/zipball/dff0867826a7068d673801b7522f8e2634016ef9",
 | 
			
		||||
                "reference": "dff0867826a7068d673801b7522f8e2634016ef9",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/translation/zipball/2de0b6f7ebe43cffd8a06996ebec6aab79ea9e91",
 | 
			
		||||
                "reference": "2de0b6f7ebe43cffd8a06996ebec6aab79ea9e91",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -2734,20 +2735,20 @@
 | 
			
		|||
            ],
 | 
			
		||||
            "description": "Symfony Translation Component",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "time": "2015-12-05 17:45:07"
 | 
			
		||||
            "time": "2016-02-02 13:44:19"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/var-dumper",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/var-dumper.git",
 | 
			
		||||
                "reference": "87db8700deb12ba2b65e858f656a1f885530bcb0"
 | 
			
		||||
                "reference": "24bb94807eff00db49374c37ebf56a0304e8aef3"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/87db8700deb12ba2b65e858f656a1f885530bcb0",
 | 
			
		||||
                "reference": "87db8700deb12ba2b65e858f656a1f885530bcb0",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/24bb94807eff00db49374c37ebf56a0304e8aef3",
 | 
			
		||||
                "reference": "24bb94807eff00db49374c37ebf56a0304e8aef3",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -2797,7 +2798,7 @@
 | 
			
		|||
                "debug",
 | 
			
		||||
                "dump"
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2015-12-05 11:13:14"
 | 
			
		||||
            "time": "2016-01-07 13:38:51"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "vlucas/phpdotenv",
 | 
			
		||||
| 
						 | 
				
			
			@ -3182,22 +3183,24 @@
 | 
			
		|||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "phpspec/prophecy",
 | 
			
		||||
            "version": "v1.5.0",
 | 
			
		||||
            "version": "v1.6.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/phpspec/prophecy.git",
 | 
			
		||||
                "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7"
 | 
			
		||||
                "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4745ded9307786b730d7a60df5cb5a6c43cf95f7",
 | 
			
		||||
                "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7",
 | 
			
		||||
                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
 | 
			
		||||
                "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "doctrine/instantiator": "^1.0.2",
 | 
			
		||||
                "php": "^5.3|^7.0",
 | 
			
		||||
                "phpdocumentor/reflection-docblock": "~2.0",
 | 
			
		||||
                "sebastian/comparator": "~1.1"
 | 
			
		||||
                "sebastian/comparator": "~1.1",
 | 
			
		||||
                "sebastian/recursion-context": "~1.0"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "phpspec/phpspec": "~2.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -3205,7 +3208,7 @@
 | 
			
		|||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.4.x-dev"
 | 
			
		||||
                    "dev-master": "1.5.x-dev"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
| 
						 | 
				
			
			@ -3238,7 +3241,7 @@
 | 
			
		|||
                "spy",
 | 
			
		||||
                "stub"
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2015-08-13 10:07:40"
 | 
			
		||||
            "time": "2016-02-15 07:46:21"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "phpunit/php-code-coverage",
 | 
			
		||||
| 
						 | 
				
			
			@ -3482,16 +3485,16 @@
 | 
			
		|||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "phpunit/phpunit",
 | 
			
		||||
            "version": "4.8.21",
 | 
			
		||||
            "version": "4.8.23",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/sebastianbergmann/phpunit.git",
 | 
			
		||||
                "reference": "ea76b17bced0500a28098626b84eda12dbcf119c"
 | 
			
		||||
                "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea76b17bced0500a28098626b84eda12dbcf119c",
 | 
			
		||||
                "reference": "ea76b17bced0500a28098626b84eda12dbcf119c",
 | 
			
		||||
                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6e351261f9cd33daf205a131a1ba61c6d33bd483",
 | 
			
		||||
                "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -3550,7 +3553,7 @@
 | 
			
		|||
                "testing",
 | 
			
		||||
                "xunit"
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2015-12-12 07:45:58"
 | 
			
		||||
            "time": "2016-02-11 14:56:33"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "phpunit/phpunit-mock-objects",
 | 
			
		||||
| 
						 | 
				
			
			@ -3981,16 +3984,16 @@
 | 
			
		|||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/css-selector",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/css-selector.git",
 | 
			
		||||
                "reference": "4613311fd46e146f506403ce2f8a0c71d402d2a3"
 | 
			
		||||
                "reference": "6605602690578496091ac20ec7a5cbd160d4dff4"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/css-selector/zipball/4613311fd46e146f506403ce2f8a0c71d402d2a3",
 | 
			
		||||
                "reference": "4613311fd46e146f506403ce2f8a0c71d402d2a3",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/css-selector/zipball/6605602690578496091ac20ec7a5cbd160d4dff4",
 | 
			
		||||
                "reference": "6605602690578496091ac20ec7a5cbd160d4dff4",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -4030,20 +4033,20 @@
 | 
			
		|||
            ],
 | 
			
		||||
            "description": "Symfony CssSelector Component",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "time": "2015-12-05 17:45:07"
 | 
			
		||||
            "time": "2016-01-27 05:14:46"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/dom-crawler",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/dom-crawler.git",
 | 
			
		||||
                "reference": "7c622b0c9fb8bdb146d6dfa86c5f91dcbfdbc11d"
 | 
			
		||||
                "reference": "b693a9650aa004576b593ff2e91ae749dc90123d"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/7c622b0c9fb8bdb146d6dfa86c5f91dcbfdbc11d",
 | 
			
		||||
                "reference": "7c622b0c9fb8bdb146d6dfa86c5f91dcbfdbc11d",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b693a9650aa004576b593ff2e91ae749dc90123d",
 | 
			
		||||
                "reference": "b693a9650aa004576b593ff2e91ae749dc90123d",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -4086,20 +4089,20 @@
 | 
			
		|||
            ],
 | 
			
		||||
            "description": "Symfony DomCrawler Component",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "time": "2015-12-26 13:42:31"
 | 
			
		||||
            "time": "2016-01-25 09:56:57"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/yaml",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "version": "v3.0.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/yaml.git",
 | 
			
		||||
                "reference": "3df409958a646dad2bc5046c3fb671ee24a1a691"
 | 
			
		||||
                "reference": "3cf0709d7fe936e97bee9e954382e449003f1d9a"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/yaml/zipball/3df409958a646dad2bc5046c3fb671ee24a1a691",
 | 
			
		||||
                "reference": "3df409958a646dad2bc5046c3fb671ee24a1a691",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/yaml/zipball/3cf0709d7fe936e97bee9e954382e449003f1d9a",
 | 
			
		||||
                "reference": "3cf0709d7fe936e97bee9e954382e449003f1d9a",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
| 
						 | 
				
			
			@ -4135,7 +4138,7 @@
 | 
			
		|||
            ],
 | 
			
		||||
            "description": "Symfony Yaml Component",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "time": "2015-12-26 13:39:53"
 | 
			
		||||
            "time": "2016-02-02 13:44:19"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "aliases": [],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ class CreateUsersTable extends Migration
 | 
			
		|||
            $table->string('email')->unique();
 | 
			
		||||
            $table->string('password', 60);
 | 
			
		||||
            $table->rememberToken();
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        \BookStack\User::forceCreate([
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ class CreateBooksTable extends Migration
 | 
			
		|||
            $table->string('name');
 | 
			
		||||
            $table->string('slug')->indexed();
 | 
			
		||||
            $table->text('description');
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ class CreatePagesTable extends Migration
 | 
			
		|||
            $table->longText('html');
 | 
			
		||||
            $table->longText('text');
 | 
			
		||||
            $table->integer('priority');
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ class CreateImagesTable extends Migration
 | 
			
		|||
            $table->increments('id');
 | 
			
		||||
            $table->string('name');
 | 
			
		||||
            $table->string('url');
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ class CreateChaptersTable extends Migration
 | 
			
		|||
            $table->text('name');
 | 
			
		||||
            $table->text('description');
 | 
			
		||||
            $table->integer('priority');
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ class CreatePageRevisionsTable extends Migration
 | 
			
		|||
            $table->longText('html');
 | 
			
		||||
            $table->longText('text');
 | 
			
		||||
            $table->integer('created_by');
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ class CreateActivitiesTable extends Migration
 | 
			
		|||
            $table->integer('user_id');
 | 
			
		||||
            $table->integer('entity_id');
 | 
			
		||||
            $table->string('entity_type');
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ class AddRolesAndPermissions extends Migration
 | 
			
		|||
            $table->string('name')->unique();
 | 
			
		||||
            $table->string('display_name')->nullable();
 | 
			
		||||
            $table->string('description')->nullable();
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Create table for associating roles to users (Many-to-Many)
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ class AddRolesAndPermissions extends Migration
 | 
			
		|||
            $table->string('name')->unique();
 | 
			
		||||
            $table->string('display_name')->nullable();
 | 
			
		||||
            $table->string('description')->nullable();
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Create table for associating permissions to roles (Many-to-Many)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ class CreateSettingsTable extends Migration
 | 
			
		|||
        Schema::create('settings', function (Blueprint $table) {
 | 
			
		||||
            $table->string('setting_key')->primary()->indexed();
 | 
			
		||||
            $table->text('value');
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ class CreateSocialAccountsTable extends Migration
 | 
			
		|||
            $table->string('driver')->index();
 | 
			
		||||
            $table->string('driver_id');
 | 
			
		||||
            $table->string('avatar');
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ class AddEmailConfirmationTable extends Migration
 | 
			
		|||
            $table->increments('id');
 | 
			
		||||
            $table->integer('user_id')->index();
 | 
			
		||||
            $table->string('token')->index();
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ class CreateViewsTable extends Migration
 | 
			
		|||
            $table->integer('viewable_id');
 | 
			
		||||
            $table->string('viewable_type');
 | 
			
		||||
            $table->integer('views');
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->nullableTimestamps();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
 | 
			
		||||
class AddSlugToRevisions extends Migration
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Run the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function up()
 | 
			
		||||
    {
 | 
			
		||||
        Schema::table('page_revisions', function (Blueprint $table) {
 | 
			
		||||
            $table->string('slug');
 | 
			
		||||
            $table->index('slug');
 | 
			
		||||
            $table->string('book_slug');
 | 
			
		||||
            $table->index('book_slug');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverse the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function down()
 | 
			
		||||
    {
 | 
			
		||||
        Schema::table('page_revisions', function (Blueprint $table) {
 | 
			
		||||
            $table->dropColumn('slug');
 | 
			
		||||
            $table->dropColumn('book_slug');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -25,8 +25,13 @@
 | 
			
		|||
        <env name="SESSION_DRIVER" value="array"/>
 | 
			
		||||
        <env name="QUEUE_DRIVER" value="sync"/>
 | 
			
		||||
        <env name="DB_CONNECTION" value="mysql_testing"/>
 | 
			
		||||
        <env name="MAIL_PRETEND" value="true"/>
 | 
			
		||||
        <env name="MAIL_DRIVER" value="log"/>
 | 
			
		||||
        <env name="AUTH_METHOD" value="standard"/>
 | 
			
		||||
        <env name="DISABLE_EXTERNAL_SERVICES" value="false"/>
 | 
			
		||||
        <env name="LDAP_VERSION" value="3"/>
 | 
			
		||||
        <env name="GITHUB_APP_ID" value="aaaaaaaaaaaaaa"/>
 | 
			
		||||
        <env name="GITHUB_APP_SECRET" value="aaaaaaaaaaaaaa"/>
 | 
			
		||||
        <env name="GOOGLE_APP_ID" value="aaaaaaaaaaaaaa"/>
 | 
			
		||||
        <env name="GOOGLE_APP_SECRET" value="aaaaaaaaaaaaaa"/>
 | 
			
		||||
    </php>
 | 
			
		||||
</phpunit>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -106,6 +106,12 @@ $(function () {
 | 
			
		|||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Common jQuery actions
 | 
			
		||||
    $('[data-action="expand-entity-list-details"]').click(function() {
 | 
			
		||||
        $('.entity-list.compact').find('p').slideToggle(240);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -139,54 +139,6 @@ form.search-box {
 | 
			
		|||
  height: 43px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  vertical-align: top;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container ul {
 | 
			
		||||
  display: none;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  z-index: 999;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  list-style: none;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  margin: $-m 0;
 | 
			
		||||
  background-color: #FFFFFF;
 | 
			
		||||
  box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.1);
 | 
			
		||||
  border-radius: 1px;
 | 
			
		||||
  border: 1px solid #EEE;
 | 
			
		||||
  min-width: 180px;
 | 
			
		||||
  padding: $-xs 0;
 | 
			
		||||
  color: #555;
 | 
			
		||||
  text-align: left !important;
 | 
			
		||||
  &.wide {
 | 
			
		||||
    min-width: 220px;
 | 
			
		||||
  }
 | 
			
		||||
  .text-muted {
 | 
			
		||||
    color: #999;
 | 
			
		||||
  }
 | 
			
		||||
  a {
 | 
			
		||||
    display: block;
 | 
			
		||||
    padding: $-xs $-m;
 | 
			
		||||
    color: #555;
 | 
			
		||||
    &:hover {
 | 
			
		||||
      text-decoration: none;
 | 
			
		||||
      background-color: #EEE;
 | 
			
		||||
    }
 | 
			
		||||
    i {
 | 
			
		||||
      margin-right: $-m;
 | 
			
		||||
      padding-right: 0;
 | 
			
		||||
      display: inline;
 | 
			
		||||
      width: 22px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  li.border-bottom {
 | 
			
		||||
    border-bottom: 1px solid #DDD;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.breadcrumbs span.sep {
 | 
			
		||||
  color: #aaa;
 | 
			
		||||
  padding: 0 $-xs;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -283,4 +283,87 @@ ul.pagination {
 | 
			
		|||
  a {
 | 
			
		||||
    color: $primary;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.entity-list {
 | 
			
		||||
  >div {
 | 
			
		||||
    padding: $-m 0;
 | 
			
		||||
  }
 | 
			
		||||
  h3 {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
  }
 | 
			
		||||
  p {
 | 
			
		||||
    margin: $-xs 0 0 0;
 | 
			
		||||
  }
 | 
			
		||||
  hr {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .text-small.text-muted {
 | 
			
		||||
    color: #AAA;
 | 
			
		||||
    font-size: 0.75em;
 | 
			
		||||
    margin-top: $-xs;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.entity-list.compact {
 | 
			
		||||
  font-size: 0.6em;
 | 
			
		||||
  h3, a {
 | 
			
		||||
    line-height: 1.2;
 | 
			
		||||
  }
 | 
			
		||||
  p {
 | 
			
		||||
    display: none;
 | 
			
		||||
    font-size: $fs-m * 0.8;
 | 
			
		||||
    padding-top: $-xs;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
  }
 | 
			
		||||
  hr {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  vertical-align: top;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container ul {
 | 
			
		||||
  display: none;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  z-index: 999;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  list-style: none;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  margin: $-m 0;
 | 
			
		||||
  background-color: #FFFFFF;
 | 
			
		||||
  box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.1);
 | 
			
		||||
  border-radius: 1px;
 | 
			
		||||
  border: 1px solid #EEE;
 | 
			
		||||
  min-width: 180px;
 | 
			
		||||
  padding: $-xs 0;
 | 
			
		||||
  color: #555;
 | 
			
		||||
  text-align: left !important;
 | 
			
		||||
  &.wide {
 | 
			
		||||
    min-width: 220px;
 | 
			
		||||
  }
 | 
			
		||||
  .text-muted {
 | 
			
		||||
    color: #999;
 | 
			
		||||
  }
 | 
			
		||||
  a {
 | 
			
		||||
    display: block;
 | 
			
		||||
    padding: $-xs $-m;
 | 
			
		||||
    color: #555;
 | 
			
		||||
    &:hover {
 | 
			
		||||
      text-decoration: none;
 | 
			
		||||
      background-color: #EEE;
 | 
			
		||||
    }
 | 
			
		||||
    i {
 | 
			
		||||
      margin-right: $-m;
 | 
			
		||||
      padding-right: 0;
 | 
			
		||||
      display: inline;
 | 
			
		||||
      width: 22px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  li.border-bottom {
 | 
			
		||||
    border-bottom: 1px solid #DDD;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,7 +100,7 @@
 | 
			
		|||
    background-color: #FFF;
 | 
			
		||||
    border: 1px solid #DDD;
 | 
			
		||||
    color: #666;
 | 
			
		||||
    width: 180px;
 | 
			
		||||
    width: 172px;
 | 
			
		||||
    z-index: 40;
 | 
			
		||||
  }
 | 
			
		||||
  input, button {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,4 +20,8 @@ table.table {
 | 
			
		|||
 | 
			
		||||
table {
 | 
			
		||||
  max-width: 100%;
 | 
			
		||||
  thead {
 | 
			
		||||
    background-color: #F8F8F8;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +115,8 @@ pre {
 | 
			
		|||
  box-shadow: 0 1px 2px 0px rgba(10, 10, 10, 0.06);
 | 
			
		||||
  border: 1px solid rgba(221, 221, 221, 0.66);
 | 
			
		||||
  background-color: #fdf6e3;
 | 
			
		||||
  padding: 0.5em;
 | 
			
		||||
  padding: $-s;
 | 
			
		||||
  overflow-x: scroll;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
blockquote {
 | 
			
		||||
| 
						 | 
				
			
			@ -251,6 +252,18 @@ ol {
 | 
			
		|||
  text-align: right;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text-bigger {
 | 
			
		||||
  font-size: 1.1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text-large {
 | 
			
		||||
  font-size: 1.6666em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.no-color {
 | 
			
		||||
  color: inherit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Grouping
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,6 +47,13 @@ body.dragging, body.dragging * {
 | 
			
		|||
    width: 80px;
 | 
			
		||||
    height: 80px;
 | 
			
		||||
  }
 | 
			
		||||
  &.huge {
 | 
			
		||||
    width: 120px;
 | 
			
		||||
    height: 120px;
 | 
			
		||||
  }
 | 
			
		||||
  &.square {
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// System wide notifications
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,10 +58,13 @@
 | 
			
		|||
                                </span>
 | 
			
		||||
                                <ul>
 | 
			
		||||
                                    <li>
 | 
			
		||||
                                        <a href="/users/{{$currentUser->id}}" class="text-primary"><i class="zmdi zmdi-edit zmdi-hc-lg"></i>Edit Profile</a>
 | 
			
		||||
                                        <a href="/user/{{$currentUser->id}}" class="text-primary"><i class="zmdi zmdi-account zmdi-hc-fw zmdi-hc-lg"></i>View Profile</a>
 | 
			
		||||
                                    </li>
 | 
			
		||||
                                    <li>
 | 
			
		||||
                                        <a href="/logout" class="text-neg"><i class="zmdi zmdi-run zmdi-hc-lg"></i>Logout</a>
 | 
			
		||||
                                        <a href="/settings/users/{{$currentUser->id}}" class="text-primary"><i class="zmdi zmdi-edit zmdi-hc-fw zmdi-hc-lg"></i>Edit Profile</a>
 | 
			
		||||
                                    </li>
 | 
			
		||||
                                    <li>
 | 
			
		||||
                                        <a href="/logout" class="text-neg"><i class="zmdi zmdi-run zmdi-hc-fw zmdi-hc-lg"></i>Logout</a>
 | 
			
		||||
                                    </li>
 | 
			
		||||
                                </ul>
 | 
			
		||||
                            </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
        <p class="text-muted">{{ $chapter->getExcerpt() }}</p>
 | 
			
		||||
    @endif
 | 
			
		||||
 | 
			
		||||
    @if(count($chapter->pages) > 0 && !isset($hidePages))
 | 
			
		||||
    @if(!isset($hidePages) && count($chapter->pages) > 0)
 | 
			
		||||
        <p class="text-muted chapter-toggle"><i class="zmdi zmdi-caret-right"></i> <i class="zmdi zmdi-file-text"></i> <span>{{ count($chapter->pages) }} Pages</span></p>
 | 
			
		||||
        <div class="inset-list">
 | 
			
		||||
            @foreach($chapter->pages as $page)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,20 +2,44 @@
 | 
			
		|||
 | 
			
		||||
@section('content')
 | 
			
		||||
 | 
			
		||||
    <div class="faded-small toolbar">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
            <div class="row">
 | 
			
		||||
                <div class="col-sm-4 faded">
 | 
			
		||||
                    <div class="action-buttons text-left">
 | 
			
		||||
                        <a data-action="expand-entity-list-details" class="text-primary text-button"><i class="zmdi zmdi-wrap-text"></i>Toggle Details</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="col-sm-8 faded">
 | 
			
		||||
                    <div class="action-buttons">
 | 
			
		||||
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="container" ng-non-bindable>
 | 
			
		||||
        <div class="row">
 | 
			
		||||
 | 
			
		||||
            <div class="col-md-7">
 | 
			
		||||
            <div class="col-sm-4">
 | 
			
		||||
                @if($signedIn)
 | 
			
		||||
                    <h2>My Recently Viewed</h2>
 | 
			
		||||
                    <h3>My Recently Viewed</h3>
 | 
			
		||||
                @else
 | 
			
		||||
                    <h2>Recent Books</h2>
 | 
			
		||||
                    <h3>Recent Books</h3>
 | 
			
		||||
                @endif
 | 
			
		||||
                @include('partials/entity-list', ['entities' => $recents])
 | 
			
		||||
                @include('partials/entity-list', ['entities' => $recents, 'style' => 'compact'])
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="col-md-4 col-md-offset-1">
 | 
			
		||||
                <div class="margin-top large"> </div>
 | 
			
		||||
            <div class="col-sm-4">
 | 
			
		||||
                <h3><a class="no-color" href="/pages/recently-created">Recently Created Pages</a></h3>
 | 
			
		||||
                @include('partials/entity-list', ['entities' => $recentlyCreatedPages, 'style' => 'compact'])
 | 
			
		||||
 | 
			
		||||
                <h3><a class="no-color" href="/pages/recently-updated">Recently Updated Pages</a></h3>
 | 
			
		||||
                @include('partials/entity-list', ['entities' => $recentlyCreatedPages, 'style' => 'compact'])
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="col-sm-4" id="recent-activity">
 | 
			
		||||
                <h3>Recent Activity</h3>
 | 
			
		||||
                @include('partials/activity-list', ['activity' => $activity])
 | 
			
		||||
            </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
@extends('base')
 | 
			
		||||
 | 
			
		||||
@section('content')
 | 
			
		||||
 | 
			
		||||
    <div class="container">
 | 
			
		||||
        <div class="row">
 | 
			
		||||
 | 
			
		||||
            <div class="col-sm-7">
 | 
			
		||||
                <h1>{{ $title }}</h1>
 | 
			
		||||
                @include('partials/entity-list', ['entities' => $pages, 'style' => 'detailed'])
 | 
			
		||||
                {!! $pages->links() !!}
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="col-sm-4 col-sm-offset-1"></div>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@stop
 | 
			
		||||
| 
						 | 
				
			
			@ -3,18 +3,29 @@
 | 
			
		|||
        <a href="{{ $page->getUrl() }}" class="text-page"><i class="zmdi zmdi-file-text"></i>{{ $page->name }}</a>
 | 
			
		||||
    </h3>
 | 
			
		||||
 | 
			
		||||
    @if(isset($showMeta) && $showMeta)
 | 
			
		||||
        <div class="meta">
 | 
			
		||||
            <span class="text-book"><i class="zmdi zmdi-book"></i> {{ $page->book->name }}</span>
 | 
			
		||||
            @if($page->chapter)
 | 
			
		||||
                <span class="text-chapter"><i class="zmdi zmdi-collection-bookmark"></i> {{ $page->chapter->name }}</span>
 | 
			
		||||
            @endif
 | 
			
		||||
         </div>
 | 
			
		||||
    @endif
 | 
			
		||||
 | 
			
		||||
    @if(isset($page->searchSnippet))
 | 
			
		||||
        <p class="text-muted">{!! $page->searchSnippet !!}</p>
 | 
			
		||||
    @else
 | 
			
		||||
        <p class="text-muted">{{ $page->getExcerpt() }}</p>
 | 
			
		||||
    @endif
 | 
			
		||||
 | 
			
		||||
    @if(isset($style) && $style === 'detailed')
 | 
			
		||||
        <div class="row meta text-muted text-small">
 | 
			
		||||
            <div class="col-md-4">
 | 
			
		||||
                Created {{$page->created_at->diffForHumans()}} @if($page->createdBy)by {{$page->createdBy->name}}@endif <br>
 | 
			
		||||
                Last updated {{ $page->updated_at->diffForHumans() }} @if($page->updatedBy)by {{$page->updatedBy->name}} @endif
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-md-8">
 | 
			
		||||
                <a class="text-book" href="{{ $page->book->getUrl() }}"><i class="zmdi zmdi-book"></i>{{ $page->book->getShortName(30) }}</a>
 | 
			
		||||
                <br>
 | 
			
		||||
                @if($page->chapter)
 | 
			
		||||
                    <a class="text-chapter" href="{{ $page->chapter->getUrl() }}"><i class="zmdi zmdi-collection-bookmark"></i>{{ $page->chapter->getShortName(30) }}</a>
 | 
			
		||||
                @else
 | 
			
		||||
                    <i class="zmdi zmdi-collection-bookmark"></i> Page is not in a chapter
 | 
			
		||||
                @endif
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    @endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			@ -9,7 +9,7 @@
 | 
			
		|||
 | 
			
		||||
<div class="right" ng-non-bindable>
 | 
			
		||||
    @if($activity->user)
 | 
			
		||||
        {{$activity->user->name}}
 | 
			
		||||
        <a href="/user/{{ $activity->user->id }}">{{$activity->user->name}}</a>
 | 
			
		||||
    @else
 | 
			
		||||
        A deleted user
 | 
			
		||||
    @endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,21 +1,23 @@
 | 
			
		|||
 | 
			
		||||
@if(count($entities) > 0)
 | 
			
		||||
    @foreach($entities as $index => $entity)
 | 
			
		||||
        @if($entity->isA('page'))
 | 
			
		||||
            @include('pages/list-item', ['page' => $entity])
 | 
			
		||||
        @elseif($entity->isA('book'))
 | 
			
		||||
            @include('books/list-item', ['book' => $entity])
 | 
			
		||||
        @elseif($entity->isA('chapter'))
 | 
			
		||||
            @include('chapters/list-item', ['chapter' => $entity, 'hidePages' => true])
 | 
			
		||||
        @endif
 | 
			
		||||
<div class="entity-list @if(isset($style)){{ $style }}@endif" ng-non-bindable>
 | 
			
		||||
    @if(count($entities) > 0)
 | 
			
		||||
        @foreach($entities as $index => $entity)
 | 
			
		||||
            @if($entity->isA('page'))
 | 
			
		||||
                @include('pages/list-item', ['page' => $entity])
 | 
			
		||||
            @elseif($entity->isA('book'))
 | 
			
		||||
                @include('books/list-item', ['book' => $entity])
 | 
			
		||||
            @elseif($entity->isA('chapter'))
 | 
			
		||||
                @include('chapters/list-item', ['chapter' => $entity, 'hidePages' => true])
 | 
			
		||||
            @endif
 | 
			
		||||
 | 
			
		||||
        @if($index !== count($entities) - 1)
 | 
			
		||||
            <hr>
 | 
			
		||||
        @endif
 | 
			
		||||
            @if($index !== count($entities) - 1)
 | 
			
		||||
                <hr>
 | 
			
		||||
            @endif
 | 
			
		||||
 | 
			
		||||
    @endforeach
 | 
			
		||||
@else
 | 
			
		||||
    <p class="text-muted">
 | 
			
		||||
        No items available
 | 
			
		||||
    </p>
 | 
			
		||||
@endif
 | 
			
		||||
        @endforeach
 | 
			
		||||
    @else
 | 
			
		||||
        <p class="text-muted">
 | 
			
		||||
            No items available
 | 
			
		||||
        </p>
 | 
			
		||||
    @endif
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			@ -6,41 +6,36 @@
 | 
			
		|||
 | 
			
		||||
        <h1>Search Results    <span class="text-muted">{{$searchTerm}}</span></h1>
 | 
			
		||||
 | 
			
		||||
        <p>
 | 
			
		||||
            <a href="/search/pages?term={{$searchTerm}}" class="text-page"><i class="zmdi zmdi-file-text"></i>View all matched pages</a>
 | 
			
		||||
 | 
			
		||||
            @if(count($chapters) > 0)
 | 
			
		||||
                    
 | 
			
		||||
                <a href="/search/chapters?term={{$searchTerm}}" class="text-chapter"><i class="zmdi zmdi-collection-bookmark"></i>View all matched chapters</a>
 | 
			
		||||
            @endif
 | 
			
		||||
 | 
			
		||||
            @if(count($books) > 0)
 | 
			
		||||
                    
 | 
			
		||||
                <a href="/search/books?term={{$searchTerm}}" class="text-book"><i class="zmdi zmdi-book"></i>View all matched books</a>
 | 
			
		||||
            @endif
 | 
			
		||||
        </p>
 | 
			
		||||
        <div class="row">
 | 
			
		||||
 | 
			
		||||
            <div class="col-md-6">
 | 
			
		||||
                <h3>Matching Pages</h3>
 | 
			
		||||
                <div class="page-list">
 | 
			
		||||
                    @if(count($pages) > 0)
 | 
			
		||||
                        @foreach($pages as $page)
 | 
			
		||||
                            @include('pages/list-item', ['page' => $page, 'showMeta' => true])
 | 
			
		||||
                            <hr>
 | 
			
		||||
                        @endforeach
 | 
			
		||||
                    @else
 | 
			
		||||
                        <p class="text-muted">No pages matched this search</p>
 | 
			
		||||
                    @endif
 | 
			
		||||
                </div>
 | 
			
		||||
                <h3><a href="/search/pages?term={{$searchTerm}}" class="no-color">Matching Pages</a></h3>
 | 
			
		||||
                @include('partials/entity-list', ['entities' => $pages, 'style' => 'detailed'])
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="col-md-5 col-md-offset-1">
 | 
			
		||||
 | 
			
		||||
                @if(count($books) > 0)
 | 
			
		||||
                    <h3>Matching Books</h3>
 | 
			
		||||
                    <div class="page-list">
 | 
			
		||||
                        @foreach($books as $book)
 | 
			
		||||
                            @include('books/list-item', ['book' => $book])
 | 
			
		||||
                            <hr>
 | 
			
		||||
                        @endforeach
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <h3><a href="/search/books?term={{$searchTerm}}" class="no-color">Matching Books</a></h3>
 | 
			
		||||
                    @include('partials/entity-list', ['entities' => $books])
 | 
			
		||||
                @endif
 | 
			
		||||
 | 
			
		||||
                @if(count($chapters) > 0)
 | 
			
		||||
                    <h3>Matching Chapters</h3>
 | 
			
		||||
                    <div class="page-list">
 | 
			
		||||
                        @foreach($chapters as $chapter)
 | 
			
		||||
                            @include('chapters/list-item', ['chapter' => $chapter, 'hidePages' => true])
 | 
			
		||||
                        @endforeach
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <h3><a href="/search/chapters?term={{$searchTerm}}" class="no-color">Matching Chapters</a></h3>
 | 
			
		||||
                    @include('partials/entity-list', ['entities' => $chapters])
 | 
			
		||||
                @endif
 | 
			
		||||
 | 
			
		||||
            </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
@extends('base')
 | 
			
		||||
 | 
			
		||||
@section('content')
 | 
			
		||||
 | 
			
		||||
    <div class="container">
 | 
			
		||||
        <div class="row">
 | 
			
		||||
 | 
			
		||||
            <div class="col-sm-7">
 | 
			
		||||
                <h1>{{ $title }} <small>{{$searchTerm}}</small></h1>
 | 
			
		||||
                @include('partials.entity-list', ['entities' => $entities, 'style' => 'detailed'])
 | 
			
		||||
                {!! $entities->links() !!}
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="col-sm-4 col-sm-offset-1"></div>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@stop
 | 
			
		||||
| 
						 | 
				
			
			@ -4,7 +4,7 @@
 | 
			
		|||
        <div class="row">
 | 
			
		||||
            <div class="col-md-12 setting-nav">
 | 
			
		||||
                <a href="/settings" @if($selected == 'settings') class="selected text-button" @endif><i class="zmdi zmdi-settings"></i>Settings</a>
 | 
			
		||||
                <a href="/users" @if($selected == 'users') class="selected text-button" @endif><i class="zmdi zmdi-accounts"></i>Users</a>
 | 
			
		||||
                <a href="/settings/users" @if($selected == 'users') class="selected text-button" @endif><i class="zmdi zmdi-accounts"></i>Users</a>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@
 | 
			
		|||
    <div class="container small" ng-non-bindable>
 | 
			
		||||
        <h1>Create User</h1>
 | 
			
		||||
 | 
			
		||||
        <form action="/users/create" method="post">
 | 
			
		||||
        <form action="/settings/users/create" method="post">
 | 
			
		||||
            {!! csrf_field() !!}
 | 
			
		||||
            @include('users.forms.' . $authMethod)
 | 
			
		||||
        </form>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@
 | 
			
		|||
        <p>This will fully delete this user with the name '<span class="text-neg">{{$user->name}}</span>' from the system.</p>
 | 
			
		||||
        <p class="text-neg">Are you sure you want to delete this user?</p>
 | 
			
		||||
 | 
			
		||||
        <form action="/users/{{$user->id}}" method="POST">
 | 
			
		||||
        <form action="/settings/users/{{$user->id}}" method="POST">
 | 
			
		||||
            {!! csrf_field() !!}
 | 
			
		||||
            <input type="hidden" name="_method" value="DELETE">
 | 
			
		||||
            <a href="/users/{{$user->id}}" class="button muted">Cancel</a>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@
 | 
			
		|||
                <div class="col-sm-6"></div>
 | 
			
		||||
                <div class="col-sm-6 faded">
 | 
			
		||||
                    <div class="action-buttons">
 | 
			
		||||
                        <a href="/users/{{$user->id}}/delete" class="text-neg text-button"><i class="zmdi zmdi-delete"></i>Delete User</a>
 | 
			
		||||
                        <a href="/settings/users/{{$user->id}}/delete" class="text-neg text-button"><i class="zmdi zmdi-delete"></i>Delete User</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
    <div class="container small">
 | 
			
		||||
        <form action="/users/{{$user->id}}" method="post">
 | 
			
		||||
        <form action="/settings/users/{{$user->id}}" method="post">
 | 
			
		||||
        <div class="row">
 | 
			
		||||
            <div class="col-md-6" ng-non-bindable>
 | 
			
		||||
                <h1>Edit {{ $user->id === $currentUser->id ? 'Profile' : 'User' }}</h1>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,6 @@
 | 
			
		|||
@endif
 | 
			
		||||
 | 
			
		||||
<div class="form-group">
 | 
			
		||||
    <a href="/users" class="button muted">Cancel</a>
 | 
			
		||||
    <a href="/settings/users" class="button muted">Cancel</a>
 | 
			
		||||
    <button class="button pos" type="submit">Save</button>
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +34,7 @@
 | 
			
		|||
</div>
 | 
			
		||||
 | 
			
		||||
<div class="form-group">
 | 
			
		||||
    <a href="/users" class="button muted">Cancel</a>
 | 
			
		||||
    <a href="/settings/users" class="button muted">Cancel</a>
 | 
			
		||||
    <button class="button pos" type="submit">Save</button>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
        <h1>Users</h1>
 | 
			
		||||
        @if($currentUser->can('user-create'))
 | 
			
		||||
            <p>
 | 
			
		||||
                <a href="/users/create" class="text-pos"><i class="zmdi zmdi-account-add"></i>Add new user</a>
 | 
			
		||||
                <a href="/settings/users/create" class="text-pos"><i class="zmdi zmdi-account-add"></i>Add new user</a>
 | 
			
		||||
            </p>
 | 
			
		||||
        @endif
 | 
			
		||||
        <table class="table">
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +25,7 @@
 | 
			
		|||
                    <td style="line-height: 0;"><img class="avatar med" src="{{$user->getAvatar(40)}}" alt="{{$user->name}}"></td>
 | 
			
		||||
                    <td>
 | 
			
		||||
                        @if($currentUser->can('user-update') || $currentUser->id == $user->id)
 | 
			
		||||
                            <a href="/users/{{$user->id}}">
 | 
			
		||||
                            <a href="/settings/users/{{$user->id}}">
 | 
			
		||||
                                @endif
 | 
			
		||||
                                {{ $user->name }}
 | 
			
		||||
                                @if($currentUser->can('user-update') || $currentUser->id == $user->id)
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +34,7 @@
 | 
			
		|||
                    </td>
 | 
			
		||||
                    <td>
 | 
			
		||||
                        @if($currentUser->can('user-update') || $currentUser->id == $user->id)
 | 
			
		||||
                            <a href="/users/{{$user->id}}">
 | 
			
		||||
                            <a href="/settings/users/{{$user->id}}">
 | 
			
		||||
                                @endif
 | 
			
		||||
                                {{ $user->email }}
 | 
			
		||||
                                @if($currentUser->can('user-update') || $currentUser->id == $user->id)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
@extends('base')
 | 
			
		||||
 | 
			
		||||
@section('content')
 | 
			
		||||
 | 
			
		||||
    <div class="container" ng-non-bindable>
 | 
			
		||||
        <div class="row">
 | 
			
		||||
            <div class="col-sm-7">
 | 
			
		||||
 | 
			
		||||
                <div class="padded-top large"></div>
 | 
			
		||||
 | 
			
		||||
                <div class="row">
 | 
			
		||||
                    <div class="col-md-7">
 | 
			
		||||
                        <div class="clearfix">
 | 
			
		||||
                            <div class="padded-right float left">
 | 
			
		||||
                                <img class="avatar square huge" src="{{$user->getAvatar(120)}}" alt="{{ $user->name }}">
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <div>
 | 
			
		||||
                                <h3 style="margin-top: 0;">{{ $user->name }}</h3>
 | 
			
		||||
                                <p class="text-muted">
 | 
			
		||||
                                    User for {{ $user->created_at->diffForHumans(null, true) }}
 | 
			
		||||
                                </p>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="col-md-5 text-bigger" id="content-counts">
 | 
			
		||||
                        <div class="text-muted">Created Content</div>
 | 
			
		||||
                        <div class="text-book">
 | 
			
		||||
                            <i class="zmdi zmdi-book zmdi-hc-fw"></i> {{ $assetCounts['books'] }} {{ str_plural('Book', $assetCounts['books']) }}
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="text-chapter">
 | 
			
		||||
                            <i class="zmdi zmdi-collection-bookmark zmdi-hc-fw"></i> {{ $assetCounts['chapters'] }} {{ str_plural('Chapter', $assetCounts['chapters']) }}
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="text-page">
 | 
			
		||||
                            <i class="zmdi zmdi-file-text zmdi-hc-fw"></i> {{ $assetCounts['pages'] }} {{ str_plural('Page', $assetCounts['pages']) }}
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                <hr class="even">
 | 
			
		||||
 | 
			
		||||
                <h3>Recently Created Pages</h3>
 | 
			
		||||
                @if (count($recentlyCreated['pages']) > 0)
 | 
			
		||||
                    @include('partials/entity-list', ['entities' => $recentlyCreated['pages']])
 | 
			
		||||
                @else
 | 
			
		||||
                    <p class="text-muted">{{ $user->name }} has not created any pages</p>
 | 
			
		||||
                @endif
 | 
			
		||||
 | 
			
		||||
                <hr class="even">
 | 
			
		||||
 | 
			
		||||
                <h3>Recently Created Chapters</h3>
 | 
			
		||||
                @if (count($recentlyCreated['chapters']) > 0)
 | 
			
		||||
                    @include('partials/entity-list', ['entities' => $recentlyCreated['chapters']])
 | 
			
		||||
                @else
 | 
			
		||||
                    <p class="text-muted">{{ $user->name }} has not created any chapters</p>
 | 
			
		||||
                @endif
 | 
			
		||||
 | 
			
		||||
                <hr class="even">
 | 
			
		||||
 | 
			
		||||
                <h3>Recently Created Books</h3>
 | 
			
		||||
                @if (count($recentlyCreated['books']) > 0)
 | 
			
		||||
                    @include('partials/entity-list', ['entities' => $recentlyCreated['books']])
 | 
			
		||||
                @else
 | 
			
		||||
                    <p class="text-muted">{{ $user->name }} has not created any books</p>
 | 
			
		||||
                @endif
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="col-sm-4 col-sm-offset-1" id="recent-activity">
 | 
			
		||||
                <h3>Recent Activity</h3>
 | 
			
		||||
                @include('partials/activity-list', ['activity' => $activity])
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@stop
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +129,7 @@ class AuthTest extends TestCase
 | 
			
		|||
        $user = factory(\BookStack\User::class)->make();
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/users')
 | 
			
		||||
            ->visit('/settings/users')
 | 
			
		||||
            ->click('Add new user')
 | 
			
		||||
            ->type($user->name, '#name')
 | 
			
		||||
            ->type($user->email, '#email')
 | 
			
		||||
| 
						 | 
				
			
			@ -138,7 +138,7 @@ class AuthTest extends TestCase
 | 
			
		|||
            ->type($user->password, '#password-confirm')
 | 
			
		||||
            ->press('Save')
 | 
			
		||||
            ->seeInDatabase('users', $user->toArray())
 | 
			
		||||
            ->seePageIs('/users')
 | 
			
		||||
            ->seePageIs('/settings/users')
 | 
			
		||||
            ->see($user->name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -147,13 +147,13 @@ class AuthTest extends TestCase
 | 
			
		|||
        $user = \BookStack\User::all()->last();
 | 
			
		||||
        $password = $user->password;
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/users')
 | 
			
		||||
            ->visit('/settings/users')
 | 
			
		||||
            ->click($user->name)
 | 
			
		||||
            ->seePageIs('/users/' . $user->id)
 | 
			
		||||
            ->seePageIs('/settings/users/' . $user->id)
 | 
			
		||||
            ->see($user->email)
 | 
			
		||||
            ->type('Barry Scott', '#name')
 | 
			
		||||
            ->press('Save')
 | 
			
		||||
            ->seePageIs('/users')
 | 
			
		||||
            ->seePageIs('/settings/users')
 | 
			
		||||
            ->seeInDatabase('users', ['id' => $user->id, 'name' => 'Barry Scott', 'password' => $password])
 | 
			
		||||
            ->notSeeInDatabase('users', ['name' => $user->name]);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -161,7 +161,7 @@ class AuthTest extends TestCase
 | 
			
		|||
    public function test_user_password_update()
 | 
			
		||||
    {
 | 
			
		||||
        $user = \BookStack\User::all()->last();
 | 
			
		||||
        $userProfilePage = '/users/' . $user->id;
 | 
			
		||||
        $userProfilePage = '/settings/users/' . $user->id;
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit($userProfilePage)
 | 
			
		||||
            ->type('newpassword', '#password')
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +172,7 @@ class AuthTest extends TestCase
 | 
			
		|||
            ->type('newpassword', '#password')
 | 
			
		||||
            ->type('newpassword', '#password-confirm')
 | 
			
		||||
            ->press('Save')
 | 
			
		||||
            ->seePageIs('/users');
 | 
			
		||||
            ->seePageIs('/settings/users');
 | 
			
		||||
 | 
			
		||||
            $userPassword = \BookStack\User::find($user->id)->password;
 | 
			
		||||
            $this->assertTrue(Hash::check('newpassword', $userPassword));
 | 
			
		||||
| 
						 | 
				
			
			@ -184,11 +184,11 @@ class AuthTest extends TestCase
 | 
			
		|||
        $user = $this->getNewUser($userDetails->toArray());
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/users/' . $user->id)
 | 
			
		||||
            ->visit('/settings/users/' . $user->id)
 | 
			
		||||
            ->click('Delete User')
 | 
			
		||||
            ->see($user->name)
 | 
			
		||||
            ->press('Confirm')
 | 
			
		||||
            ->seePageIs('/users')
 | 
			
		||||
            ->seePageIs('/settings/users')
 | 
			
		||||
            ->notSeeInDatabase('users', ['name' => $user->name]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -199,10 +199,10 @@ class AuthTest extends TestCase
 | 
			
		|||
        $this->assertEquals(1, $adminRole->users()->count());
 | 
			
		||||
        $user = $adminRole->users->first();
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()->visit('/users/' . $user->id)
 | 
			
		||||
        $this->asAdmin()->visit('/settings/users/' . $user->id)
 | 
			
		||||
            ->click('Delete User')
 | 
			
		||||
            ->press('Confirm')
 | 
			
		||||
            ->seePageIs('/users/' . $user->id)
 | 
			
		||||
            ->seePageIs('/settings/users/' . $user->id)
 | 
			
		||||
            ->see('You cannot delete the only admin');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,7 +94,7 @@ class LdapTest extends \TestCase
 | 
			
		|||
 | 
			
		||||
    public function test_create_user_form()
 | 
			
		||||
    {
 | 
			
		||||
        $this->asAdmin()->visit('/users/create')
 | 
			
		||||
        $this->asAdmin()->visit('/settings/users/create')
 | 
			
		||||
            ->dontSee('Password')
 | 
			
		||||
            ->type($this->mockUser->name, '#name')
 | 
			
		||||
            ->type($this->mockUser->email, '#email')
 | 
			
		||||
| 
						 | 
				
			
			@ -102,19 +102,19 @@ class LdapTest extends \TestCase
 | 
			
		|||
            ->see('The external auth id field is required.')
 | 
			
		||||
            ->type($this->mockUser->name, '#external_auth_id')
 | 
			
		||||
            ->press('Save')
 | 
			
		||||
            ->seePageIs('/users')
 | 
			
		||||
            ->seePageIs('/settings/users')
 | 
			
		||||
            ->seeInDatabase('users', ['email' => $this->mockUser->email, 'external_auth_id' => $this->mockUser->name, 'email_confirmed' => true]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_user_edit_form()
 | 
			
		||||
    {
 | 
			
		||||
        $editUser = User::all()->last();
 | 
			
		||||
        $this->asAdmin()->visit('/users/' . $editUser->id)
 | 
			
		||||
        $this->asAdmin()->visit('/settings/users/' . $editUser->id)
 | 
			
		||||
            ->see('Edit User')
 | 
			
		||||
            ->dontSee('Password')
 | 
			
		||||
            ->type('test_auth_id', '#external_auth_id')
 | 
			
		||||
            ->press('Save')
 | 
			
		||||
            ->seePageIs('/users')
 | 
			
		||||
            ->seePageIs('/settings/users')
 | 
			
		||||
            ->seeInDatabase('users', ['email' => $editUser->email, 'external_auth_id' => 'test_auth_id']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +127,7 @@ class LdapTest extends \TestCase
 | 
			
		|||
    public function test_non_admins_cannot_change_auth_id()
 | 
			
		||||
    {
 | 
			
		||||
        $testUser = User::all()->last();
 | 
			
		||||
        $this->actingAs($testUser)->visit('/users/' . $testUser->id)
 | 
			
		||||
        $this->actingAs($testUser)->visit('/settings/users/' . $testUser->id)
 | 
			
		||||
            ->dontSee('External Authentication');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,85 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
 | 
			
		||||
class EntitySearchTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    public function test_page_search()
 | 
			
		||||
    {
 | 
			
		||||
        $book = \BookStack\Book::all()->first();
 | 
			
		||||
        $page = $book->pages->first();
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/')
 | 
			
		||||
            ->type($page->name, 'term')
 | 
			
		||||
            ->press('header-search-box-button')
 | 
			
		||||
            ->see('Search Results')
 | 
			
		||||
            ->see($page->name)
 | 
			
		||||
            ->click($page->name)
 | 
			
		||||
            ->seePageIs($page->getUrl());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_invalid_page_search()
 | 
			
		||||
    {
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/')
 | 
			
		||||
            ->type('<p>test</p>', 'term')
 | 
			
		||||
            ->press('header-search-box-button')
 | 
			
		||||
            ->see('Search Results')
 | 
			
		||||
            ->seeStatusCode(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_empty_search_redirects_back()
 | 
			
		||||
    {
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/')
 | 
			
		||||
            ->visit('/search/all')
 | 
			
		||||
            ->seePageIs('/');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_book_search()
 | 
			
		||||
    {
 | 
			
		||||
        $book = \BookStack\Book::all()->first();
 | 
			
		||||
        $page = $book->pages->last();
 | 
			
		||||
        $chapter = $book->chapters->last();
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/search/book/' . $book->id . '?term=' . urlencode($page->name))
 | 
			
		||||
            ->see($page->name)
 | 
			
		||||
 | 
			
		||||
            ->visit('/search/book/' . $book->id  . '?term=' . urlencode($chapter->name))
 | 
			
		||||
            ->see($chapter->name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_empty_book_search_redirects_back()
 | 
			
		||||
    {
 | 
			
		||||
        $book = \BookStack\Book::all()->first();
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/books')
 | 
			
		||||
            ->visit('/search/book/' . $book->id . '?term=')
 | 
			
		||||
            ->seePageIs('/books');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function test_pages_search_listing()
 | 
			
		||||
    {
 | 
			
		||||
        $page = \BookStack\Page::all()->last();
 | 
			
		||||
        $this->asAdmin()->visit('/search/pages?term=' . $page->name)
 | 
			
		||||
            ->see('Page Search Results')->see('.entity-list', $page->name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_chapters_search_listing()
 | 
			
		||||
    {
 | 
			
		||||
        $chapter = \BookStack\Chapter::all()->last();
 | 
			
		||||
        $this->asAdmin()->visit('/search/chapters?term=' . $chapter->name)
 | 
			
		||||
            ->see('Chapter Search Results')->seeInElement('.entity-list', $chapter->name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_books_search_listing()
 | 
			
		||||
    {
 | 
			
		||||
        $book = \BookStack\Book::all()->last();
 | 
			
		||||
        $this->asAdmin()->visit('/search/books?term=' . $book->name)
 | 
			
		||||
            ->see('Book Search Results')->see('.entity-list', $book->name);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -155,63 +155,6 @@ class EntityTest extends TestCase
 | 
			
		|||
        return $book;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_page_search()
 | 
			
		||||
    {
 | 
			
		||||
        $book = \BookStack\Book::all()->first();
 | 
			
		||||
        $page = $book->pages->first();
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/')
 | 
			
		||||
            ->type($page->name, 'term')
 | 
			
		||||
            ->press('header-search-box-button')
 | 
			
		||||
            ->see('Search Results')
 | 
			
		||||
            ->see($page->name)
 | 
			
		||||
            ->click($page->name)
 | 
			
		||||
            ->seePageIs($page->getUrl());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_invalid_page_search()
 | 
			
		||||
    {
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/')
 | 
			
		||||
            ->type('<p>test</p>', 'term')
 | 
			
		||||
            ->press('header-search-box-button')
 | 
			
		||||
            ->see('Search Results')
 | 
			
		||||
            ->seeStatusCode(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_empty_search_redirects_back()
 | 
			
		||||
    {
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/')
 | 
			
		||||
            ->visit('/search/all')
 | 
			
		||||
            ->seePageIs('/');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_book_search()
 | 
			
		||||
    {
 | 
			
		||||
        $book = \BookStack\Book::all()->first();
 | 
			
		||||
        $page = $book->pages->last();
 | 
			
		||||
        $chapter = $book->chapters->last();
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/search/book/' . $book->id . '?term=' . urlencode($page->name))
 | 
			
		||||
            ->see($page->name)
 | 
			
		||||
 | 
			
		||||
            ->visit('/search/book/' . $book->id  . '?term=' . urlencode($chapter->name))
 | 
			
		||||
            ->see($chapter->name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_empty_book_search_redirects_back()
 | 
			
		||||
    {
 | 
			
		||||
        $book = \BookStack\Book::all()->first();
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/books')
 | 
			
		||||
            ->visit('/search/book/' . $book->id . '?term=')
 | 
			
		||||
            ->seePageIs('/books');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function test_entities_viewable_after_creator_deletion()
 | 
			
		||||
    {
 | 
			
		||||
        // Create required assets and revisions
 | 
			
		||||
| 
						 | 
				
			
			@ -250,5 +193,36 @@ class EntityTest extends TestCase
 | 
			
		|||
            ->click('Revisions')->seeStatusCode(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_recently_created_pages_view()
 | 
			
		||||
    {
 | 
			
		||||
        $user = $this->getNewUser();
 | 
			
		||||
        $content = $this->createEntityChainBelongingToUser($user);
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()->visit('/pages/recently-created')
 | 
			
		||||
            ->seeInNthElement('.entity-list .page', 0, $content['page']->name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_recently_updated_pages_view()
 | 
			
		||||
    {
 | 
			
		||||
        $user = $this->getNewUser();
 | 
			
		||||
        $content = $this->createEntityChainBelongingToUser($user);
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()->visit('/pages/recently-updated')
 | 
			
		||||
            ->seeInNthElement('.entity-list .page', 0, $content['page']->name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_old_page_slugs_redirect_to_new_pages()
 | 
			
		||||
    {
 | 
			
		||||
        $page = \BookStack\Page::all()->first();
 | 
			
		||||
        $pageUrl = $page->getUrl();
 | 
			
		||||
        $newPageUrl = '/books/' . $page->book->slug . '/page/super-test-page';
 | 
			
		||||
        $this->asAdmin()->visit($pageUrl)
 | 
			
		||||
            ->clickInElement('#content', 'Edit')
 | 
			
		||||
            ->type('super test page', '#name')
 | 
			
		||||
            ->press('Save Page')
 | 
			
		||||
            ->seePageIs($newPageUrl)
 | 
			
		||||
            ->visit($pageUrl)
 | 
			
		||||
            ->seePageIs($newPageUrl);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -109,4 +109,18 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
 | 
			
		|||
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,80 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
class UserProfileTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    protected $user;
 | 
			
		||||
 | 
			
		||||
    public function setUp()
 | 
			
		||||
    {
 | 
			
		||||
        parent::setUp();
 | 
			
		||||
        $this->user = \BookStack\User::all()->last();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_profile_page_shows_name()
 | 
			
		||||
    {
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/user/' . $this->user->id)
 | 
			
		||||
            ->see($this->user->name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_profile_page_shows_recent_entities()
 | 
			
		||||
    {
 | 
			
		||||
        $content = $this->createEntityChainBelongingToUser($this->user, $this->user);
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()
 | 
			
		||||
            ->visit('/user/' . $this->user->id)
 | 
			
		||||
            // Check the recently created page is shown
 | 
			
		||||
            ->see($content['page']->name)
 | 
			
		||||
            // Check the recently created chapter is shown
 | 
			
		||||
            ->see($content['chapter']->name)
 | 
			
		||||
            // Check the recently created book is shown
 | 
			
		||||
            ->see($content['book']->name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_profile_page_shows_created_content_counts()
 | 
			
		||||
    {
 | 
			
		||||
        $newUser = $this->getNewUser();
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()->visit('/user/' . $newUser->id)
 | 
			
		||||
            ->see($newUser->name)
 | 
			
		||||
            ->seeInElement('#content-counts', '0 Books')
 | 
			
		||||
            ->seeInElement('#content-counts', '0 Chapters')
 | 
			
		||||
            ->seeInElement('#content-counts', '0 Pages');
 | 
			
		||||
 | 
			
		||||
        $this->createEntityChainBelongingToUser($newUser, $newUser);
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()->visit('/user/' . $newUser->id)
 | 
			
		||||
            ->see($newUser->name)
 | 
			
		||||
            ->seeInElement('#content-counts', '1 Book')
 | 
			
		||||
            ->seeInElement('#content-counts', '1 Chapter')
 | 
			
		||||
            ->seeInElement('#content-counts', '1 Page');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_profile_page_shows_recent_activity()
 | 
			
		||||
    {
 | 
			
		||||
        $newUser = $this->getNewUser();
 | 
			
		||||
        $this->actingAs($newUser);
 | 
			
		||||
        $entities = $this->createEntityChainBelongingToUser($newUser, $newUser);
 | 
			
		||||
        Activity::add($entities['book'], 'book_update', $entities['book']->id);
 | 
			
		||||
        Activity::add($entities['page'], 'page_create', $entities['book']->id);
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()->visit('/user/' . $newUser->id)
 | 
			
		||||
            ->seeInElement('#recent-activity', 'updated book')
 | 
			
		||||
            ->seeInElement('#recent-activity', 'created page')
 | 
			
		||||
            ->seeInElement('#recent-activity', $entities['page']->name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_clicking_user_name_in_activity_leads_to_profile_page()
 | 
			
		||||
    {
 | 
			
		||||
        $newUser = $this->getNewUser();
 | 
			
		||||
        $this->actingAs($newUser);
 | 
			
		||||
        $entities = $this->createEntityChainBelongingToUser($newUser, $newUser);
 | 
			
		||||
        Activity::add($entities['book'], 'book_update', $entities['book']->id);
 | 
			
		||||
        Activity::add($entities['page'], 'page_create', $entities['book']->id);
 | 
			
		||||
 | 
			
		||||
        $this->asAdmin()->visit('/')->clickInElement('#recent-activity', $newUser->name)
 | 
			
		||||
            ->seePageIs('/user/' . $newUser->id)
 | 
			
		||||
            ->see($newUser->name);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue