diff --git a/app/Http/Controllers/User/AccountController.php b/app/Http/Controllers/User/AccountController.php index 694f5310..3b280bee 100644 --- a/app/Http/Controllers/User/AccountController.php +++ b/app/Http/Controllers/User/AccountController.php @@ -1,6 +1,7 @@ tokens()->whereId($id)->delete(); + if(Auth::user()->id !== $token->tokenable_id) { + return response('Unauthorized', 401); + } + + $token->delete(); return response('Deleted!', 204); } + + /** + * Email verification + * + * @param Request $request + * @param User $user + * @return ResponseFactory|\Illuminate\Http\Response + */ + public function email_verify(User $user, Request $request) + { + if (!$request->hasValidSignature()) { + return response("Invalid/Expired url provided.", 401); + } + + if (!$user->hasVerifiedEmail()) { + $user->markEmailAsVerified(); + } + + return redirect()->to('/'); + } + + /** + * Resend verification email + * + * @return ResponseFactory|\Illuminate\Http\Response + */ + public function resend_verify_email() + { + if (Auth::user()->hasVerifiedEmail()) { + return response("Email already verified.", 204); + } + + Auth::user()->sendEmailVerificationNotification(); + + return response("Email verification link sent on your email", 200); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 0c72af5e..013c049e 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -13,8 +13,9 @@ use Illuminate\Support\Facades\Storage; use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; +use Illuminate\Contracts\Auth\MustVerifyEmail; -class User extends Authenticatable +class User extends Authenticatable implements MustVerifyEmail { use Notifiable, Billable, Sortable, HasFactory, HasApiTokens; diff --git a/routes/user.php b/routes/user.php index 8c38f383..7a1feb84 100644 --- a/routes/user.php +++ b/routes/user.php @@ -7,10 +7,14 @@ use App\Http\Controllers\User\PaymentMethodsController; Route::post('/check', [AuthController::class, 'check_account']); +// Email verification +Route::get('email/verify/{user}', [AccountController::class, 'email_verify'])->name('verification.verify'); + Route::group(['middleware' => ['auth:sanctum']], function () { // Account Route::patch('/relationships/settings', [AccountController::class, 'update_user_settings']); - Route::delete('/token/revoke/{id}', [AccountController::class, 'revoke_token']); + Route::post('/email/resend/verify', [AccountController::class, 'resend_verify_email']); + Route::delete('/token/revoke/{token}', [AccountController::class, 'revoke_token']); Route::post('/token/create', [AccountController::class, 'create_token']); Route::post('/password', [AccountController::class, 'change_password']); Route::get('/subscription', [SubscriptionController::class, 'show']); diff --git a/tests/Feature/Accounts/AuthTest.php b/tests/Feature/Accounts/AuthTest.php index 0e2876b7..6b2ccb30 100644 --- a/tests/Feature/Accounts/AuthTest.php +++ b/tests/Feature/Accounts/AuthTest.php @@ -5,6 +5,7 @@ namespace Tests\Feature\Accounts; use App\Models\Setting; use App\Models\User; use App\Notifications\ResetPassword; +use Illuminate\Auth\Notifications\VerifyEmail; use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Support\Facades\Password; use Laravel\Sanctum\Sanctum; @@ -42,6 +43,8 @@ class AuthTest extends TestCase */ public function it_register_user() { + Notification::fake(); + collect([ [ 'name' => 'storage_default', @@ -76,6 +79,8 @@ class AuthTest extends TestCase Storage::disk('local') ->assertExists('files/' . User::first()->id); + + Notification::assertTimesSent(1, VerifyEmail::class); } /** diff --git a/tests/Feature/Accounts/UserAccountTest.php b/tests/Feature/Accounts/UserAccountTest.php index b14f15c5..c2305ed5 100644 --- a/tests/Feature/Accounts/UserAccountTest.php +++ b/tests/Feature/Accounts/UserAccountTest.php @@ -6,10 +6,12 @@ use App\Models\User; use App\Services\SetupService; use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Auth\Notifications\VerifyEmail; use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Laravel\Sanctum\Sanctum; use Storage; +use Notification; use Tests\TestCase; use App\Models\Folder; @@ -191,7 +193,6 @@ class UserAccountTest extends TestCase $this->assertDatabaseMissing('personal_access_tokens', [ 'id' => $token_id ]); - } /** @@ -225,7 +226,7 @@ class UserAccountTest extends TestCase public function it_use_user_token_to_request() { $user = User::factory(User::class) - ->create(); + ->create(); $folder = Folder::factory(Folder::class) ->create([ @@ -256,7 +257,39 @@ class UserAccountTest extends TestCase // 'user_id' => $user->id, // ]); - dd($response); + // dd($response); + } + /** + * @test + */ + public function it_user_email_verify() + { + $user = User::factory(User::class) + ->create(); + + $this->getJson("/api/user/email/verify/$user->id"); + + $this->assertNotNull($user->email_verified_at); + } + + /** + * @test + */ + public function it_resend_user_verify_email() + { + Notification::fake(); + + $user = User::factory(User::class) + ->create([ + 'email_verified_at' => null + ]); + + Sanctum::actingAs($user); + + $this->postJson('/api/user/email/resend/verify') + ->assertStatus(200); + + Notification::assertTimesSent(1, VerifyEmail::class); } }