diff --git a/app/Http/Controllers/AccountDeletionController.php b/app/Http/Controllers/AccountDeletionController.php new file mode 100644 index 00000000..7c407345 --- /dev/null +++ b/app/Http/Controllers/AccountDeletionController.php @@ -0,0 +1,60 @@ +hasValidSignature(); + $hasValidHash = ! empty($user->email) && hash_equals(sha1($user->email), (string) $request->query('hash')); + + if (! $hasValidSignature || ! $hasValidHash) { + return Inertia::render('Account/ConfirmDeletion', [ + 'isValid' => false, + 'user' => null, + 'confirmUrl' => '', + ]); + } + + return Inertia::render('Account/ConfirmDeletion', [ + 'isValid' => true, + 'user' => [ + 'id' => $user->id, + 'name' => $user->name, + 'email' => $user->email, + ], + 'confirmUrl' => $request->fullUrl(), + ]); + } + + /** + * Process the permanent deletion requested via signed URL. + */ + public function confirmDelete(Request $request, User $user) + { + if (! hash_equals(sha1($user->email), (string) $request->query('hash'))) { + abort(403, 'Invalid deletion token.'); + } + + // If currently authenticated as this user, log them out and invalidate session + if (Auth::id() === $user->id) { + Auth::logout(); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + } + + $user->delete(); + + return redirect('/') + ->with('success', 'আপনার অ্যাকাউন্টটি সফলভাবে মুছে ফেলা হয়েছে।'); + } +} diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 7b2f420d..cade5e36 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -6,12 +6,14 @@ use App\Http\Requests\User\StoreUserRequest; use App\Http\Requests\User\UpdateUserRequest; use App\Mail\AccountDeletedMail; +use App\Mail\AccountDeletionLinkMail; use App\Models\User; use App\Notifications\WelcomeNotification; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Facades\URL; use Inertia\Inertia; use Spatie\Permission\Models\Permission; @@ -170,6 +172,29 @@ public function destroy(User $user) ->with('success', 'User deleted successfully.'); } + /** + * Send a temporary signed account deletion link to the user. + */ + public function sendDeleteLink(User $user) + { + if (empty($user->email)) { + return back()->with('error', 'This user does not have an email address.'); + } + + $signedUrl = URL::temporarySignedRoute( + 'account.delete.verify', + now()->addDays(7), + [ + 'user' => $user->id, + 'hash' => sha1($user->email), + ] + ); + + Mail::to($user->email)->queue(new AccountDeletionLinkMail($user, $signedUrl)); + + return back()->with('success', "Deletion link sent successfully to {$user->email}."); + } + /** * Log in as the specified user. */ diff --git a/app/Mail/AccountDeletionLinkMail.php b/app/Mail/AccountDeletionLinkMail.php new file mode 100644 index 00000000..18e41075 --- /dev/null +++ b/app/Mail/AccountDeletionLinkMail.php @@ -0,0 +1,49 @@ +user->name ? "Hello {$this->user->name}," : 'প্রিয় শিক্ষার্থী,'; + + return new Content( + view: 'emails.default', + with: [ + 'subject' => 'আপনার অ্যাকাউন্ট মুছে ফেলার কনফার্মেশন লিংক', + 'greeting' => $name, + 'lines' => [ + 'আমরা আপনার অ্যাকাউন্ট মুছে ফেলার অনুরোধটি পেয়েছি।', + 'আপনি যদি আপনার HSCStack অ্যাকাউন্টটি ডিলিট করতে চান, তাহলে নিচের বাটনে ক্লিক করে কনফার্মেশন সম্পন্ন করুন।', + 'সতর্কতা: এই লিংকের মেয়াদ আগামী ৭ দিন পর্যন্ত কার্যকর থাকবে। অ্যাকাউন্ট মুছে ফেলার পর আপনার সব ডাটা স্থায়ীভাবে ডিলিট হয়ে যাবে এবং তা আর পুনরুদ্ধার করা সম্ভব হবে না।', + 'আপনি যদি অ্যাকাউন্ট ডিলিট করতে না চান, তবে এই ইমেইলটি উপেক্ষা করুন। আপনার অ্যাকাউন্ট সুরক্ষিত থাকবে।', + ], + 'actionText' => 'অ্যাকাউন্ট ডিলিট করুন (Confirm Deletion)', + 'actionUrl' => $this->signedUrl, + ], + ); + } +} diff --git a/resources/js/components/admin/UserRow.vue b/resources/js/components/admin/UserRow.vue index af7221c0..37f7c3e3 100644 --- a/resources/js/components/admin/UserRow.vue +++ b/resources/js/components/admin/UserRow.vue @@ -1,7 +1,8 @@ @@ -178,7 +212,7 @@ const deleteUser = (id: number) => { diff --git a/resources/js/pages/Account/ConfirmDeletion.vue b/resources/js/pages/Account/ConfirmDeletion.vue new file mode 100644 index 00000000..e438f382 --- /dev/null +++ b/resources/js/pages/Account/ConfirmDeletion.vue @@ -0,0 +1,204 @@ + + + + + +
+ অ্যাকাউন্ট মুছে ফেলার এই কনফার্মেশন লিংকটির মেয়াদ শেষ হয়ে + গেছে অথবা লিংকটি পরিবর্তিত হয়েছে। নতুন লিংকের জন্য পুনরায় + আবেদন জমা দিন বা আমাদের সাপোর্টে যোগাযোগ করুন। +
+ ++ এই প্রক্রিয়াটি সম্পন্ন হলে আপনার অ্যাকাউন্ট এবং ডাটা + চিরতরে মুছে যাবে +
++ চিহ্নিত অ্যাকাউন্ট: +
++ {{ user.name }} +
++ {{ user.email }} +
++ গুরুত্বপূর্ণ সতর্কতা: +
+- আপনার ইতিমধ্যে ৩টি খোলা সাপোর্ট টিকেট রয়েছে। -
-- নতুন টিকেট খোলার আগে অনুগ্রহ করে পূর্ববর্তী টিকেটের - সমাধান হওয়া পর্যন্ত অপেক্ষা করুন। +
সাপোর্ট টিকিট সীমা পূর্ণ হয়েছে
++ আপনার ইতিমধ্যে ৩টি সক্রিয় সাপোর্ট টিকিট উন্মুক্ত + রয়েছে। নতুন রিকোয়েস্ট পাঠাতে পূর্বের টিকিট নিষ্পত্তি + হওয়া পর্যন্ত অপেক্ষা করুন।
-- অ্যাকাউন্ট ও সংশ্লিষ্ট সকল ডেটা স্থায়ীভাবে মুছে ফেলার - জন্য সরাসরি সাপোর্ট টিকেট তৈরি হবে। +
+ অ্যাকাউন্ট ও সংশ্লিষ্ট সকল ডেটা স্থায়ীভাবে মুছে ফেলার + জন্য আবেদন জমা নেওয়া হবে।
{ @{{ authUser?.username }} • {{ authUser.email }} @@ -223,174 +365,296 @@ const submitDeleteTicket = () => {