194 lines
7.6 KiB
PHP
194 lines
7.6 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Requests;
|
|
|
|
use App\Events\ProfileVerified;
|
|
use Illuminate\Foundation\Http\FormRequest;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Validation\Validator;
|
|
|
|
class ProfileEmailVerificationRequest extends FormRequest
|
|
{
|
|
public $profileModel;
|
|
|
|
/**
|
|
* Determine if the user is authorized to make this request.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function authorize()
|
|
{
|
|
$type = $this->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;
|
|
}
|
|
}
|