]> BookStack Code Mirror - bookstack/commitdiff
Merge fixes from branch 'v0.12'
authorDan Brown <redacted>
Sat, 12 Nov 2016 11:40:54 +0000 (11:40 +0000)
committerDan Brown <redacted>
Sat, 12 Nov 2016 11:40:54 +0000 (11:40 +0000)
1  2 
app/Http/Controllers/Auth/ForgotPasswordController.php
app/Http/Controllers/Auth/ResetPasswordController.php
config/setting-defaults.php
resources/assets/sass/_text.scss
resources/views/auth/passwords/email.blade.php
resources/views/auth/passwords/reset.blade.php
resources/views/base.blade.php
resources/views/public.blade.php
tests/Auth/AuthTest.php
tests/ImageTest.php

index d93854e23a49d947ffc68188f8929956d92874b1,0000000000000000000000000000000000000000..45e40e6fe8371a5d8034ca2d5627f2ff63621acc
mode 100644,000000..100644
--- /dev/null
@@@ -1,33 -1,0 +1,68 @@@
 +<?php
 +
 +namespace BookStack\Http\Controllers\Auth;
 +
 +use BookStack\Http\Controllers\Controller;
 +use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
++use Illuminate\Http\Request;
++use Password;
 +
 +class ForgotPasswordController extends Controller
 +{
 +    /*
 +    |--------------------------------------------------------------------------
 +    | Password Reset Controller
 +    |--------------------------------------------------------------------------
 +    |
 +    | This controller is responsible for handling password reset emails and
 +    | includes a trait which assists in sending these notifications from
 +    | your application to your users. Feel free to explore this trait.
 +    |
 +    */
 +
 +    use SendsPasswordResetEmails;
 +
 +    /**
 +     * Create a new controller instance.
 +     *
 +     * @return void
 +     */
 +    public function __construct()
 +    {
 +        $this->middleware('guest');
 +        parent::__construct();
 +    }
++
++
++    /**
++     * Send a reset link to the given user.
++     *
++     * @param  \Illuminate\Http\Request  $request
++     * @return \Illuminate\Http\RedirectResponse
++     */
++    public function sendResetLinkEmail(Request $request)
++    {
++        $this->validate($request, ['email' => 'required|email']);
++
++        // We will send the password reset link to this user. Once we have attempted
++        // to send the link, we will examine the response then see the message we
++        // need to show to the user. Finally, we'll send out a proper response.
++        $response = $this->broker()->sendResetLink(
++            $request->only('email')
++        );
++
++        if ($response === Password::RESET_LINK_SENT) {
++            $message = 'A password reset link has been sent to ' . $request->get('email') . '.';
++            session()->flash('success', $message);
++            return back()->with('status', trans($response));
++        }
++
++        // If an error was returned by the password broker, we will get this message
++        // translated so we can notify a user of the problem. We'll redirect back
++        // to where the users came from so they can attempt this process again.
++        return back()->withErrors(
++            ['email' => trans($response)]
++        );
++    }
++
 +}
index 656b8cc42418a63840fe2c32946100e952ee64f0,0000000000000000000000000000000000000000..bd64793f9223078d375da6577af9a01cfd1a9fae
mode 100644,000000..100644
--- /dev/null
@@@ -1,33 -1,0 +1,49 @@@
 +<?php
 +
 +namespace BookStack\Http\Controllers\Auth;
 +
 +use BookStack\Http\Controllers\Controller;
 +use Illuminate\Foundation\Auth\ResetsPasswords;
 +
 +class ResetPasswordController extends Controller
 +{
 +    /*
 +    |--------------------------------------------------------------------------
 +    | Password Reset Controller
 +    |--------------------------------------------------------------------------
 +    |
 +    | This controller is responsible for handling password reset requests
 +    | and uses a simple trait to include this behavior. You're free to
 +    | explore this trait and override any methods you wish to tweak.
 +    |
 +    */
 +
 +    use ResetsPasswords;
 +
++    protected $redirectTo = '/';
++
 +    /**
 +     * Create a new controller instance.
 +     *
 +     * @return void
 +     */
 +    public function __construct()
 +    {
 +        $this->middleware('guest');
 +        parent::__construct();
 +    }
++
++    /**
++     * Get the response for a successful password reset.
++     *
++     * @param  string  $response
++     * @return \Illuminate\Http\Response
++     */
++    protected function sendResetResponse($response)
++    {
++        $message = 'Your password has been successfully reset.';
++        session()->flash('success', $message);
++        return redirect($this->redirectPath())
++            ->with('status', trans($response));
++    }
 +}
