Dan Brown

Merge fixes from branch 'v0.12'

...@@ -4,6 +4,8 @@ namespace BookStack\Http\Controllers\Auth; ...@@ -4,6 +4,8 @@ namespace BookStack\Http\Controllers\Auth;
4 4
5 use BookStack\Http\Controllers\Controller; 5 use BookStack\Http\Controllers\Controller;
6 use Illuminate\Foundation\Auth\SendsPasswordResetEmails; 6 use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
7 +use Illuminate\Http\Request;
8 +use Password;
7 9
8 class ForgotPasswordController extends Controller 10 class ForgotPasswordController extends Controller
9 { 11 {
...@@ -30,4 +32,37 @@ class ForgotPasswordController extends Controller ...@@ -30,4 +32,37 @@ class ForgotPasswordController extends Controller
30 $this->middleware('guest'); 32 $this->middleware('guest');
31 parent::__construct(); 33 parent::__construct();
32 } 34 }
35 +
36 +
37 + /**
38 + * Send a reset link to the given user.
39 + *
40 + * @param \Illuminate\Http\Request $request
41 + * @return \Illuminate\Http\RedirectResponse
42 + */
43 + public function sendResetLinkEmail(Request $request)
44 + {
45 + $this->validate($request, ['email' => 'required|email']);
46 +
47 + // We will send the password reset link to this user. Once we have attempted
48 + // to send the link, we will examine the response then see the message we
49 + // need to show to the user. Finally, we'll send out a proper response.
50 + $response = $this->broker()->sendResetLink(
51 + $request->only('email')
52 + );
53 +
54 + if ($response === Password::RESET_LINK_SENT) {
55 + $message = 'A password reset link has been sent to ' . $request->get('email') . '.';
56 + session()->flash('success', $message);
57 + return back()->with('status', trans($response));
58 + }
59 +
60 + // If an error was returned by the password broker, we will get this message
61 + // translated so we can notify a user of the problem. We'll redirect back
62 + // to where the users came from so they can attempt this process again.
63 + return back()->withErrors(
64 + ['email' => trans($response)]
65 + );
66 + }
67 +
33 } 68 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -20,6 +20,8 @@ class ResetPasswordController extends Controller ...@@ -20,6 +20,8 @@ class ResetPasswordController extends Controller
20 20
21 use ResetsPasswords; 21 use ResetsPasswords;
22 22
23 + protected $redirectTo = '/';
24 +
23 /** 25 /**
24 * Create a new controller instance. 26 * Create a new controller instance.
25 * 27 *
...@@ -30,4 +32,18 @@ class ResetPasswordController extends Controller ...@@ -30,4 +32,18 @@ class ResetPasswordController extends Controller
30 $this->middleware('guest'); 32 $this->middleware('guest');
31 parent::__construct(); 33 parent::__construct();
32 } 34 }
35 +
36 + /**
37 + * Get the response for a successful password reset.
38 + *
39 + * @param string $response
40 + * @return \Illuminate\Http\Response
41 + */
42 + protected function sendResetResponse($response)
43 + {
44 + $message = 'Your password has been successfully reset.';
45 + session()->flash('success', $message);
46 + return redirect($this->redirectPath())
47 + ->with('status', trans($response));
48 + }
33 } 49 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -9,6 +9,8 @@ return [ ...@@ -9,6 +9,8 @@ return [
9 'app-name-header' => true, 9 'app-name-header' => true,
10 'app-editor' => 'wysiwyg', 10 'app-editor' => 'wysiwyg',
11 'app-color' => '#0288D1', 11 'app-color' => '#0288D1',
12 - 'app-color-light' => 'rgba(21, 101, 192, 0.15)' 12 + 'app-color-light' => 'rgba(21, 101, 192, 0.15)',
13 + 'app-custom-head' => false,
14 + 'registration-enabled' => false,
13 15
14 ]; 16 ];
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -135,6 +135,7 @@ ...@@ -135,6 +135,7 @@
135 border-left: 3px solid #BBB; 135 border-left: 3px solid #BBB;
136 background-color: #EEE; 136 background-color: #EEE;
137 padding: $-s; 137 padding: $-s;
138 + display: flex;
138 &:before { 139 &:before {
139 font-family: 'Material-Design-Iconic-Font'; 140 font-family: 'Material-Design-Iconic-Font';
140 padding-right: $-s; 141 padding-right: $-s;
......
...@@ -262,7 +262,7 @@ ul { ...@@ -262,7 +262,7 @@ ul {
262 262
263 ol { 263 ol {
264 list-style: decimal; 264 list-style: decimal;
265 - padding-left: $-m * 1.3; 265 + padding-left: $-m * 2;
266 overflow: hidden; 266 overflow: hidden;
267 } 267 }
268 268
......
1 @extends('public') 1 @extends('public')
2 2
3 +@section('header-buttons')
4 + <a href="{{ baseUrl("/login") }}"><i class="zmdi zmdi-sign-in"></i>Sign in</a>
5 + @if(setting('registration-enabled'))
6 + <a href="{{ baseUrl("/register") }}"><i class="zmdi zmdi-account-add"></i>Sign up</a>
7 + @endif
8 +@stop
9 +
3 @section('content') 10 @section('content')
4 11
5 12
......
1 @extends('public') 1 @extends('public')
2 2
3 +@section('header-buttons')
4 + <a href="{{ baseUrl("/login") }}"><i class="zmdi zmdi-sign-in"></i>Sign in</a>
5 + @if(setting('registration-enabled'))
6 + <a href="{{ baseUrl("/register") }}"><i class="zmdi zmdi-account-add"></i>Sign up</a>
7 + @endif
8 +@stop
9 +
3 @section('body-class', 'image-cover login') 10 @section('body-class', 'image-cover login')
4 11
5 @section('content') 12 @section('content')
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
23 @include('partials/custom-styles') 23 @include('partials/custom-styles')
24 24
25 <!-- Custom user content --> 25 <!-- Custom user content -->
26 - @if(setting('app-custom-head', false)) 26 + @if(setting('app-custom-head'))
27 {!! setting('app-custom-head') !!} 27 {!! setting('app-custom-head') !!}
28 @endif 28 @endif
29 </head> 29 </head>
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
14 table { 14 table {
15 max-width: 800px !important; 15 max-width: 800px !important;
16 font-size: 0.8em; 16 font-size: 0.8em;
17 - width: auto !important; 17 + width: 100% !important;
18 } 18 }
19 19
20 table td { 20 table td {
......
...@@ -17,6 +17,11 @@ ...@@ -17,6 +17,11 @@
17 <!-- Scripts --> 17 <!-- Scripts -->
18 <script src="{{ baseUrl("/libs/jquery/jquery.min.js?version=2.1.4") }}"></script> 18 <script src="{{ baseUrl("/libs/jquery/jquery.min.js?version=2.1.4") }}"></script>
19 @include('partials/custom-styles') 19 @include('partials/custom-styles')
20 +
21 + <!-- Custom user content -->
22 + @if(setting('app-custom-head'))
23 + {!! setting('app-custom-head') !!}
24 + @endif
20 </head> 25 </head>
21 <body class="@yield('body-class')" ng-app="bookStack"> 26 <body class="@yield('body-class')" ng-app="bookStack">
22 27
......
...@@ -218,6 +218,37 @@ class AuthTest extends TestCase ...@@ -218,6 +218,37 @@ class AuthTest extends TestCase
218 ->seePageIs('/login'); 218 ->seePageIs('/login');
219 } 219 }
220 220
221 + public function test_reset_password_flow()
222 + {
223 + $this->visit('/login')->click('Forgot Password?')
224 + ->seePageIs('/password/email')
225 + ->type('admin@admin.com', 'email')
226 + ->press('Send Reset Link')
227 + ->see('A password reset link has been sent to admin@admin.com');
228 +
229 + $this->seeInDatabase('password_resets', [
230 + 'email' => 'admin@admin.com'
231 + ]);
232 +
233 + $reset = DB::table('password_resets')->where('email', '=', 'admin@admin.com')->first();
234 + $this->visit('/password/reset/' . $reset->token)
235 + ->see('Reset Password')
236 + ->submitForm('Reset Password', [
237 + 'email' => 'admin@admin.com',
238 + 'password' => 'randompass',
239 + 'password_confirmation' => 'randompass'
240 + ])->seePageIs('/')
241 + ->see('Your password has been successfully reset');
242 + }
243 +
244 + public function test_reset_password_page_shows_sign_links()
245 + {
246 + $this->setSettings(['registration-enabled' => 'true']);
247 + $this->visit('/password/email')
248 + ->seeLink('Sign in')
249 + ->seeLink('Sign up');
250 + }
251 +
221 /** 252 /**
222 * Perform a login 253 * Perform a login
223 * @param string $email 254 * @param string $email
......
...@@ -91,6 +91,12 @@ class EntitySearchTest extends TestCase ...@@ -91,6 +91,12 @@ class EntitySearchTest extends TestCase
91 ->see('Book Search Results')->see('.entity-list', $book->name); 91 ->see('Book Search Results')->see('.entity-list', $book->name);
92 } 92 }
93 93
94 + public function test_searching_hypen_doesnt_break()
95 + {
96 + $this->visit('/search/all?term=cat+-')
97 + ->seeStatusCode(200);
98 + }
99 +
94 public function test_ajax_entity_search() 100 public function test_ajax_entity_search()
95 { 101 {
96 $page = \BookStack\Page::all()->last(); 102 $page = \BookStack\Page::all()->last();
......
...@@ -57,7 +57,7 @@ class ImageTest extends TestCase ...@@ -57,7 +57,7 @@ class ImageTest extends TestCase
57 $relPath = $this->uploadImage($imageName, $page->id); 57 $relPath = $this->uploadImage($imageName, $page->id);
58 $this->assertResponseOk(); 58 $this->assertResponseOk();
59 59
60 - $this->assertTrue(file_exists(public_path($relPath)), 'Uploaded image exists'); 60 + $this->assertTrue(file_exists(public_path($relPath)), 'Uploaded image not found at path: '. public_path($relPath));
61 61
62 $this->deleteImage($relPath); 62 $this->deleteImage($relPath);
63 63
...@@ -70,7 +70,6 @@ class ImageTest extends TestCase ...@@ -70,7 +70,6 @@ class ImageTest extends TestCase
70 'updated_by' => $admin->id, 70 'updated_by' => $admin->id,
71 'name' => $imageName 71 'name' => $imageName
72 ]); 72 ]);
73 -
74 73
75 } 74 }
76 75
......