Skip to content

Commit

Permalink
Add password reset functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
francescomalatesta committed Nov 17, 2016
1 parent 0ae517a commit 4f511db
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 0 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ API_SUBTYPE=app
API_VERSION=v1

SIGN_UP_RELEASE_TOKEN=false
PASSWORD_RESET_RELEASE_TOKEN=false
76 changes: 76 additions & 0 deletions app/Api/V1/Controllers/ResetPasswordController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace App\Api\V1\Controllers;

use Config;
use App\User;
use Tymon\JWTAuth\JWTAuth;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Password;
use App\Api\V1\Requests\ResetPasswordRequest;
use Symfony\Component\HttpKernel\Exception\HttpException;

class ResetPasswordController extends Controller
{
public function resetPassword(ResetPasswordRequest $request, JWTAuth $JWTAuth)
{
$response = $this->broker()->reset(
$this->credentials($request), function ($user, $password) {
$this->reset($user, $password);
}
);

if($response !== Password::PASSWORD_RESET) {
throw new HttpException(500);
}

if(!Config::get('boilerplate.reset_password.release_token')) {
return response()->json([
'status' => 'ok',
]);
}

$user = User::where('email', '=', $request->get('email'))->first();

return response()->json([
'status' => 'ok',
'token' => $JWTAuth->fromUser($user)
]);
}

/**
* Get the broker to be used during password reset.
*
* @return \Illuminate\Contracts\Auth\PasswordBroker
*/
public function broker()
{
return Password::broker();
}

/**
* Get the password reset credentials from the request.
*
* @param ResetPasswordRequest $request
* @return array
*/
protected function credentials(ResetPasswordRequest $request)
{
return $request->only(
'email', 'password', 'password_confirmation', 'token'
);
}

/**
* Reset the given user's password.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @param string $password
* @return void
*/
protected function reset($user, $password)
{
$user->password = $password;
$user->save();
}
}
19 changes: 19 additions & 0 deletions app/Api/V1/Requests/ResetPasswordRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace App\Api\V1\Requests;

use Config;
use Dingo\Api\Http\FormRequest;

class ResetPasswordRequest extends FormRequest
{
public function rules()
{
return Config::get('boilerplate.reset_password.validation_rules');
}

public function authorize()
{
return true;
}
}
9 changes: 9 additions & 0 deletions config/boilerplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@
'validation_rules' => [
'email' => 'required|email'
]
],

'reset_password' => [
'release_token' => env('PASSWORD_RESET_RELEASE_TOKEN', false),
'validation_rules' => [
'token' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed'
]
]

];
1 change: 1 addition & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="DB_DATABASE" value="homestead_test"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
Expand Down
1 change: 1 addition & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
$api->post('login', 'App\\Api\\V1\\Controllers\\LoginController@login');

$api->post('recovery', 'App\\Api\\V1\\Controllers\\ForgotPasswordController@sendResetEmail');
$api->post('reset', 'App\\Api\\V1\\Controllers\\ResetPasswordController@resetPassword');
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace App\Functional\Api\V1\Controllers;

use DB;
use Config;
use App\User;
use App\TestCase;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class ResetPasswordControllerTest extends TestCase
{
use DatabaseMigrations;

public function testResetSuccessfully()
{
$this->post('api/reset', [
'email' => 'test@email.com',
'token' => 'my_super_secret_code',
'password' => 'mynewpass',
'password_confirmation' => 'mynewpass'
])->seeJson([
'status' => 'ok'
])->assertResponseOk();
}

public function testResetSuccessfullyWithTokenRelease()
{
Config::set('boilerplate.reset_password.release_token', true);

$this->post('api/reset', [
'email' => 'test@email.com',
'token' => 'my_super_secret_code',
'password' => 'mynewpass',
'password_confirmation' => 'mynewpass'
])->seeJsonStructure([
'status',
'token'
])->seeJson([
'status' => 'ok'
])->assertResponseOk();
}

public function testResetReturnsProcessError()
{
$this->post('api/reset', [
'email' => 'unknown@email.com',
'token' => 'this_code_is_invalid',
'password' => 'mynewpass',
'password_confirmation' => 'mynewpass'
])->seeJsonStructure([
'error'
])->assertResponseStatus(500);
}

public function testResetReturnsValidationError()
{
$this->post('api/reset', [
'email' => 'test@email.com',
'token' => 'my_super_secret_code',
'password' => 'mynewpass'
])->seeJsonStructure([
'error'
])->assertResponseStatus(422);
}

public function setUp()
{
parent::setUp();

$user = new User([
'name' => 'Test User',
'email' => 'test@email.com',
'password' => '123456'
]);
$user->save();

DB::table('password_resets')->insert([
'email' => 'test@email.com',
'token' => 'my_super_secret_code',
'created_at' => Carbon::now()
]);
}
}

0 comments on commit 4f511db

Please sign in to comment.