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 }}
+
+ {{ __('emails/subscriptions/upcoming.closing') }}
+ The Kanka Team
+
@endif
diff --git a/routes/web.php b/routes/web.php
index 51264ab619..b1222b5cb9 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -34,3 +34,5 @@
Route::get('roadmap/{feature}', [App\Http\Controllers\Roadmap\FeatureController::class, 'show'])->name('roadmap.feature.show');
Route::post('roadmap/{feature}/upvote', [App\Http\Controllers\Roadmap\FeatureController::class, 'upvote'])->name('roadmap.upvote');
Route::post('roadmap/submit', [App\Http\Controllers\Roadmap\FeatureController::class, 'store'])->name('roadmap.store');
+
+Route::get('/users/{user}/validation', [App\Http\Controllers\User\EmailValidationController::class, 'validateEmail'])->name('validation.email');
From 018bc97160a0d442ff28c0e7ecfe2d21d0e6fbf9 Mon Sep 17 00:00:00 2001
From: spitfire305
Date: Wed, 24 Jan 2024 22:52:41 +0000
Subject: [PATCH 2/9] Fix styling
---
app/Http/Controllers/User/EmailValidationController.php | 4 +---
app/Jobs/Emails/Subscriptions/EmailValidationJob.php | 1 -
app/Mail/Subscription/User/ValidationEmail.php | 1 -
app/Observers/CampaignObserver.php | 2 +-
app/Renderers/DatagridRenderer2.php | 2 +-
app/User.php | 2 +-
.../2024_01_22_203110_create_user_validations_table.php | 3 +--
7 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/app/Http/Controllers/User/EmailValidationController.php b/app/Http/Controllers/User/EmailValidationController.php
index 57eeb203d4..f2c6a9ce0f 100644
--- a/app/Http/Controllers/User/EmailValidationController.php
+++ b/app/Http/Controllers/User/EmailValidationController.php
@@ -7,10 +7,8 @@
use App\User;
use Illuminate\Http\Request;
-
class EmailValidationController extends Controller
{
-
public function validateEmail(Request $request, User $user)
{
$token = $request->get('token');
@@ -26,7 +24,7 @@ public function validateEmail(Request $request, User $user)
} else {
response()->redirectTo(route('settings.subscription'))->withError(__('emails/validation.error'));
}
-
+
return response()->redirectTo(route('settings.subscription'))->withSuccess(__('emails/validation.success'));
}
}
diff --git a/app/Jobs/Emails/Subscriptions/EmailValidationJob.php b/app/Jobs/Emails/Subscriptions/EmailValidationJob.php
index 6711f35309..e9889ae710 100644
--- a/app/Jobs/Emails/Subscriptions/EmailValidationJob.php
+++ b/app/Jobs/Emails/Subscriptions/EmailValidationJob.php
@@ -3,7 +3,6 @@
namespace App\Jobs\Emails\Subscriptions;
use App\Mail\Subscription\User\ValidationEmail;
-use App\Models\UserValidation;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
diff --git a/app/Mail/Subscription/User/ValidationEmail.php b/app/Mail/Subscription/User/ValidationEmail.php
index cffa1f9677..3de9ab7f08 100644
--- a/app/Mail/Subscription/User/ValidationEmail.php
+++ b/app/Mail/Subscription/User/ValidationEmail.php
@@ -2,7 +2,6 @@
namespace App\Mail\Subscription\User;
-use App\Models\UserValidation;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
diff --git a/app/Observers/CampaignObserver.php b/app/Observers/CampaignObserver.php
index 2f15d9f5d2..95f36278be 100644
--- a/app/Observers/CampaignObserver.php
+++ b/app/Observers/CampaignObserver.php
@@ -53,7 +53,7 @@ public function saving(Campaign $campaign)
$isPublic = request()->get('is_public', null);
if (!empty($isPublic) && $previousVisibility == Campaign::VISIBILITY_PRIVATE) {
$campaign->visibility_id = Campaign::VISIBILITY_PUBLIC;
- // Default to public for now. Later will have REVIEW mode.
+ // Default to public for now. Later will have REVIEW mode.
} elseif (empty($isPublic) && $previousVisibility != Campaign::VISIBILITY_PRIVATE) {
$campaign->visibility_id = Campaign::VISIBILITY_PRIVATE;
}
diff --git a/app/Renderers/DatagridRenderer2.php b/app/Renderers/DatagridRenderer2.php
index d475ea333a..3e9ccc320c 100644
--- a/app/Renderers/DatagridRenderer2.php
+++ b/app/Renderers/DatagridRenderer2.php
@@ -158,7 +158,7 @@ public function bulks(): array
}
continue;
}
- // More specific use cases?
+ // More specific use cases?
} elseif ($bulk === Layout::ACTION_DELETE) {
if (auth()->check() && auth()->user()->isAdmin()) {
$this->bulks[] = $bulk;
diff --git a/app/User.php b/app/User.php
index 176a7a239d..20da4ec5f9 100644
--- a/app/User.php
+++ b/app/User.php
@@ -441,7 +441,7 @@ public function isFrauding(): bool
if ($validation) {
return false;
}
-
+
// If the account was created recently, add some small checks
/*if ($this->created_at->isAfter(Carbon::now()->subHour())) {
// User's name is directly in the campaign name
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 0d09e9d31a..b558a10a04 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
@@ -4,8 +4,7 @@
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
-return new class extends Migration
-{
+return new class () extends Migration {
/**
* Run the migrations.
*/
From 14ef8766b091dc11c4788b553ee1eb7e1c093a8d Mon Sep 17 00:00:00 2001
From: Spitfire
Date: Thu, 1 Feb 2024 17:10:40 -0600
Subject: [PATCH 3/9] Implemented requested changes.
---
.../User/EmailValidationController.php | 4 ++
.../Subscriptions/EmailValidationJob.php | 9 ++--
.../Subscription/User/ValidationEmail.php | 11 ++---
app/Models/Relations/UserRelations.php | 6 +++
app/Models/Scopes/UserScope.php | 7 +++
app/Services/Users/EmailValidationService.php | 43 +++++++++++++++++++
app/User.php | 34 +--------------
...2_203110_create_user_validations_table.php | 2 +-
.../validation/user-html.blade.php | 6 +--
.../settings/subscription/change.blade.php | 6 ++-
10 files changed, 77 insertions(+), 51 deletions(-)
create mode 100644 app/Services/Users/EmailValidationService.php
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 }}