Showing
9 changed files
with
97 additions
and
37 deletions
| ... | @@ -110,7 +110,11 @@ class ImageController extends Controller | ... | @@ -110,7 +110,11 @@ class ImageController extends Controller |
| 110 | public function upload(Request $request) | 110 | public function upload(Request $request) |
| 111 | { | 111 | { |
| 112 | $this->checkPermission('image-create'); | 112 | $this->checkPermission('image-create'); |
| 113 | + $this->validate($request, [ | ||
| 114 | + 'file' => 'image|mimes:jpeg,gif,png' | ||
| 115 | + ]); | ||
| 113 | $imageUpload = $request->file('file'); | 116 | $imageUpload = $request->file('file'); |
| 117 | + | ||
| 114 | $name = str_replace(' ', '-', $imageUpload->getClientOriginalName()); | 118 | $name = str_replace(' ', '-', $imageUpload->getClientOriginalName()); |
| 115 | $storageName = substr(sha1(time()), 0, 10) . '-' . $name; | 119 | $storageName = substr(sha1(time()), 0, 10) . '-' . $name; |
| 116 | $imagePath = '/uploads/images/' . Date('Y-m-M') . '/'; | 120 | $imagePath = '/uploads/images/' . Date('Y-m-M') . '/'; | ... | ... |
| ... | @@ -27,6 +27,7 @@ class ViewService | ... | @@ -27,6 +27,7 @@ class ViewService |
| 27 | */ | 27 | */ |
| 28 | public function add(Entity $entity) | 28 | public function add(Entity $entity) |
| 29 | { | 29 | { |
| 30 | + if($this->user === null) return 0; | ||
| 30 | $view = $entity->views()->where('user_id', '=', $this->user->id)->first(); | 31 | $view = $entity->views()->where('user_id', '=', $this->user->id)->first(); |
| 31 | // Add view if model exists | 32 | // Add view if model exists |
| 32 | if ($view) { | 33 | if ($view) { |
| ... | @@ -52,6 +53,7 @@ class ViewService | ... | @@ -52,6 +53,7 @@ class ViewService |
| 52 | */ | 53 | */ |
| 53 | public function getUserRecentlyViewed($count = 10, $page = 0, $filterModel = false) | 54 | public function getUserRecentlyViewed($count = 10, $page = 0, $filterModel = false) |
| 54 | { | 55 | { |
| 56 | + if($this->user === null) return collect(); | ||
| 55 | $skipCount = $count * $page; | 57 | $skipCount = $count * $page; |
| 56 | $query = $this->view->where('user_id', '=', auth()->user()->id); | 58 | $query = $this->view->where('user_id', '=', auth()->user()->id); |
| 57 | 59 | ... | ... |
| ... | @@ -2,35 +2,40 @@ | ... | @@ -2,35 +2,40 @@ |
| 2 | 2 | ||
| 3 | A platform to create documentation/wiki content. General information about BookStack can be found at https://www.bookstackapp.com/ | 3 | A platform to create documentation/wiki content. General information about BookStack can be found at https://www.bookstackapp.com/ |
| 4 | 4 | ||
| 5 | -**BookStack is currently in rapid development so use now is heavily cautioned as future updates my break existing installations.** | ||
| 6 | 5 | ||
| 7 | ## Requirements | 6 | ## Requirements |
| 8 | 7 | ||
| 9 | -BookStack has the similar requirements to Laravel. On top of those are some front-end build tools which the requirement of will be removed once out of beta release. | 8 | +BookStack has the similar requirements to Laravel. On top of those are some front-end build tools which are only required when developing. |
| 10 | 9 | ||
| 11 | * PHP >= 5.5.9 | 10 | * PHP >= 5.5.9 |
| 12 | * OpenSSL PHP Extension | 11 | * OpenSSL PHP Extension |
| 13 | * PDO PHP Extension | 12 | * PDO PHP Extension |
| 14 | -* Mbstring PHP Extension | 13 | +* MBstring PHP Extension |
| 15 | * Tokenizer PHP Extension | 14 | * Tokenizer PHP Extension |
| 16 | * MySQL >= 5.6 | 15 | * MySQL >= 5.6 |
| 16 | +* Git (Not strictly required but helps manage updates) | ||
| 17 | * [Composer](https://getcomposer.org/) | 17 | * [Composer](https://getcomposer.org/) |
| 18 | -* [Node.js](https://nodejs.org/en/) **To be removed in future** | 18 | +* [Node.js](https://nodejs.org/en/) **Development Only** |
| 19 | -* [Bower](http://bower.io/) **To be removed in future** | 19 | +* [Gulp](http://gulpjs.com/) **Development Only** |
| 20 | -* [Gulp](http://gulpjs.com/) **To be removed in future** | ||
| 21 | 20 | ||
| 22 | 21 | ||
| 23 | ## Installation | 22 | ## Installation |
| 24 | 23 | ||
| 25 | Ensure the requirements are met before installing. | 24 | Ensure the requirements are met before installing. |
| 26 | 25 | ||
| 27 | -The installation is currently somewhat complicated. Some PHP/Laravel experience will benefit. This will be streamlined in the future. | 26 | +This project currently uses the `release` branch of this repository as a stable channel for providing updates. |
| 28 | 27 | ||
| 29 | -1. Clone the repository into a folder. | 28 | +The installation is currently somewhat complicated. Some PHP/Laravel experience will benefit. |
| 30 | -2. `cd` into folder and run `composer install` followed by `npm install` and `bower install`. | 29 | + |
| 31 | -3. Run `gulp --production` to compile the JavaScript and css files. | 30 | +1. Clone the release branch of this repository into a folder. |
| 32 | -4. Copy the `.env.example` file to `.env` and fill with your own database and mail details. | 31 | + |
| 33 | -5. Ensure the `storage` & `bootstrap/cache` folders are writable by the web server. | 32 | +``` |
| 33 | +git clone https://github.com/ssddanbrown/BookStack.git --branch release --single-branch | ||
| 34 | +``` | ||
| 35 | + | ||
| 36 | +2. `cd` into the application folder and run `composer install`. | ||
| 37 | +3. Copy the `.env.example` file to `.env` and fill with your own database and mail details. | ||
| 38 | +4. Ensure the `storage` & `bootstrap/cache` folders are writable by the web server. | ||
| 34 | 5. In the application root, Run `php artisan key:generate` to generate a unique application key. | 39 | 5. In the application root, Run `php artisan key:generate` to generate a unique application key. |
| 35 | 6. If not using apache or `.htaccess` files are disable you will have to create some URL rewrite rules as shown below. | 40 | 6. If not using apache or `.htaccess` files are disable you will have to create some URL rewrite rules as shown below. |
| 36 | 7. Run `php migrate` to update the database. | 41 | 7. Run `php migrate` to update the database. | ... | ... |
| ... | @@ -110,6 +110,12 @@ | ... | @@ -110,6 +110,12 @@ |
| 110 | dz.removeFile(file); | 110 | dz.removeFile(file); |
| 111 | }); | 111 | }); |
| 112 | }); | 112 | }); |
| 113 | + this.on('error', function(file, errorMessage, xhr) { | ||
| 114 | + if(errorMessage.file) { | ||
| 115 | + $(file.previewElement).find('[data-dz-errormessage]').text(errorMessage.file[0]); | ||
| 116 | + } | ||
| 117 | + console.log(errorMessage); | ||
| 118 | + }); | ||
| 113 | } | 119 | } |
| 114 | }); | 120 | }); |
| 115 | }, | 121 | }, | ... | ... |
| ... | @@ -19,12 +19,16 @@ | ... | @@ -19,12 +19,16 @@ |
| 19 | max-width: 840px; | 19 | max-width: 840px; |
| 20 | overflow-wrap: break-word; | 20 | overflow-wrap: break-word; |
| 21 | .align-left { | 21 | .align-left { |
| 22 | - float: left !important; | ||
| 23 | text-align: left; | 22 | text-align: left; |
| 23 | + } | ||
| 24 | + img.align-left, table.align-left { | ||
| 25 | + float: left !important; | ||
| 24 | margin: $-xs $-s $-xs 0; | 26 | margin: $-xs $-s $-xs 0; |
| 25 | } | 27 | } |
| 26 | .align-right { | 28 | .align-right { |
| 27 | float: right !important; | 29 | float: right !important; |
| 30 | + } | ||
| 31 | + img.align-right, table.align-right { | ||
| 28 | text-align: right; | 32 | text-align: right; |
| 29 | margin: $-xs 0 $-xs $-s; | 33 | margin: $-xs 0 $-xs $-s; |
| 30 | } | 34 | } | ... | ... |
| ... | @@ -3,7 +3,7 @@ | ... | @@ -3,7 +3,7 @@ |
| 3 | <head> | 3 | <head> |
| 4 | <title>BookStack</title> | 4 | <title>BookStack</title> |
| 5 | 5 | ||
| 6 | - <!-- Meta--> | 6 | + <!-- Meta --> |
| 7 | <meta name="viewport" content="width=device-width"> | 7 | <meta name="viewport" content="width=device-width"> |
| 8 | <meta name="token" content="{{ csrf_token() }}"> | 8 | <meta name="token" content="{{ csrf_token() }}"> |
| 9 | <meta charset="utf-8"> | 9 | <meta charset="utf-8"> |
| ... | @@ -21,17 +21,7 @@ | ... | @@ -21,17 +21,7 @@ |
| 21 | </head> | 21 | </head> |
| 22 | <body class="@yield('body-class')" id="app"> | 22 | <body class="@yield('body-class')" id="app"> |
| 23 | 23 | ||
| 24 | - @if(Session::has('success')) | 24 | + @include('partials/notifications') |
| 25 | - <div class="notification anim pos"> | ||
| 26 | - <i class="zmdi zmdi-mood"></i> <span>{{ Session::get('success') }}</span> | ||
| 27 | - </div> | ||
| 28 | - @endif | ||
| 29 | - | ||
| 30 | - @if(Session::has('error')) | ||
| 31 | - <div class="notification anim neg stopped"> | ||
| 32 | - <i class="zmdi zmdi-alert-circle"></i> <span>{{ Session::get('error') }}</span> | ||
| 33 | - </div> | ||
| 34 | - @endif | ||
| 35 | 25 | ||
| 36 | <header id="header"> | 26 | <header id="header"> |
| 37 | <div class="container"> | 27 | <div class="container"> | ... | ... |
| 1 | +@if(Session::has('success')) | ||
| 2 | + <div class="notification anim pos"> | ||
| 3 | + <i class="zmdi zmdi-mood"></i> <span>{{ Session::get('success') }}</span> | ||
| 4 | + </div> | ||
| 5 | +@endif | ||
| 6 | + | ||
| 7 | +@if(Session::has('error')) | ||
| 8 | + <div class="notification anim neg stopped"> | ||
| 9 | + <i class="zmdi zmdi-alert-circle"></i> <span>{{ Session::get('error') }}</span> | ||
| 10 | + </div> | ||
| 11 | +@endif | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -2,27 +2,24 @@ | ... | @@ -2,27 +2,24 @@ |
| 2 | <html> | 2 | <html> |
| 3 | <head> | 3 | <head> |
| 4 | <title>BookStack</title> | 4 | <title>BookStack</title> |
| 5 | + | ||
| 6 | + <!-- Meta --> | ||
| 5 | <meta name="viewport" content="width=device-width"> | 7 | <meta name="viewport" content="width=device-width"> |
| 8 | + <meta charset="utf-8"> | ||
| 9 | + | ||
| 10 | + <!-- Styles and Fonts --> | ||
| 6 | <link rel="stylesheet" href="{{ elixir('css/styles.css') }}"> | 11 | <link rel="stylesheet" href="{{ elixir('css/styles.css') }}"> |
| 12 | + <link rel="stylesheet" media="print" href="{{ elixir('css/print-styles.css') }}"> | ||
| 7 | <link href='//fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,300italic,100,300' rel='stylesheet' type='text/css'> | 13 | <link href='//fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,300italic,100,300' rel='stylesheet' type='text/css'> |
| 8 | - <link rel="stylesheet" href="/bower/material-design-iconic-font/dist/css/material-design-iconic-font.min.css"> | 14 | + <link rel="stylesheet" href="/libs/material-design-iconic-font/css/material-design-iconic-font.min.css"> |
| 9 | 15 | ||
| 10 | <!-- Scripts --> | 16 | <!-- Scripts --> |
| 11 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> | 17 | <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> |
| 18 | + | ||
| 12 | </head> | 19 | </head> |
| 13 | <body class="@yield('body-class')" id="app"> | 20 | <body class="@yield('body-class')" id="app"> |
| 14 | 21 | ||
| 15 | -@if(Session::has('success')) | 22 | +@include('partials/notifications') |
| 16 | - <div class="notification anim pos"> | ||
| 17 | - <i class="zmdi zmdi-mood"></i> <span>{{ Session::get('success') }}</span> | ||
| 18 | - </div> | ||
| 19 | -@endif | ||
| 20 | - | ||
| 21 | -@if(Session::has('error')) | ||
| 22 | - <div class="notification anim neg stopped"> | ||
| 23 | - <i class="zmdi zmdi-alert-circle"></i> <span>{{ Session::get('error') }}</span> | ||
| 24 | - </div> | ||
| 25 | -@endif | ||
| 26 | 23 | ||
| 27 | <header id="header"> | 24 | <header id="header"> |
| 28 | <div class="container"> | 25 | <div class="container"> | ... | ... |
tests/PublicViewTest.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +class PublicViewTest extends TestCase | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | + public function testBooksViewable() | ||
| 7 | + { | ||
| 8 | + $this->setSettings(['app-public' => 'true']); | ||
| 9 | + $books = \BookStack\Book::orderBy('name', 'asc')->take(10)->get(); | ||
| 10 | + $bookToVisit = $books[1]; | ||
| 11 | + | ||
| 12 | + // Check books index page is showing | ||
| 13 | + $this->visit('/books') | ||
| 14 | + ->seeStatusCode(200) | ||
| 15 | + ->see($books[0]->name) | ||
| 16 | + // Check indavidual book page is showing and it's child contents are visible. | ||
| 17 | + ->click($bookToVisit->name) | ||
| 18 | + ->seePageIs($bookToVisit->getUrl()) | ||
| 19 | + ->see($bookToVisit->name) | ||
| 20 | + ->see($bookToVisit->chapters()->first()->name); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + public function testChaptersViewable() | ||
| 24 | + { | ||
| 25 | + $this->setSettings(['app-public' => 'true']); | ||
| 26 | + $chapterToVisit = \BookStack\Chapter::first(); | ||
| 27 | + $pageToVisit = $chapterToVisit->pages()->first(); | ||
| 28 | + | ||
| 29 | + // Check chapters index page is showing | ||
| 30 | + $this->visit($chapterToVisit->getUrl()) | ||
| 31 | + ->seeStatusCode(200) | ||
| 32 | + ->see($chapterToVisit->name) | ||
| 33 | + // Check indavidual chapter page is showing and it's child contents are visible. | ||
| 34 | + ->see($pageToVisit->name) | ||
| 35 | + ->click($pageToVisit->name) | ||
| 36 | + ->see($chapterToVisit->book->name) | ||
| 37 | + ->see($chapterToVisit->name) | ||
| 38 | + ->seePageIs($pageToVisit->getUrl()); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or sign in to post a comment