From 0139cc92bf6fb939223940a93fa86b08b08e4b8d Mon Sep 17 00:00:00 2001 From: Milos Holba Date: Thu, 20 May 2021 21:18:28 +0200 Subject: [PATCH] added user verification option in admin settings --- app/Actions/Fortify/CreateNewUser.php | 4 +++ app/Console/Commands/SetupDevEnvironment.php | 3 ++ app/Http/Controllers/Auth/AuthController.php | 1 + .../Controllers/User/AccountController.php | 14 +++++--- config/language-translations.php | 5 +++ public/mix-manifest.json | 35 +++++++++++++++++-- .../AppSettings/AppSettingsTabs/Others.vue | 23 ++++++++++-- resources/js/views/Auth/SignIn.vue | 27 ++++++++++++++ resources/views/index.blade.php | 1 + routes/user.php | 4 +-- tests/Feature/Accounts/UserAccountTest.php | 14 ++++++-- 11 files changed, 117 insertions(+), 14 deletions(-) diff --git a/app/Actions/Fortify/CreateNewUser.php b/app/Actions/Fortify/CreateNewUser.php index b9cb8e2b..c6b11538 100644 --- a/app/Actions/Fortify/CreateNewUser.php +++ b/app/Actions/Fortify/CreateNewUser.php @@ -54,6 +54,10 @@ class CreateNewUser implements CreatesNewUsers 'storage_capacity' => $settings['storage_default'], ]); + if(!get_setting('user_verification')) { + $user->markEmailAsVerified(); + } + UserSettings::reguard(); return $user; diff --git a/app/Console/Commands/SetupDevEnvironment.php b/app/Console/Commands/SetupDevEnvironment.php index d1e95516..222de869 100644 --- a/app/Console/Commands/SetupDevEnvironment.php +++ b/app/Console/Commands/SetupDevEnvironment.php @@ -9,6 +9,7 @@ use App\Models\Folder; use App\Models\Setting; use Illuminate\Support\Str; use App\Services\SetupService; +use Illuminate\Support\Carbon; use Illuminate\Console\Command; use Illuminate\Support\Facades\Storage; @@ -87,6 +88,7 @@ class SetupDevEnvironment extends Command 'role' => 'admin', 'email' => 'howdy@hi5ve.digital', 'password' => bcrypt('vuefilemanager'), + 'email_verified_at' => Carbon::now(), ]); $user @@ -127,6 +129,7 @@ class SetupDevEnvironment extends Command 'role' => 'user', 'email' => $this->faker->email, 'password' => bcrypt('vuefilemanager'), + 'email_verified_at' => Carbon::now(), ]); $newbie diff --git a/app/Http/Controllers/Auth/AuthController.php b/app/Http/Controllers/Auth/AuthController.php index 1e0bd482..4cd6cba6 100644 --- a/app/Http/Controllers/Auth/AuthController.php +++ b/app/Http/Controllers/Auth/AuthController.php @@ -26,6 +26,7 @@ class AuthController extends Controller return [ 'name' => $user->settings->name, 'avatar' => $user->settings->avatar, + 'verified' => $user->email_verified_at ? true : false ]; } } diff --git a/app/Http/Controllers/User/AccountController.php b/app/Http/Controllers/User/AccountController.php index 3b280bee..7dd0d6aa 100644 --- a/app/Http/Controllers/User/AccountController.php +++ b/app/Http/Controllers/User/AccountController.php @@ -178,8 +178,10 @@ class AccountController extends Controller * @param User $user * @return ResponseFactory|\Illuminate\Http\Response */ - public function email_verify(User $user, Request $request) + public function email_verify($id, Request $request) { + $user = User::find($id); + if (!$request->hasValidSignature()) { return response("Invalid/Expired url provided.", 401); } @@ -188,7 +190,7 @@ class AccountController extends Controller $user->markEmailAsVerified(); } - return redirect()->to('/'); + return redirect()->to('/sign-in'); } /** @@ -196,13 +198,15 @@ class AccountController extends Controller * * @return ResponseFactory|\Illuminate\Http\Response */ - public function resend_verify_email() + public function resend_verify_email(Request $request) { - if (Auth::user()->hasVerifiedEmail()) { + $user = User::whereEmail($request->input('email'))->first(); + + if ($user->hasVerifiedEmail()) { return response("Email already verified.", 204); } - Auth::user()->sendEmailVerificationNotification(); + $user->sendEmailVerificationNotification(); return response("Email verification link sent on your email", 200); } diff --git a/config/language-translations.php b/config/language-translations.php index 5ec38c28..3d33ba2c 100644 --- a/config/language-translations.php +++ b/config/language-translations.php @@ -291,6 +291,8 @@ return [ 'admin_settings.email.username_plac' => 'Type your mail username', 'admin_settings.others.allow_registration' => 'Allow User Registration', 'admin_settings.others.allow_registration_help' => 'You can disable public registration for new users. You will still able to
create new users in administration panel.', + 'admin_settings.others.allow_user_verification' => 'Allow User Email Verification', + 'admin_settings.others.allow_user_verification_help' => 'Turn on, if you want to allow user email verification.', 'admin_settings.others.cache_clear' => 'Clear Cache', 'admin_settings.others.cache_disclaimer' => 'Did you change anything in your .env file or change your Stripe credentials? Then clear your cache.', 'admin_settings.others.contact_email' => 'Contact Email', @@ -472,6 +474,9 @@ return [ 'page_sign_in.placeholder_password' => 'Type your password', 'page_sign_in.subtitle' => 'Confirm you by your password', 'page_sign_in.title' => 'Are You {name}?', + 'page_not_verified.subtitle' => 'Your account is not verified. Before login, verify your account please.', + 'page_not_verified.resend_text' => 'Do you want resend verification email?', + 'page_not_verified.resend_button' => 'Resend verification email.', 'popup_create_folder.folder_default_name' => 'New Folder', 'popup_create_folder.label' => 'Type Name', 'popup_create_folder.placeholder' => 'Type your name', diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 69009780..02473636 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -20,7 +20,7 @@ "/chunks/app-language.js": "/chunks/app-language.js?id=14b28923d876241b4324", "/chunks/app-language~chunks/app-settings~chunks/dashboard~chunks/invoices~chunks/page-edit~chunks/pag~824d674f.js": "/chunks/app-language~chunks/app-settings~chunks/dashboard~chunks/invoices~chunks/page-edit~chunks/pag~824d674f.js?id=53e545b823ce2e687b31", "/chunks/app-language~chunks/dashboard~chunks/files~chunks/invoices~chunks/pages~chunks/plans~chunks/s~38c276fc.js": "/chunks/app-language~chunks/dashboard~chunks/files~chunks/invoices~chunks/pages~chunks/plans~chunks/s~38c276fc.js?id=f90c5804695eeea92af0", - "/chunks/app-others.js": "/chunks/app-others.js?id=314e16368587d44da0fe", + "/chunks/app-others.js": "/chunks/app-others.js?id=1af00eb21fae95d927c0", "/chunks/app-payments.js": "/chunks/app-payments.js?id=a8167d5a9383b34ac322", "/chunks/app-settings.js": "/chunks/app-settings.js?id=7036abc45d63af4fe972", "/chunks/app-setup.js": "/chunks/app-setup.js?id=99d86e5e53e0961538d4", @@ -72,7 +72,7 @@ "/chunks/shared/authenticate.js": "/chunks/shared/authenticate.js?id=238c362399a4018549bd", "/chunks/shared/file-browser.js": "/chunks/shared/file-browser.js?id=d630c473dc6b751ec50f", "/chunks/shared/single-file.js": "/chunks/shared/single-file.js?id=040a7241ea133456200c", - "/chunks/sign-in.js": "/chunks/sign-in.js?id=a694e3863cefe7da1daa", + "/chunks/sign-in.js": "/chunks/sign-in.js?id=649d051ab2fa0118f313", "/chunks/sign-up.js": "/chunks/sign-up.js?id=f5634301e476029d6fa1", "/chunks/stripe-credentials.js": "/chunks/stripe-credentials.js?id=7a9a78fcdfebbeff5c3d", "/chunks/subscription-plans.js": "/chunks/subscription-plans.js?id=314fdc603b7dd04d2b9d", @@ -92,5 +92,34 @@ "/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~2fac28cc.js": "/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~2fac28cc.js?id=57c854adb91ed9a9d088", "/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~d5e36d91.js": "/vendors~chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~d5e36d91.js?id=170765b4fd923b62195c", "/vendors~chunks/files~chunks/platform~chunks/shared~chunks/shared-files~chunks/shared/file-browser~ch~52c14f2e.js": "/vendors~chunks/files~chunks/platform~chunks/shared~chunks/shared-files~chunks/shared/file-browser~ch~52c14f2e.js?id=66afa0e341251a68c3d3", - "/vendors~chunks/platform~chunks/shared.js": "/vendors~chunks/platform~chunks/shared.js?id=eb141834bc24b72d8e92" + "/vendors~chunks/platform~chunks/shared.js": "/vendors~chunks/platform~chunks/shared.js?id=eb141834bc24b72d8e92", + "/chunks/app-others.4a1880c5e5279e443415.hot-update.js": "/chunks/app-others.4a1880c5e5279e443415.hot-update.js", + "/chunks/app-others.65fc70ed6cd855b5f739.hot-update.js": "/chunks/app-others.65fc70ed6cd855b5f739.hot-update.js", + "/chunks/app-others.ec7781305c199afd7ac1.hot-update.js": "/chunks/app-others.ec7781305c199afd7ac1.hot-update.js", + "/chunks/app-others.8b1366ac8c6c3d51a360.hot-update.js": "/chunks/app-others.8b1366ac8c6c3d51a360.hot-update.js", + "/chunks/app-others.ee1c494b6e7c65ef457d.hot-update.js": "/chunks/app-others.ee1c494b6e7c65ef457d.hot-update.js", + "/chunks/app-others.bdcb16d88a2f534975b1.hot-update.js": "/chunks/app-others.bdcb16d88a2f534975b1.hot-update.js", + "/chunks/app-others.d7ea54db66f0d57ed713.hot-update.js": "/chunks/app-others.d7ea54db66f0d57ed713.hot-update.js", + "/chunks/app-others.f5d5675c971c27d1f7e9.hot-update.js": "/chunks/app-others.f5d5675c971c27d1f7e9.hot-update.js", + "/chunks/sign-in.184793cba19c4befae4f.hot-update.js": "/chunks/sign-in.184793cba19c4befae4f.hot-update.js", + "/chunks/sign-in.a9ecea30dd01a6e837ed.hot-update.js": "/chunks/sign-in.a9ecea30dd01a6e837ed.hot-update.js", + "/chunks/sign-in.cdc378238cd3ebffb0f4.hot-update.js": "/chunks/sign-in.cdc378238cd3ebffb0f4.hot-update.js", + "/chunks/sign-in.50ca919fad3f9a6b0c7a.hot-update.js": "/chunks/sign-in.50ca919fad3f9a6b0c7a.hot-update.js", + "/chunks/sign-in.2f00413d818bda25eb35.hot-update.js": "/chunks/sign-in.2f00413d818bda25eb35.hot-update.js", + "/chunks/sign-in.2a7a8d0a41dd6c30c0ed.hot-update.js": "/chunks/sign-in.2a7a8d0a41dd6c30c0ed.hot-update.js", + "/chunks/sign-in.8ea3e1a7d9dd1a70b024.hot-update.js": "/chunks/sign-in.8ea3e1a7d9dd1a70b024.hot-update.js", + "/chunks/sign-in.dc398a4251e46ac97944.hot-update.js": "/chunks/sign-in.dc398a4251e46ac97944.hot-update.js", + "/chunks/sign-in.3adea8208d6fc3821797.hot-update.js": "/chunks/sign-in.3adea8208d6fc3821797.hot-update.js", + "/chunks/sign-in.9efe4a4c966f1960aba3.hot-update.js": "/chunks/sign-in.9efe4a4c966f1960aba3.hot-update.js", + "/chunks/sign-in.6d963727e5c35fb26e6e.hot-update.js": "/chunks/sign-in.6d963727e5c35fb26e6e.hot-update.js", + "/chunks/sign-in.8d5c9b43872d4f560074.hot-update.js": "/chunks/sign-in.8d5c9b43872d4f560074.hot-update.js", + "/chunks/sign-in.de26ebb8f5305618ba79.hot-update.js": "/chunks/sign-in.de26ebb8f5305618ba79.hot-update.js", + "/chunks/sign-in.7406fea0a099e3a8665a.hot-update.js": "/chunks/sign-in.7406fea0a099e3a8665a.hot-update.js", + "/chunks/sign-in.8da4f2ef76780a6c56c0.hot-update.js": "/chunks/sign-in.8da4f2ef76780a6c56c0.hot-update.js", + "/chunks/sign-in.bf19d64759c9e9b5239f.hot-update.js": "/chunks/sign-in.bf19d64759c9e9b5239f.hot-update.js", + "/chunks/sign-in.28b0b83732ce321c4e39.hot-update.js": "/chunks/sign-in.28b0b83732ce321c4e39.hot-update.js", + "/chunks/sign-up.1a6fc69e814f5c2081cf.hot-update.js": "/chunks/sign-up.1a6fc69e814f5c2081cf.hot-update.js", + "/chunks/sign-up.2eeea0f4a373d3154966.hot-update.js": "/chunks/sign-up.2eeea0f4a373d3154966.hot-update.js", + "/chunks/sign-up.824b863643bbc69324a0.hot-update.js": "/chunks/sign-up.824b863643bbc69324a0.hot-update.js", + "/chunks/sign-up.1ca02954735d934e513e.hot-update.js": "/chunks/sign-up.1ca02954735d934e513e.hot-update.js" } diff --git a/resources/js/views/Admin/AppSettings/AppSettingsTabs/Others.vue b/resources/js/views/Admin/AppSettings/AppSettingsTabs/Others.vue index e124eb2c..40c7e6aa 100644 --- a/resources/js/views/Admin/AppSettings/AppSettingsTabs/Others.vue +++ b/resources/js/views/Admin/AppSettings/AppSettingsTabs/Others.vue @@ -58,6 +58,24 @@ +
+
+
+
+ + +
+ +
+
+
+ {{ $t('admin_settings.others.section_others') }} @@ -173,7 +191,7 @@ mounted() { axios.get('/api/admin/settings', { params: { - column: 'contact_email|google_analytics|storage_default|registration|storage_limitation|mimetypes_blacklist|upload_limit' + column: 'contact_email|google_analytics|storage_default|registration|storage_limitation|mimetypes_blacklist|upload_limit|user_verification' } }) .then(response => { @@ -186,7 +204,8 @@ userRegistration: parseInt(response.data.registration), storageLimitation: parseInt(response.data.storage_limitation), mimetypesBlacklist : response.data.mimetypes_blacklist, - uploadLimit: response.data.upload_limit + uploadLimit: response.data.upload_limit, + userVerification: response.data.user_verification } }) } diff --git a/resources/js/views/Auth/SignIn.vue b/resources/js/views/Auth/SignIn.vue index 16c6957f..9f5becde 100644 --- a/resources/js/views/Auth/SignIn.vue +++ b/resources/js/views/Auth/SignIn.vue @@ -61,6 +61,19 @@ + + + +
+ +

{{ checkedAccount.name }}

+

{{ $t('page_not_verified.subtitle') }}

+
+ + {{ $t('page_not_verified.resend_text') }} + {{ $t('page_not_verified.resend_button') }} + +
@@ -110,6 +123,13 @@ } }) }, + resendEmail() { + axios. + post('/api/user/email/resend/verify', { + email: this.loginEmail + }) + .then(console.log('send')) + }, async logIn() { // Validate fields @@ -164,6 +184,13 @@ if (!isValid) return; + if(!this.checkedAccount.verified) { + + this.goToAuthPage('not-verified') + + return + } + // Start loading this.isLoading = true diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php index b4a26d9e..0b631db6 100644 --- a/resources/views/index.blade.php +++ b/resources/views/index.blade.php @@ -55,6 +55,7 @@ allowHomepage: {{ $settings->allow_homepage ?? 1 }}, userRegistration: {{ $settings->registration ?? 1 }}, + userVerification: {{ $settings->user_verification ?? 0 }}, storageLimit: {{ $settings->storage_limitation ?? 1 }}, storageDefaultSpace: {{ $settings->storage_default ?? 5 }}, storageDefaultSpaceFormatted: '{{ isset($settings->storage_default) ? format_gigabytes($settings->storage_default) : format_gigabytes(5) }}', diff --git a/routes/user.php b/routes/user.php index 7a1feb84..4eb8466b 100644 --- a/routes/user.php +++ b/routes/user.php @@ -8,12 +8,12 @@ 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::get('/email/verify/{id}', [AccountController::class, 'email_verify'])->name('verification.verify'); +Route::post('/email/resend/verify', [AccountController::class, 'resend_verify_email'])->name('verification.send'); Route::group(['middleware' => ['auth:sanctum']], function () { // Account Route::patch('/relationships/settings', [AccountController::class, 'update_user_settings']); - 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']); diff --git a/tests/Feature/Accounts/UserAccountTest.php b/tests/Feature/Accounts/UserAccountTest.php index c2305ed5..b95cc6c3 100644 --- a/tests/Feature/Accounts/UserAccountTest.php +++ b/tests/Feature/Accounts/UserAccountTest.php @@ -14,6 +14,7 @@ use Storage; use Notification; use Tests\TestCase; use App\Models\Folder; +use Illuminate\Support\Facades\URL; class UserAccountTest extends TestCase { @@ -265,10 +266,19 @@ class UserAccountTest extends TestCase */ public function it_user_email_verify() { + // TODO:make request with signature $user = User::factory(User::class) - ->create(); + ->create([ + 'email_verified_at' => null + ]); - $this->getJson("/api/user/email/verify/$user->id"); + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1($user->email)] + ); + + $this->getJson($verificationUrl); $this->assertNotNull($user->email_verified_at); }