Skip to content

Commit 6f24f8d

Browse files
committed
Adds password reset support
1 parent 2b4f55a commit 6f24f8d

10 files changed

+172
-101
lines changed

.editorconfig

+2
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@ trim_trailing_whitespace = true
99
insert_final_newline = true
1010
[*.php]
1111
indent_size = 4
12+
[*.blade.php]
13+
indent_size = 2
1214
[*.md]
1315
trim_trailing_whitespace = false

app/Http/Controllers/AuthController.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function store(Request $request)
1717
return response()->json(['error' => 'Invalid Credentials'], 401);
1818
}
1919

20-
return response()->json([], 204);
20+
return response()->noContent();
2121
}
2222

2323
public function destroy()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
namespace Knot\Http\Controllers;
4+
5+
use Illuminate\Support\Str;
6+
use Illuminate\Http\Request;
7+
use Illuminate\Support\Facades\Hash;
8+
use Illuminate\Support\Facades\Password;
9+
use Illuminate\Auth\Events\PasswordReset;
10+
11+
class PasswordResetsController extends Controller
12+
{
13+
public function show(Request $request, $token)
14+
{
15+
return view('auth.reset-password', ['token' => $token]);
16+
}
17+
18+
public function store(Request $request)
19+
{
20+
$validated = $request->validate([
21+
'email' => 'required|email|exists:users',
22+
]);
23+
24+
$status = Password::sendResetLink(
25+
$request->only('email')
26+
);
27+
28+
if ($status === Password::RESET_LINK_SENT) {
29+
response()->noContent();
30+
}
31+
32+
return response(['email' => $status], 500);
33+
}
34+
35+
public function update(Request $request)
36+
{
37+
$request->validate([
38+
'token' => 'required',
39+
'email' => 'required|email',
40+
'password' => 'required|confirmed',
41+
]);
42+
43+
$status = Password::reset(
44+
$request->only('email', 'password', 'password_confirmation', 'token'),
45+
function ($user, $password) {
46+
$user->forceFill([
47+
'password' => $password
48+
])->save();
49+
50+
$user->setRememberToken(Str::random(60));
51+
52+
event(new PasswordReset($user));
53+
}
54+
);
55+
56+
return $status == Password::PASSWORD_RESET
57+
? response('Your password has been successfully reset. You may now go back to the app and sign in with your new password.', 200)
58+
: back()->withErrors(['email' => trans($status)]);
59+
}
60+
}

app/Http/Controllers/ProfileController.php

+9-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Http\Request;
66
use Illuminate\Support\Facades\Hash;
7+
use Illuminate\Validation\Rule;
78
use Knot\Models\User;
89

910
class ProfileController extends Controller
@@ -40,14 +41,18 @@ public function updateInfo(Request $request)
4041

4142
$request->validate([
4243
'first_name' => 'required',
43-
'email' => 'required|email|unique:users',
44-
'current_password' => 'required_with:password',
45-
'password' => 'confirmed',
44+
'email' => [
45+
'required',
46+
'email',
47+
Rule::unique('users')->ignore(auth()->id()),
48+
],
49+
'current_password' => 'nullable|required_with:password',
50+
'password' => 'nullable|confirmed',
4651
]);
4752

4853
$user->update($request->only('first_name', 'last_name', 'email'));
4954

50-
if ($request->has('current_password')) {
55+
if ($request->filled('current_password')) {
5156
if (Hash::check($request->current_password, $user->password)) {
5257
$user->update(['password' => $request->password]);
5358
} else {

app/Http/Middleware/VerifyCsrfToken.php

+1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ class VerifyCsrfToken extends Middleware
2020
*/
2121
protected $except = [
2222
'register',
23+
'forgot-password'
2324
];
2425
}

config/cors.php

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
'logout',
2222
'register',
2323
'api/*',
24+
'forgot-password',
2425
],
2526

2627
'allowed_methods' => ['*'],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<!DOCTYPE html>
2+
<html lang="{{ config('app.locale') }}">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
8+
<title>Reset Your Password</title>
9+
10+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap">
11+
12+
<!-- Styles -->
13+
<style>
14+
*,*::before,*::after {
15+
box-sizing: border-box;
16+
}
17+
html, body {
18+
font-family: 'Inter UI var', 'Inter UI', sans-serif;
19+
font-size: 16px;
20+
height: 100vh;
21+
margin: 0;
22+
}
23+
24+
form {
25+
display: flex;
26+
flex-direction: column;
27+
}
28+
29+
.container {
30+
width: 100%;
31+
max-width: 90vw;
32+
margin: 0 auto;
33+
}
34+
35+
h1 {
36+
color: #4b5563;
37+
}
38+
39+
input {
40+
-webkit-appearance: none;
41+
appearance: none;
42+
transition: border-color 150ms ease;
43+
border: 2px solid #e5e7eb;
44+
border-radius: 0.25rem;
45+
color: #374151;
46+
height: 3rem;
47+
margin-top: 16px;
48+
outline: none;
49+
padding: 0 0.75rem;
50+
51+
}
52+
53+
input:focus {
54+
border-color: #f56565;
55+
}
56+
57+
button {
58+
background-color: #e02424;
59+
border-radius: 0.25rem;
60+
border: none;
61+
color: #fff;
62+
cursor: pointer;
63+
font-weight: 700;
64+
letter-spacing: 0.1em;
65+
margin-top: 16px;
66+
padding: 0.75rem 0;
67+
text-transform: uppercase;
68+
}
69+
70+
button:focus {
71+
outline: 0;
72+
box-shadow: 0 0 0 3px rgba(248, 180, 180, 0.45);
73+
}
74+
</style>
75+
</head>
76+
<body>
77+
<div class="container">
78+
<h1>Reset Your Password</h1>
79+
<form action="/reset-password" method="POST">
80+
@csrf
81+
<input type="hidden" name="token" value="{{ $token }}">
82+
<input type="hidden" name="email" value="{{ request('email') }}">
83+
<input type="password" name="password" placeholder="Enter a new password">
84+
<input type="password" name="password_confirmation" placeholder="Confirm password">
85+
<button type="submit">Reset Password</button>
86+
</form>
87+
</div>
88+
</body>
89+
</html>

resources/views/welcome.blade.php

-95
This file was deleted.

routes/api.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
Route::post('/friendships/unfriend/{friend}', 'FriendshipsController@unfriend');
4040

4141
Route::post('/generate-cloudinary-signature', function (Request $request) {
42-
return ApiUtils::signParameters(config('services.cloudinary.secret'), $request->only('timestamp', 'upload_preset'));
42+
43+
$request->validate([
44+
'timestamp' => 'required',
45+
]);
46+
47+
return ApiUtils::signParameters(config('services.cloudinary.secret'), $request->only('timestamp', 'upload_preset', 'folder'));
4348
});
4449
});

routes/web.php

+3
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@
1818
Route::post('login', 'AuthController@store');
1919
Route::post('register', 'UserController@store');
2020
Route::post('logout', 'AuthController@destroy');
21+
Route::post('forgot-password', 'PasswordResetsController@store');
22+
Route::get('reset-password/{token}', 'PasswordResetsController@show')->name('password.reset');
23+
Route::post('reset-password', 'PasswordResetsController@update')->name('password.update');

0 commit comments

Comments
 (0)