route('type'); $profileId = $this->route('id'); $modelClass = 'App\\Models\\' . \Illuminate\Support\Str::studly($type); if (!class_exists($modelClass)) { Log::warning("Authorization failed: Model class does not exist - {$modelClass}"); return false; } $profileModel = $modelClass::find($profileId); if (!$profileModel) { Log::warning("Authorization failed: Profile model not found - {$modelClass} with ID {$profileId}"); return false; } // Check all guards to find authenticated user $loggedInUser = $this->user(); // Try default web guard first // If not on web guard, check other guards if (!$loggedInUser) { $guards = ['organization', 'bank', 'admin']; foreach ($guards as $guard) { $loggedInUser = auth()->guard($guard)->user(); if ($loggedInUser) { Log::info("Found authenticated user on '{$guard}' guard", [ 'user_id' => $loggedInUser->id, 'user_type' => get_class($loggedInUser), ]); break; } } } if (!$loggedInUser) { Log::warning("Authorization failed: No authenticated user on any guard."); return false; } $isAssociated = false; // Flag to track if user is associated with the profile $emailToVerify = null; // --- Check Association and Get Email --- // First check: Is the logged-in entity the same as the profile being verified? if (get_class($loggedInUser) === get_class($profileModel) && $loggedInUser->id === $profileModel->id) { // User is verifying their own profile (e.g., Organization verifying Organization email) $isAssociated = true; $emailToVerify = method_exists($profileModel, 'getEmailForVerification') ? $profileModel->getEmailForVerification() : $profileModel->email; Log::info("Authorization: Logged-in entity is verifying own email", [ 'entity_type' => get_class($profileModel), 'entity_id' => $profileModel->id, ]); } elseif ($profileModel instanceof \App\Models\User) { // Case 1: Profile is a User model (and logged-in user is different) if ($loggedInUser instanceof \App\Models\User && $profileModel->id === $loggedInUser->id) { $isAssociated = true; $emailToVerify = $loggedInUser->getEmailForVerification(); } else { Log::warning("Authorization failed: User ID mismatch. Profile ID: {$profileModel->id}, Logged-in User ID: {$loggedInUser->id}"); } } else { // Case 2: Profile is Organization, Bank, Admin, etc. and logged-in user is a User if ($loggedInUser instanceof \App\Models\User) { // Check 'users' relationship first if (method_exists($profileModel, 'users')) { if ($profileModel->users()->whereKey($loggedInUser->id)->exists()) { $isAssociated = true; } } // If not associated via 'users', check 'managers' relationship elseif (method_exists($profileModel, 'managers')) { if ($profileModel->managers()->whereKey($loggedInUser->id)->exists()) { $isAssociated = true; } } if ($isAssociated) { // Use the profileModel's email for verification $emailToVerify = method_exists($profileModel, 'getEmailForVerification') ? $profileModel->getEmailForVerification() : $profileModel->email; } else { Log::warning("Authorization failed: User ID {$loggedInUser->id} not associated with " . class_basename($profileModel) . " ID {$profileModel->id} via users() or managers()."); } } else { Log::warning("Authorization failed: Logged-in entity is not a User and doesn't match profile", [ 'logged_in_type' => get_class($loggedInUser), 'logged_in_id' => $loggedInUser->id, 'profile_type' => get_class($profileModel), 'profile_id' => $profileModel->id, ]); } } // If user is not associated, deny authorization if (!$isAssociated) { return false; } // --- Compare Hash --- if ($emailToVerify === null) { Log::error("Authorization failed: Could not determine email to verify for " . class_basename($profileModel) . " ID {$profileModel->id}"); return false; // Should not happen if $isAssociated is true, but safety check } $routeHash = (string) $this->route('hash'); if (!hash_equals(sha1($emailToVerify), $routeHash)) { Log::error("Email hash mismatch for " . class_basename($profileModel) . " ID {$profileModel->id}. Email: {$emailToVerify}, Route Hash: {$routeHash}"); return false; } // --- Authorization Successful --- $this->profileModel = $profileModel; Log::info("Authorization successful for email verification of " . class_basename($profileModel) . " id: " . $profileModel->id . " by user id: " . $loggedInUser->id ); return true; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ // ]; } /** * Fulfill the email verification request. * * @return void */ public function fulfill() { Log::info('ProfileEmailVerificationRequest::fulfill() called', [ 'profileModel_class' => $this->profileModel ? get_class($this->profileModel) : 'null', 'profileModel_id' => $this->profileModel?->id, 'hasVerifiedEmail' => $this->profileModel?->hasVerifiedEmail(), 'email_verified_at_before' => $this->profileModel?->email_verified_at, ]); if (!$this->profileModel->hasVerifiedEmail()) { $result = $this->profileModel->markEmailAsVerified(); Log::info('ProfileEmailVerificationRequest::fulfill() markEmailAsVerified result', [ 'result' => $result, 'email_verified_at_after' => $this->profileModel->fresh()->email_verified_at, ]); event(new ProfileVerified($this->profileModel)); Log::info('ProfileEmailVerificationRequest::fulfill() ProfileVerified event dispatched'); } else { Log::info('ProfileEmailVerificationRequest::fulfill() email already verified, skipping'); } } /** * Configure the validator instance. * * @param \Illuminate\Validation\Validator $validator * @return \Illuminate\Validation\Validator */ public function withValidator(Validator $validator) { return $validator; } }