diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 9b2d9cc3e..626c7b37a 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -6,8 +6,8 @@ use App\Http\Middleware\RedirectIfAuthenticated; use App\Http\Requests\RegisterRequest; use App\Jobs\RegisterUser; -use App\Jobs\SendEmailConfirmation; use App\User; +use Illuminate\Auth\Events\Registered; use Illuminate\Contracts\Validation\Validator as ValidatorContract; use Illuminate\Foundation\Auth\RegistersUsers; use Illuminate\Support\Facades\Validator; @@ -59,7 +59,7 @@ protected function create(array $data): User { $user = $this->dispatchNow(RegisterUser::fromRequest(app(RegisterRequest::class))); - $this->dispatch(new SendEmailConfirmation($user)); + event(new Registered($user)); return $user; } diff --git a/app/Http/Controllers/Auth/VerificationController.php b/app/Http/Controllers/Auth/VerificationController.php index 4163aaa8b..d71dedfa2 100644 --- a/app/Http/Controllers/Auth/VerificationController.php +++ b/app/Http/Controllers/Auth/VerificationController.php @@ -3,7 +3,12 @@ namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; +use Illuminate\Auth\Access\AuthorizationException; +use Illuminate\Auth\Events\Verified; use Illuminate\Foundation\Auth\VerifiesEmails; +use Illuminate\Http\Request; +use Illuminate\Http\Response; +use Illuminate\Support\Facades\Auth; class VerificationController extends Controller { @@ -25,7 +30,68 @@ class VerificationController extends Controller * * @var string */ - protected $redirectTo = '/home'; + protected $redirectTo = '/dashboard'; + + /** + * Mark the authenticated user's email address as verified. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + * + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function verify(Request $request) + { + if (! hash_equals((string) $request->route('id'), (string) $request->user()->getKey())) { + throw new AuthorizationException(); + } + + if (! hash_equals((string) $request->hash, sha1($request->user()->emailAddress()))) { + throw new AuthorizationException(); + } + + if ($request->user()->hasVerifiedEmail()) { + $this->error('auth.confirmation.no_match'); + return $request->wantsJson() + ? new Response('', 204) + : redirect($this->redirectPath()); + } + + if ($request->user()->markEmailAsVerified()) { + event(new Verified($request->user())); + } + + $this->success('auth.confirmation.success'); + + return $request->wantsJson() + ? new Response('', 204) + : redirect($this->redirectPath())->with('verified', true); + } + + /** + * Resend the email verification notification. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function resend(Request $request) + { + if ($request->user()->hasVerifiedEmail()) { + $this->error('auth.confirmation.already_confirmed'); + + return $request->wantsJson() + ? new Response('', 204) + : redirect($this->redirectPath()); + } + + $request->user()->sendEmailVerificationNotification(); + + $this->success('auth.confirmation.sent', Auth::user()->emailAddress()); + + return $request->wantsJson() + ? new Response('', 202) + : redirect()->route('dashboard')->with('resent', true); + } /** * Create a new controller instance. diff --git a/app/User.php b/app/User.php index be79d3bdc..640421e09 100644 --- a/app/User.php +++ b/app/User.php @@ -8,12 +8,13 @@ use App\Models\Reply; use App\Models\Series; use App\Models\Thread; +use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Support\Facades\Auth; -final class User extends Authenticatable +final class User extends Authenticatable implements MustVerifyEmail { use HasTimestamps; use ModelHelpers; @@ -83,6 +84,11 @@ public function githubUsername(): string return $this->github_username; } + public function emailVerifiedAt(): ?string + { + return $this->email_verified_at; + } + public function gravatarUrl($size = 100): string { $hash = md5(strtolower(trim($this->email))); @@ -93,12 +99,12 @@ public function gravatarUrl($size = 100): string public function isConfirmed(): bool { - return (bool) $this->confirmed; + return ! $this->isUnconfirmed(); } public function isUnconfirmed(): bool { - return ! $this->isConfirmed(); + return is_null($this->emailVerifiedAt()); } public function confirmationCode(): string diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 0184fc1cb..48acb0eab 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -3,7 +3,8 @@ use App\User; use Illuminate\Support\Str; -/** @var \Illuminate\Database\Eloquent\Factory $factory */ +/* @var \Illuminate\Database\Eloquent\Factory $factory */ + $factory->define(User::class, function (Faker\Generator $faker) { static $password; @@ -20,6 +21,7 @@ 'banned_at' => null, 'type' => User::DEFAULT, 'bio' => $faker->sentence, + 'email_verified_at' => null, ]; }); diff --git a/database/migrations/2020_10_01_093001_add_email_verified_at_column_to_users.php b/database/migrations/2020_10_01_093001_add_email_verified_at_column_to_users.php new file mode 100644 index 000000000..13c6e42ba --- /dev/null +++ b/database/migrations/2020_10_01_093001_add_email_verified_at_column_to_users.php @@ -0,0 +1,15 @@ +timestamp('email_verified_at')->nullable(); + }); + } +} diff --git a/resources/views/forum/threads/show.blade.php b/resources/views/forum/threads/show.blade.php index 66aec1f43..0336fe271 100644 --- a/resources/views/forum/threads/show.blade.php +++ b/resources/views/forum/threads/show.blade.php @@ -179,7 +179,7 @@ class="forum-content" @else
You'll need to verify your account before participating in this thread.
- +