diff --git a/app/Http/Controllers/User/EmailValidationController.php b/app/Http/Controllers/User/EmailValidationController.php index f2c6a9ce0f..9e4dc50fbc 100644 --- a/app/Http/Controllers/User/EmailValidationController.php +++ b/app/Http/Controllers/User/EmailValidationController.php @@ -11,6 +11,10 @@ class EmailValidationController extends Controller { public function validateEmail(Request $request, User $user) { + if (!(auth()->check() && auth()->user()->id == $user->id)) { + return response()->redirectTo(route('settings.subscription'))->withError(__('emails/validation.error')); + } + $token = $request->get('token'); /** @var UserValidation $validation */ diff --git a/app/Jobs/Emails/Subscriptions/EmailValidationJob.php b/app/Jobs/Emails/Subscriptions/EmailValidationJob.php index e9889ae710..8ac4cf6b32 100644 --- a/app/Jobs/Emails/Subscriptions/EmailValidationJob.php +++ b/app/Jobs/Emails/Subscriptions/EmailValidationJob.php @@ -18,9 +18,8 @@ class EmailValidationJob implements ShouldQueue use Queueable; use SerializesModels; - /** @var int user id */ - protected $user; - protected $token; + protected int $user; + protected string $token; /** */ @@ -41,12 +40,12 @@ public function handle() if (empty($user)) { return; } - + $url = route('validation.email', ['user' => $user, 'token' => $this->token]); // Send an email to the user Mail::to($user->email) ->locale($user->locale) ->send( - new ValidationEmail($user, $this->token) + new ValidationEmail($user, $url) ); } } diff --git a/app/Mail/Subscription/User/ValidationEmail.php b/app/Mail/Subscription/User/ValidationEmail.php index 3de9ab7f08..c29a958c90 100644 --- a/app/Mail/Subscription/User/ValidationEmail.php +++ b/app/Mail/Subscription/User/ValidationEmail.php @@ -12,11 +12,8 @@ class ValidationEmail extends Mailable use Queueable; use SerializesModels; - /** - * @var User - */ - public $user; - public $token; + public User $user; + public string $url; public $date; @@ -26,10 +23,10 @@ class ValidationEmail extends Mailable * * @return void */ - public function __construct(User $user, string $token) + public function __construct(User $user, string $url) { $this->user = $user; - $this->token = $token; + $this->url = $url; } /** diff --git a/app/Models/Relations/UserRelations.php b/app/Models/Relations/UserRelations.php index f7bd50e259..22ae7fac6f 100644 --- a/app/Models/Relations/UserRelations.php +++ b/app/Models/Relations/UserRelations.php @@ -18,6 +18,7 @@ use App\Models\UserApp; use App\Models\UserFlag; use App\Models\Users\Tutorial; +use App\Models\UserValidation; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -199,4 +200,9 @@ public function upvotes(): HasMany { return $this->hasMany(FeatureVote::class); } + + public function userValidation(): HasMany + { + return $this->hasOne(UserValidation::class, 'user_id', 'id'); + } } diff --git a/app/Models/Scopes/UserScope.php b/app/Models/Scopes/UserScope.php index db2c38a2a0..5b1d2763d2 100644 --- a/app/Models/Scopes/UserScope.php +++ b/app/Models/Scopes/UserScope.php @@ -1,6 +1,7 @@ where(['is_valid' => $valid]); + } } diff --git a/app/Services/Users/EmailValidationService.php b/app/Services/Users/EmailValidationService.php new file mode 100644 index 0000000000..b97963f84d --- /dev/null +++ b/app/Services/Users/EmailValidationService.php @@ -0,0 +1,43 @@ +user->id)->first(); + if ($token && $token->is_valid) { + return; + } + //Check for existing token + $flag = UserFlag::where('user_id', $this->user->id)->where('flag', UserFlag::FLAG_EMAIL)->first(); + + if (!$flag) { + $flag = new UserFlag(); + $flag->user_id = $this->user->id; + $flag->flag = UserFlag::FLAG_EMAIL; + $flag->save(); + } + + if (!$token) { + $token = new UserValidation(); + $token->token = Str::uuid(); + $token->user_id = $this->user->id; + $token->is_valid = false; + $token->save(); + } + + EmailValidationJob::dispatch($this->user, $token->token); + + return; + } +} diff --git a/app/User.php b/app/User.php index 20da4ec5f9..149b446c04 100644 --- a/app/User.php +++ b/app/User.php @@ -17,11 +17,8 @@ use App\Models\Scopes\UserScope; use App\Models\UserLog; use App\Models\UserSetting; -use App\Models\UserFlag; -use App\Models\UserValidation; use App\Models\Relations\UserRelations; use Carbon\Carbon; -use App\Jobs\Emails\Subscriptions\EmailValidationJob; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Notifications\Notifiable; use Illuminate\Support\Collection; @@ -437,7 +434,7 @@ public function isFrauding(): bool return false; } - $validation = UserValidation::where('user_id', $this->id)->where('is_valid', true)->first(); + $validation = $this->userValidation->valid()->first(); if ($validation) { return false; } @@ -462,35 +459,6 @@ public function isFrauding(): bool ->count() >= 2; } - public function requiresEmail(): self - { - $token = UserValidation::where('user_id', $this->id)->first(); - if ($token && $token->is_valid) { - return $this; - } - //Check for existing token - $flag = UserFlag::where('user_id', $this->id)->where('flag', UserFlag::FLAG_EMAIL)->first(); - - if (!$flag) { - $flag = new UserFlag(); - $flag->user_id = $this->id; - $flag->flag = UserFlag::FLAG_EMAIL; - $flag->save(); - } - - if (!$token) { - $token = new UserValidation(); - $token->token = Str::uuid(); - $token->user_id = $this->id; - $token->is_valid = false; - $token->save(); - } - - EmailValidationJob::dispatch($this, $token->token); - - return $this; - } - /** * List of campaigns the user is the only admin of. This is used for the automatic purge warning emails */ diff --git a/database/migrations/2024_01_22_203110_create_user_validations_table.php b/database/migrations/2024_01_22_203110_create_user_validations_table.php index b558a10a04..8e9d5d04a1 100644 --- a/database/migrations/2024_01_22_203110_create_user_validations_table.php +++ b/database/migrations/2024_01_22_203110_create_user_validations_table.php @@ -14,7 +14,7 @@ public function up(): void $table->id(); $table->uuid('token'); $table->unsignedInteger('user_id'); - $table->boolean('is_valid'); + $table->boolean('is_valid')->default(false); $table->timestamps(); $table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete(); diff --git a/resources/views/emails/subscriptions/validation/user-html.blade.php b/resources/views/emails/subscriptions/validation/user-html.blade.php index c6e49893ff..3ff9514665 100644 --- a/resources/views/emails/subscriptions/validation/user-html.blade.php +++ b/resources/views/emails/subscriptions/validation/user-html.blade.php @@ -1,5 +1,5 @@ @extends('emails.base', [ - 'utmSource' => 'subscription', + 'utmSource' => 'validation', 'utmCampaign' => 'failed-charge' ]) @@ -12,8 +12,8 @@

This is an automatic notification.

-

To validate the email for your Kanka account click here. This link will expire in 24 hours.

-

If the above link doesnt work, open the following URL in your web browser {{ 'https://app.kanka.io/users/' . $user->id . '/validation?token=' . $token }}

+

To validate the email for your Kanka account click here. This link will expire in 24 hours.

+

If the above link doesnt work, open the following URL in your web browser {{ $url }}

{{ __('emails/subscriptions/upcoming.closing') }}
The Kanka Team diff --git a/resources/views/settings/subscription/change.blade.php b/resources/views/settings/subscription/change.blade.php index d8aba330d3..ca127a6ac8 100644 --- a/resources/views/settings/subscription/change.blade.php +++ b/resources/views/settings/subscription/change.blade.php @@ -6,8 +6,10 @@ @if (!$user->isFrauding()) + @inject('emailService', 'App\Services\Users\EmailValidationService') @php - $user->requiresEmail(); + /** @var \App\Services\Users\EmailValidationService $emailService */ + $emailService->user($user)->requiresEmail(); @endphp {{ __('emails/validation.modal') }} @@ -79,7 +81,7 @@

  • - Giropay + giropay
  • @endif