Skip to content

Commit 61277c3

Browse files
committed
Add forgot password and update password mutations
1 parent 7ce50d9 commit 61277c3

File tree

10 files changed

+253
-5
lines changed

10 files changed

+253
-5
lines changed

graphql/auth.graphql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,26 @@ type LogoutResponse {
1919
message: String
2020
}
2121

22+
type ForgotPasswordResponse {
23+
status: String!
24+
message: String
25+
}
26+
27+
input ForgotPasswordInput {
28+
email: String!
29+
}
30+
31+
input NewPasswordWithCodeInput {
32+
email: String!
33+
token: String!
34+
password: String!
35+
password_confirmation: String!
36+
}
37+
2238
extend type Mutation {
2339
login(data: LoginInput): AuthPayload! @field(resolver: "Joselfonseca\\LighthouseGraphQLPassport\\GraphQL\\Mutations\\Login@resolve")
2440
refreshToken(data: RefreshTokenInput): AuthPayload! @field(resolver: "Joselfonseca\\LighthouseGraphQLPassport\\GraphQL\\Mutations\\RefreshToken@resolve")
2541
logout: LogoutResponse! @field(resolver: "Joselfonseca\\LighthouseGraphQLPassport\\GraphQL\\Mutations\\Logout@resolve")
42+
forgotPassword(data: ForgotPasswordInput!): ForgotPasswordResponse! @field(resolver: "Joselfonseca\\LighthouseGraphQLPassport\\GraphQL\\Mutations\\ForgotPassword@resolve")
43+
updateForgottenPassword(data: NewPasswordWithCodeInput): ForgotPasswordResponse! @field(resolver: "Joselfonseca\\LighthouseGraphQLPassport\\GraphQL\\Mutations\\ResetPassword@resolve")
2644
}

