diff --git a/app/Events/UserRegistered.php b/app/Events/UserRegistered.php deleted file mode 100644 index 1bd6ce32b..000000000 --- a/app/Events/UserRegistered.php +++ /dev/null @@ -1,16 +0,0 @@ -user = $user; - } -} diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 226d7e255..7f779af9d 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -18,6 +18,7 @@ use App\Services\UserService; use App\Support\Timezonelist; use App\Support\Utils; +use Illuminate\Auth\Events\Verified; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; @@ -323,6 +324,52 @@ public function regen_apikey(int $id, Request $request): RedirectResponse return redirect(route('admin.users.edit', [$id])); } + public function verify_email(int $id, Request $request): RedirectResponse + { + $user = $this->userRepo->findWithoutFail($id); + + if (empty($user)) { + Flash::error('User not found'); + return back(); + } + + if ($user->hasVerifiedEmail()) { + Flash::error('User email already verified'); + return back(); + } + + if ($user->markEmailAsVerified()) { + event(new Verified($user)); + } + + Flash::success('User email verified successfully'); + return back(); + } + + public function request_email_verification(int $id, Request $request): RedirectResponse + { + $user = $this->userRepo->findWithoutFail($id); + + if (empty($user)) { + Flash::error('User not found'); + return back(); + } + + if (!$user->hasVerifiedEmail()) { + Flash::error('User email already not verified'); + return back(); + } + + $user->update([ + 'email_verified_at' => null, + ]); + + $user->sendEmailVerificationNotification(); + + Flash::success('User email verification requested successfully'); + return back(); + } + /** * Get the type ratings that are available to the user * diff --git a/app/Http/Controllers/Auth/VerificationController.php b/app/Http/Controllers/Auth/VerificationController.php index 92d5594d5..e52fa20f5 100644 --- a/app/Http/Controllers/Auth/VerificationController.php +++ b/app/Http/Controllers/Auth/VerificationController.php @@ -2,8 +2,13 @@ namespace App\Http\Controllers\Auth; +use App\Models\User; +use Illuminate\Auth\Access\AuthorizationException; +use Illuminate\Auth\Events\Verified; use Illuminate\Foundation\Auth\VerifiesEmails; +use Illuminate\Http\Request; use Illuminate\Routing\Controller; +use Illuminate\Support\Facades\Log; class VerificationController extends Controller { @@ -24,7 +29,7 @@ class VerificationController extends Controller * * @var string */ - protected $redirectTo = '/dashboard'; + protected string $redirectTo = '/dashboard'; /** * Create a new controller instance. @@ -33,8 +38,31 @@ class VerificationController extends Controller */ public function __construct() { - $this->middleware('auth'); $this->middleware('signed')->only('verify'); $this->middleware('throttle:6,1')->only('verify', 'resend'); } + + public function verify(Request $request) + { + $user = User::find($request->route('id')); + + if (!hash_equals((string) $request->route('id'), (string) $user->getKey())) { + throw new AuthorizationException(); + } + + if (!hash_equals((string) $request->route('hash'), sha1($user->getEmailForVerification()))) { + throw new AuthorizationException(); + } + + if ($user->hasVerifiedEmail()) { + return redirect($this->redirectPath()); + } + + if ($user->markEmailAsVerified()) { + Log::info('Marking user '.$user->id.' as verified'); + event(new Verified($user)); + } + + return redirect($this->redirectPath())->with('verified', true); + } } diff --git a/app/Http/Controllers/Frontend/ProfileController.php b/app/Http/Controllers/Frontend/ProfileController.php index b6d614163..a955153a3 100644 --- a/app/Http/Controllers/Frontend/ProfileController.php +++ b/app/Http/Controllers/Frontend/ProfileController.php @@ -213,8 +213,19 @@ public function update(Request $request): RedirectResponse $req_data['avatar'] = $path; } + // User needs to verify their new email address + if ($user->email != $request->input('email')) { + $req_data['email_verified_at'] = null; + } + $this->userRepo->update($req_data, $id); + // We need to get a new instance of the user in order to send the verification email to the new email address + if ($user->email != $request->input('email')) { + $newUser = $this->userRepo->findWithoutFail($user->id); + $newUser->sendEmailVerificationNotification(); + } + // Save all of the user fields $userFields = UserField::all(); foreach ($userFields as $field) { diff --git a/app/Models/User.php b/app/Models/User.php index 058b986e2..779661722 100755 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -35,7 +35,7 @@ * @property string home_airport_id * @property string avatar * @property Airline airline - * @property Flight[] flights + * @property int flights * @property int flight_time * @property int transfer_time * @property string remember_token diff --git a/app/Notifications/NotificationEventsHandler.php b/app/Notifications/NotificationEventsHandler.php index 2d405ed2b..c77bb523b 100644 --- a/app/Notifications/NotificationEventsHandler.php +++ b/app/Notifications/NotificationEventsHandler.php @@ -10,14 +10,15 @@ use App\Events\PirepPrefiled; use App\Events\PirepRejected; use App\Events\PirepStatusChange; -use App\Events\UserRegistered; use App\Events\UserStateChanged; +use App\Events\UserStatsChanged; use App\Models\Enums\PirepStatus; use App\Models\Enums\UserState; use App\Models\User; use App\Notifications\Messages\UserRejected; use App\Notifications\Notifiables\Broadcast; use Exception; +use Illuminate\Auth\Events\Verified; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Notification; @@ -37,9 +38,9 @@ class NotificationEventsHandler extends Listener PirepAccepted::class => 'onPirepAccepted', PirepFiled::class => 'onPirepFile', PirepRejected::class => 'onPirepRejected', - UserRegistered::class => 'onUserRegister', UserStateChanged::class => 'onUserStateChange', UserStatsChanged::class => 'onUserStatsChanged', + Verified::class => 'onEmailVerified', ]; public function __construct() @@ -113,13 +114,13 @@ protected function notifyAllUsers(\App\Contracts\Notification $notification) } } - /** - * Send an email when the user registered - * - * @param UserRegistered $event - */ - public function onUserRegister(UserRegistered $event): void + public function onEmailVerified(Verified $event): void { + // Return if the user has any flights (email change / admin requests new verification) + if ($event->user->flights > 0) { + return; + } + Log::info('NotificationEvents::onUserRegister: ' .$event->user->ident.' is ' .UserState::label($event->user->state).', sending active email'); diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 24cb9dfc4..b4942d7ee 100755 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -461,6 +461,12 @@ private function mapAdminRoutes() Route::get('users/{id}/regen_apikey', 'UserController@regen_apikey') ->name('users.regen_apikey')->middleware('ability:admin,users'); + Route::get('users/{id}/verify_email', 'UserController@verify_email') + ->name('users.verify_email')->middleware('ability:admin,users'); + + Route::get('users/{id}/request_email_verification', 'UserController@request_email_verification') + ->name('users.request_email_verification')->middleware('ability:admin,users'); + Route::resource('users', 'UserController')->middleware('ability:admin,users'); Route::match([ diff --git a/app/Services/UserService.php b/app/Services/UserService.php index 48c9ccb67..6da6271c8 100644 --- a/app/Services/UserService.php +++ b/app/Services/UserService.php @@ -3,7 +3,6 @@ namespace App\Services; use App\Contracts\Service; -use App\Events\UserRegistered; use App\Events\UserStateChanged; use App\Events\UserStatsChanged; use App\Exceptions\PilotIdNotFound; @@ -25,6 +24,7 @@ use App\Support\Units\Time; use App\Support\Utils; use Carbon\Carbon; +use Illuminate\Auth\Events\Registered; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Log; @@ -115,7 +115,7 @@ public function createUser(array $attrs, array $roles = []): User $this->calculatePilotRank($user); $user->refresh(); - event(new UserRegistered($user)); + event(new Registered($user)); return $user; } diff --git a/config/phpvms.php b/config/phpvms.php index c7d2e756f..7dc2e914b 100644 --- a/config/phpvms.php +++ b/config/phpvms.php @@ -124,6 +124,6 @@ * Enable/disable email verification on registration */ 'registration' => [ - 'email_verification' => true, + 'email_verification' => env('EMAIL_VERIFICATION_REQUIRED', true), ], ]; diff --git a/resources/views/admin/users/fields.blade.php b/resources/views/admin/users/fields.blade.php index c0ef30cfe..34a0daa61 100644 --- a/resources/views/admin/users/fields.blade.php +++ b/resources/views/admin/users/fields.blade.php @@ -90,6 +90,12 @@