index 5482c13315e8012f9f90f89644e765d895eb1569,deafceb29c2e774cee42900e8cc47739a4fffec8..c681bb7f55ddbe97e6ba73b29154373e18d2db55
@@@ -6,9 -6,10 +6,11 @@@
  return [
  
      'app-name'        => 'BookStack',
 +    'app-name-header' => true,
      'app-editor'      => 'wysiwyg',
      'app-color'       => '#0288D1',
-     'app-color-light' => 'rgba(21, 101, 192, 0.15)'
+     'app-color-light' => 'rgba(21, 101, 192, 0.15)',
+     'app-custom-head' => false,
+     'registration-enabled' => false,
  
  ];
index fd993b685402813132cb3a4c0ff50405bc20b153,8bf09a626f01528c17d6f337ae60ed26c2a6b316..e81061685a1ab3afc1d37a8fdb4fab78a4fe0987
@@@ -15,41 -15,31 +15,41 @@@ h2 
    margin-bottom: 0.43137255em;
  }
  h3 {
 -  font-size: 1.75em;
 +  font-size: 2.333em;
    line-height: 1.571428572em;
    margin-top: 0.78571429em;
    margin-bottom: 0.43137255em;
  }
  h4 {
 -  font-size: 1em;
 +  font-size: 1.666em;
    line-height: 1.375em;
    margin-top: 0.78571429em;
    margin-bottom: 0.43137255em;
  }
  
 -h1, h2, h3, h4 {
 +h1, h2, h3, h4, h5, h6 {
    font-weight: 400;
    position: relative;
    display: block;
    color: #555;
    .subheader {
 -    //display: block;
      font-size: 0.5em;
      line-height: 1em;
      color: lighten($text-dark, 32%);
    }
  }
  
 +h5 {
 +  font-size: 1.4em;
 +}
 +
 +h5, h6 {
 +  font-weight: 500;
 +  line-height: 1.2em;
 +  margin-top: 0.78571429em;
 +  margin-bottom: 0.66em;
 +}
 +
  /*
   * Link styling
   */
@@@ -262,7 -252,7 +262,7 @@@ ul 
  
  ol {
    list-style: decimal;
-   padding-left: $-m * 1.3;
+   padding-left: $-m * 2;
    overflow: hidden;
  }
  
index d8536efa723bebef008e1feb194c682fd773a394,115785ab2eb43893df69e64b3573c7aa3b3a9101..115785ab2eb43893df69e64b3573c7aa3b3a9101
@@@ -1,5 -1,12 +1,12 @@@
  @extends('public')
  
+ @section('header-buttons')
+     <a href="{{ baseUrl("/login") }}"><i class="zmdi zmdi-sign-in"></i>Sign in</a>
+     @if(setting('registration-enabled'))
+         <a href="{{ baseUrl("/register") }}"><i class="zmdi zmdi-account-add"></i>Sign up</a>
+     @endif
+ @stop
  @section('content')
  
  
index 9a9a65ff094516af8ac142e3b898222f0c2589fd,612b50ff835eb069f54b77ae0bf8af91c8d09acf..612b50ff835eb069f54b77ae0bf8af91c8d09acf
@@@ -1,5 -1,12 +1,12 @@@
  @extends('public')
  
+ @section('header-buttons')
+     <a href="{{ baseUrl("/login") }}"><i class="zmdi zmdi-sign-in"></i>Sign in</a>
+     @if(setting('registration-enabled'))
+         <a href="{{ baseUrl("/register") }}"><i class="zmdi zmdi-account-add"></i>Sign up</a>
+     @endif
+ @stop
  @section('body-class', 'image-cover login')
  
  @section('content')
index 1deed0a3fbad2057fc5ca0789f2a6029d7f24d45,961ead251bfdd79f9f886ed43639228c7e0d9da2..08acf725d95ea013b54fcd0742060d87e9d571ed
@@@ -23,7 -23,7 +23,7 @@@
      @include('partials/custom-styles')
  
      <!-- Custom user content -->
-     @if(setting('app-custom-head', false))
+     @if(setting('app-custom-head'))
          {!! setting('app-custom-head') !!}
      @endif
  </head>
@@@ -39,9 -39,7 +39,9 @@@
                          @if(setting('app-logo', '') !== 'none')
                              <img class="logo-image" src="{{ setting('app-logo', '') === '' ? baseUrl('/logo.png') : baseUrl(setting('app-logo', '')) }}" alt="Logo">
                          @endif
 -                        <span class="logo-text">{{ setting('app-name') }}</span>
 +                        @if (setting('app-name-header'))
 +                            <span class="logo-text">{{ setting('app-name') }}</span>
 +                        @endif
                      </a>
                  </div>
                  <div class="col-lg-4 col-sm-3 text-center">
index 542d5c8679add17afe29e4070f456616fc21cbf8,2bce4157028a8ca2b1595021dfaa582cb3b67ae0..16aebe2bb74fcede0efea22af753c41ec920b46b
      <!-- Scripts -->
      <script src="{{ baseUrl("/libs/jquery/jquery.min.js?version=2.1.4") }}"></script>
      @include('partials/custom-styles')
+     <!-- Custom user content -->
+     @if(setting('app-custom-head'))
+         {!! setting('app-custom-head') !!}
+     @endif
  </head>
  <body class="@yield('body-class')" ng-app="bookStack">
  
@@@ -31,9 -36,7 +36,9 @@@
                      @if(setting('app-logo', '') !== 'none')
                          <img class="logo-image" src="{{ setting('app-logo', '') === '' ? baseUrl('/logo.png') : baseUrl(setting('app-logo', '')) }}" alt="Logo">
                      @endif
 -                    <span class="logo-text">{{ setting('app-name') }}</span>
 +                    @if (setting('app-name-header'))
 +                        <span class="logo-text">{{ setting('app-name') }}</span>
 +                    @endif
                  </a>
              </div>
              <div class="col-md-6">
diff --combined tests/Auth/AuthTest.php
index 08d5ef8adb296eaea113da265d7afe2339a4d716,99885d552c7a0dcdf9b4b24e2d680502d614cad3..0d2e4ac170a660e3ed0925f65df404e915a1c398
@@@ -1,7 -1,6 +1,7 @@@
  <?php
  
 -use BookStack\EmailConfirmation;
 +use BookStack\Notifications\ConfirmEmail;
 +use Illuminate\Support\Facades\Notification;
  
  class AuthTest extends TestCase
  {
  
      public function test_confirmed_registration()
      {
 +        // Fake notifications
 +        Notification::fake();
 +
          // Set settings and get user instance
          $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
          $user = factory(\BookStack\User::class)->make();
  
 -        // Mock Mailer to ensure mail is being sent
 -        $mockMailer = Mockery::mock('Illuminate\Contracts\Mail\Mailer');
 -        $mockMailer->shouldReceive('send')->with('emails/email-confirmation', Mockery::type('array'), Mockery::type('callable'))->twice();
 -        $this->app->instance('mailer', $mockMailer);
 -
          // Go through registration process
          $this->visit('/register')
              ->see('Sign Up')
              ->seePageIs('/register/confirm')
              ->seeInDatabase('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
  
 +        // Ensure notification sent
 +        $dbUser = \BookStack\User::where('email', '=', $user->email)->first();
 +        Notification::assertSentTo($dbUser, ConfirmEmail::class);
 +
          // Test access and resend confirmation email
          $this->login($user->email, $user->password)
              ->seePageIs('/register/confirm/awaiting')
              ->seePageIs('/register/confirm/awaiting')
              ->press('Resend Confirmation Email');
  
 -        // Get confirmation
 -        $user = $user->where('email', '=', $user->email)->first();
 -        $emailConfirmation = EmailConfirmation::where('user_id', '=', $user->id)->first();
 -
 -
 -        // Check confirmation email button and confirmation activation.
 -        $this->visit('/register/confirm/' . $emailConfirmation->token . '/email')
 -            ->see('Email Confirmation')
 -            ->click('Confirm Email')
 +        // Get confirmation and confirm notification matches
 +        $emailConfirmation = DB::table('email_confirmations')->where('user_id', '=', $dbUser->id)->first();
 +        Notification::assertSentTo($dbUser, ConfirmEmail::class, function($notification, $channels) use ($emailConfirmation) {
 +            return $notification->token === $emailConfirmation->token;
 +        });
 +        
 +        // Check confirmation email confirmation activation.
 +        $this->visit('/register/confirm/' . $emailConfirmation->token)
              ->seePageIs('/')
              ->see($user->name)
              ->notSeeInDatabase('email_confirmations', ['token' => $emailConfirmation->token])
 -            ->seeInDatabase('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => true]);
 +            ->seeInDatabase('users', ['name' => $dbUser->name, 'email' => $dbUser->email, 'email_confirmed' => true]);
      }
  
      public function test_restricted_registration()
  
      public function test_user_updating()
      {
 -        $user = \BookStack\User::all()->last();
 +        $user = $this->getNormalUser();
          $password = $user->password;
          $this->asAdmin()
              ->visit('/settings/users')
  
      public function test_user_password_update()
      {
 -        $user = \BookStack\User::all()->last();
 +        $user = $this->getNormalUser();
          $userProfilePage = '/settings/users/' . $user->id;
          $this->asAdmin()
              ->visit($userProfilePage)
              ->seePageIs('/login');
      }
  
+     public function test_reset_password_flow()
+     {
+         $this->visit('/login')->click('Forgot Password?')
+             ->seePageIs('/password/email')
+             ->type('[email protected]', 'email')
+             ->press('Send Reset Link')
+             ->see('A password reset link has been sent to [email protected]');
+         $this->seeInDatabase('password_resets', [
+             'email' => '[email protected]'
+         ]);
+         $reset = DB::table('password_resets')->where('email', '=', '[email protected]')->first();
+         $this->visit('/password/reset/' . $reset->token)
+             ->see('Reset Password')
+             ->submitForm('Reset Password', [
+                 'email' => '[email protected]',
+                 'password' => 'randompass',
+                 'password_confirmation' => 'randompass'
+             ])->seePageIs('/')
+             ->see('Your password has been successfully reset');
+     }
+     public function test_reset_password_page_shows_sign_links()
+     {
+         $this->setSettings(['registration-enabled' => 'true']);
+         $this->visit('/password/email')
+             ->seeLink('Sign in')
+             ->seeLink('Sign up');
+     }
      /**
       * Perform a login
       * @param string $email
diff --combined tests/ImageTest.php
index 234988ba402c18da448ac0d5714c86f4b88edc50,23373419f21792413a97706aee439787c13dc6aa..031517cdb019d1d9380cf4161fc4dd44346d4399
@@@ -10,7 -10,7 +10,7 @@@ class ImageTest extends TestCas
       */
      protected function getTestImage($fileName)
      {
 -        return new \Illuminate\Http\UploadedFile(base_path('tests/test-image.jpg'), $fileName, 'image/jpeg', 5238);
 +        return new \Illuminate\Http\UploadedFile(base_path('tests/test-data/test-image.jpg'), $fileName, 'image/jpeg', 5238);
      }
  
      /**
          $relPath = $this->uploadImage($imageName, $page->id);
          $this->assertResponseOk();
  
-         $this->assertTrue(file_exists(public_path($relPath)), 'Uploaded image exists');
+         $this->assertTrue(file_exists(public_path($relPath)), 'Uploaded image not found at path: '. public_path($relPath));
  
          $this->deleteImage($relPath);
  
          $this->seeInDatabase('images', [
 -            'url' => url($relPath),
 +            'url' => $this->baseUrl . $relPath,
              'type' => 'gallery',
              'uploaded_to' => $page->id,
              'path' => $relPath,
@@@ -70,7 -70,6 +70,6 @@@
              'updated_by' => $admin->id,
              'name' => $imageName
          ]);
-         
  
      }
  
@@@ -87,7 -86,7 +86,7 @@@
          $this->assertResponseOk();
  
          $this->dontSeeInDatabase('images', [
 -            'url' => $relPath,
 +            'url' => $this->baseUrl . $relPath,
              'type' => 'gallery'
          ]);