phpunit.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
processIsolation="false"
1111
stopOnFailure="false">
1212
<testsuites>
13-
<testsuite name="Laravel Tactician Test Suite">
13+
<testsuite name="Integration Test Suite">
14+
<directory suffix=".php">./tests/Integration/</directory>
15+
</testsuite>
16+
<testsuite name="All Test Suite">
1417
<directory suffix=".php">./tests/</directory>
1518
</testsuite>
1619
</testsuites>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace Joselfonseca\LighthouseGraphQLPassport\Exceptions;
4+
5+
use Exception;
6+
use Nuwave\Lighthouse\Exceptions\RendersErrorsExtensions;
7+
8+
/**
9+
* Class ValidationException
10+
*
11+
* @package Joselfonseca\LighthouseGraphQLPassport\Exceptions
12+
*/
13+
class ValidationException extends Exception implements RendersErrorsExtensions
14+
{
15+
/**
16+
* @var
17+
*/
18+
public $errors;
19+
20+
/**
21+
* ValidationException constructor.
22+
*
23+
* @param $validator
24+
* @param string $message
25+
*/
26+
public function __construct($errors, string $message = "")
27+
{
28+
parent::__construct($message);
29+
30+
$this->errors = $errors;
31+
}
32+
33+
/**
34+
* The category.
35+
*
36+
* @var string
37+
*/
38+
protected $category = 'validation';
39+
40+
/**
41+
* Returns true when exception message is safe to be displayed to a client.
42+
*
43+
* @api
44+
* @return bool
45+
*/
46+
public function isClientSafe(): bool
47+
{
48+
return true;
49+
}
50+
51+
/**
52+
* @return string
53+
*/
54+
public function getCategory(): string
55+
{
56+
return 'validation';
57+
}
58+
59+
/**
60+
* @return array
61+
*/
62+
public function extensionsContent(): array
63+
{
64+
return ['errors' => $this->errors];
65+
}
66+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Joselfonseca\LighthouseGraphQLPassport\GraphQL\Mutations;
4+
5+
use GraphQL\Type\Definition\ResolveInfo;
6+
use Illuminate\Support\Facades\Password;
7+
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
8+
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
9+
10+
class ForgotPassword
11+
{
12+
13+
use SendsPasswordResetEmails;
14+
/**
15+
* @param $rootValue
16+
* @param array $args
17+
* @param \Nuwave\Lighthouse\Support\Contracts\GraphQLContext|null $context
18+
* @param \GraphQL\Type\Definition\ResolveInfo $resolveInfo
19+
* @return array
20+
* @throws \Exception
21+
*/
22+
public function resolve($rootValue, array $args, GraphQLContext $context = null, ResolveInfo $resolveInfo)
23+
{
24+
$response = $this->broker()->sendResetLink(['email' => $args['data']['email']]);
25+
if ($response == Password::RESET_LINK_SENT) {
26+
return [
27+
'status' => 'EMAIL_SENT',
28+
'message' => trans($response)
29+
];
30+
}
31+
return [
32+
'status' => 'EMAIL_NOT_SENT',
33+
'message' => trans($response)
34+
];
35+
}
36+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
namespace Joselfonseca\LighthouseGraphQLPassport\GraphQL\Mutations;
4+
5+
use Illuminate\Support\Facades\Hash;
6+
use GraphQL\Type\Definition\ResolveInfo;
7+
use Illuminate\Support\Facades\Password;
8+
use Illuminate\Auth\Events\PasswordReset;
9+
use Illuminate\Foundation\Auth\ResetsPasswords;
10+
use Illuminate\Validation\ValidationException;
11+
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
12+
use Illuminate\Foundation\Validation\ValidatesRequests;
13+
use Joselfonseca\LighthouseGraphQLPassport\Exceptions\ValidationException as GraphQLValidationException;
14+
15+
class ResetPassword
16+
{
17+
use ResetsPasswords, ValidatesRequests;
18+
19+
public function resolve($rootValue, array $args, GraphQLContext $context = null, ResolveInfo $resolveInfo)
20+
{
21+
try {
22+
$this->validate($args['data'], $this->rules());
23+
} catch (ValidationException $e) {
24+
throw new GraphQLValidationException($e->errors(), "Input validation failed");
25+
}
26+
27+
$response = $this->broker()->reset($args['data'], function ($user, $password) {
28+
$this->resetPassword($user, $password);
29+
});
30+
31+
if($response === Password::PASSWORD_RESET) {
32+
return [
33+
'status' => 'PASSWORD_UPDATED',
34+
'message' => trans($response)
35+
];
36+
}
37+
38+
return [
39+
'status' => 'PASSWORD_NOT_UPDATED',
40+
'message' => trans($response)
41+
];
42+
}
43+
44+
/**
45+
* @return array
46+
*/
47+
protected function rules()
48+
{
49+
return [
50+
'token' => 'required',
51+
'email' => 'required|email',
52+
'password' => 'required|confirmed|min:6',
53+
];
54+
}
55+
56+
/**
57+
* @param array $data
58+
* @param array $rules
59+
* @param array $messages
60+
* @param array $customAttributes
61+
* @return mixed
62+
*/
63+
public function validate(array $data, array $rules, array $messages = [], array $customAttributes = [])
64+
{
65+
return $this->getValidationFactory()->make($data, $rules, $messages, $customAttributes)->validate();
66+
}
67+
68+
/**
69+
* Reset the given user's password.
70+
*
71+
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
72+
* @param string $password
73+
* @return void
74+
*/
75+
protected function resetPassword($user, $password)
76+
{
77+
$user->password = Hash::make($password);
78+
79+
$user->save();
80+
81+
event(new PasswordReset($user));
82+
83+
}
84+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace Joselfonseca\LighthouseGraphQLPassport\Tests\Integration\GraphQL\Mutations;
4+
5+
use Illuminate\Support\Facades\Mail;
6+
use Illuminate\Support\Facades\Notification;
7+
use Illuminate\Auth\Notifications\ResetPassword;
8+
use Joselfonseca\LighthouseGraphQLPassport\Tests\User;
9+
use Joselfonseca\LighthouseGraphQLPassport\Tests\TestCase;
10+
11+
class ForgotPassword extends TestCase
12+
{
13+
function test_it_sends_recover_password_email()
14+
{
15+
Mail::fake();
16+
Notification::fake();
17+
$this->createClient();
18+
$user = User::create([
19+
'name' => 'Jose Fonseca',
20+
'email' => 'jose@example.com',
21+
'password' => bcrypt('123456789qq')
22+
]);
23+
$response = $this->postGraphQL([
24+
'query' => 'mutation {
25+
forgotPassword(data: {
26+
email: "jose@example.com"
27+
}) {
28+
status
29+
message
30+
}
31+
}'
32+
]);
33+
$responseBody = json_decode($response->getContent(), true);
34+
$this->assertArrayHasKey('forgotPassword', $responseBody['data']);
35+
$this->assertArrayHasKey('status', $responseBody['data']['forgotPassword']);
36+
$this->assertArrayHasKey('message', $responseBody['data']['forgotPassword']);
37+
$this->assertEquals('EMAIL_SENT', $responseBody['data']['forgotPassword']['status']);
38+
Notification::assertSentTo($user, ResetPassword::class);
39+
}
40+
}

tests/GraphQL/Mutations/LoginTest.php renamed to tests/Integration/GraphQL/Mutations/LoginTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace Joselfonseca\LighthouseGraphQLPassport\Tests\GraphQL\Mutations;
3+
namespace Joselfonseca\LighthouseGraphQLPassport\Tests\Integration\GraphQL\Mutations;
44

55
use Joselfonseca\LighthouseGraphQLPassport\Tests\User;
66
use Joselfonseca\LighthouseGraphQLPassport\Tests\TestCase;

tests/GraphQL/Mutations/Logout.php renamed to tests/Integration/GraphQL/Mutations/Logout.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace Joselfonseca\LighthouseGraphQLPassport\Tests\GraphQL\Mutations;
3+
namespace Joselfonseca\LighthouseGraphQLPassport\Tests\Integration\GraphQL\Mutations;
44

55
use Joselfonseca\LighthouseGraphQLPassport\Tests\User;
66
use Joselfonseca\LighthouseGraphQLPassport\Tests\TestCase;

tests/GraphQL/Mutations/RefreshToken.php renamed to tests/Integration/GraphQL/Mutations/RefreshToken.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace Joselfonseca\LighthouseGraphQLPassport\Tests\GraphQL\Mutations;
3+
namespace Joselfonseca\LighthouseGraphQLPassport\Tests\Integration\GraphQL\Mutations;
44

55
use Joselfonseca\LighthouseGraphQLPassport\Tests\User;
66
use Joselfonseca\LighthouseGraphQLPassport\Tests\TestCase;

tests/User.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Joselfonseca\LighthouseGraphQLPassport\Tests;
44

55
use Laravel\Passport\HasApiTokens;
6+
use Illuminate\Notifications\Notifiable;
67
use Illuminate\Foundation\Auth\User as Authenticatable;
78

89
/**
@@ -12,7 +13,7 @@
1213
*/
1314
class User extends Authenticatable
1415
{
15-
use HasApiTokens;
16+
use HasApiTokens, Notifiable;
1617

1718
/**
1819
* The attributes that are mass assignable.

0 commit comments

Comments
 (0)