Showing
13 changed files
with
115 additions
and
6 deletions
| ... | @@ -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; | ... | ... |
| 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> | ... | ... |
| ... | @@ -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 | ... | ... |
-
Please register or sign in to post a comment