From 346a59cfa1a754f3fb0fde88827eedcf445c8607 Mon Sep 17 00:00:00 2001 From: TR Tajim Date: Fri, 9 Oct 2026 16:21:14 +0600 Subject: [PATCH 1/3] feat(mail): add AccountDeletedMail mailable and email template --- app/Mail/AccountDeletedMail.php | 39 ++++ .../views/emails/account_deleted.blade.php | 209 ++++++++++++++++++ routes/web.php | 1 + 3 files changed, 249 insertions(+) create mode 100644 app/Mail/AccountDeletedMail.php create mode 100644 resources/views/emails/account_deleted.blade.php diff --git a/app/Mail/AccountDeletedMail.php b/app/Mail/AccountDeletedMail.php new file mode 100644 index 00000000..fbb45203 --- /dev/null +++ b/app/Mail/AccountDeletedMail.php @@ -0,0 +1,39 @@ + $this->recipientName, + 'privacyPolicyUrl' => url('/privacy-policy'), + 'termsConditionsUrl' => url('/terms-conditions'), + 'appUrl' => config('app.url', url('/')), + ], + ); + } +} diff --git a/resources/views/emails/account_deleted.blade.php b/resources/views/emails/account_deleted.blade.php new file mode 100644 index 00000000..ab48dab1 --- /dev/null +++ b/resources/views/emails/account_deleted.blade.php @@ -0,0 +1,209 @@ + + + + + + আপনার অ্যাকাউন্ট ডিলিট করা হয়েছে + + + +
+
+ + + + +
+
আপনার অ্যাকাউন্ট ডিলিট করা হয়েছে
+ +

+ আমরা আপনার অ্যাকাউন্ট ডিলিট করার অনুরোধটি পেয়েছি। আপনার অ্যাকাউন্ট এবং এর সাথে সম্পর্কিত যাবতীয় তথ্য আমাদের + Privacy Policy ও + Terms & Conditions + অনুযায়ী স্থায়ীভাবে মুছে ফেলা হয়েছে। +

+ +

+ HSCStack-এর সাথে থাকার জন্য আপনাকে ধন্যবাদ। ❤️ +

+ +

+ ভবিষ্যতে যদি আবার HSCStack ব্যবহার করতে চান, তাহলে যেকোনো সময় নতুন করে একটি অ্যাকাউন্ট তৈরি করে আমাদের প্ল্যাটফর্মে ফিরে আসতে পারেন। +

+ +
+
HSCStack-এর উল্লেখযোগ্য ফিচারসমূহ:
+
+ Resource Archive — HSC ও SSC-এর Science, Arts এবং Commerce বিভাগের ক্লাস, নোট ও বিভিন্ন শিক্ষামূলক রিসোর্স। +
+
+ Forum — যেকোনো প্রশ্ন করতে পারবেন এবং সহপাঠীদের কাছ থেকে উত্তর ও সহযোগিতা পেতে পারবেন। +
+
+ Global Chat — সারাদেশের শিক্ষার্থীদের সাথে যোগাযোগ ও মতবিনিময়ের সুযোগ। +
+
+ Study Tracker — আপনার পড়াশোনা ও সিলেবাসের অগ্রগতি সহজেই ট্র্যাক করুন। +
+
+ Community Interaction — অন্যান্য শিক্ষার্থীদের সাথে যুক্ত হয়ে আলোচনা, সহযোগিতা ও জ্ঞান বিনিময় করুন। +
+
+ +

আবারও ধন্যবাদ HSCStack-এর সাথে থাকার জন্য।

+

ভবিষ্যতে আবার দেখা হবে! 💙

+
+ + + +
+
+ + diff --git a/routes/web.php b/routes/web.php index 1899a893..857d2e9e 100644 --- a/routes/web.php +++ b/routes/web.php @@ -93,6 +93,7 @@ Route::middleware('throttle:60,1')->group(function () { Route::inertia('/privacy-policy', 'legal/PrivacyPolicy'); Route::inertia('/terms-service', 'legal/TermsConditions'); + Route::permanentRedirect('/terms-conditions', '/terms-service'); Route::inertia('/content-policy', 'legal/ContentPolicy'); Route::inertia('/donate', 'Donate')->name('donate'); Route::get('/support', [SupportTicketController::class, 'index'])->name('support.index'); From 7b8661d69ee2bfeccc2ea45bd7a1545e5362f30b Mon Sep 17 00:00:00 2001 From: TR Tajim Date: Fri, 9 Oct 2026 16:21:19 +0600 Subject: [PATCH 2/3] feat(admin): send AccountDeletedMail on user deletion with tests --- app/Http/Controllers/Admin/UserController.php | 6 ++ tests/Feature/AccountDeletionMailTest.php | 62 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/Feature/AccountDeletionMailTest.php diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index c32679c1..d41d0804 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -5,10 +5,12 @@ use App\Http\Controllers\Controller; use App\Http\Requests\User\StoreUserRequest; use App\Http\Requests\User\UpdateUserRequest; +use App\Mail\AccountDeletedMail; 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 Inertia\Inertia; use Spatie\Permission\Models\Permission; @@ -157,6 +159,10 @@ public function update(UpdateUserRequest $request, User $user) public function destroy(User $user) { + if (! empty($user->email)) { + Mail::to($user->email)->queue(new AccountDeletedMail($user->name)); + } + $user->delete(); return redirect() diff --git a/tests/Feature/AccountDeletionMailTest.php b/tests/Feature/AccountDeletionMailTest.php new file mode 100644 index 00000000..7797aa80 --- /dev/null +++ b/tests/Feature/AccountDeletionMailTest.php @@ -0,0 +1,62 @@ +seed(RolePermissionSeeder::class); +}); + +test('account deleted mailable renders expected subject, content and legal links', function () { + $mailable = new AccountDeletedMail('Rahim Ahmed'); + + $mailable->assertHasSubject('আপনার অ্যাকাউন্ট ডিলিট করা হয়েছে'); + + $html = $mailable->render(); + + expect($html) + ->toContain('আপনার অ্যাকাউন্ট ডিলিট করা হয়েছে') + ->toContain('আমরা আপনার অ্যাকাউন্ট ডিলিট করার অনুরোধটি পেয়েছি') + ->toContain('Privacy Policy') + ->toContain('Terms & Conditions') + ->toContain('/privacy-policy') + ->toContain('/terms-conditions') + ->toContain('Resource Archive') + ->toContain('Forum') + ->toContain('Global Chat') + ->toContain('Study Tracker') + ->toContain('Community Interaction') + ->toContain('ভবিষ্যতে আবার দেখা হবে! 💙'); +}); + +test('admin deleting a user queues account deleted mail and deletes user', function () { + Mail::fake(); + + $admin = User::factory()->create(); + $admin->assignRole('admin'); + + $userToDelete = User::factory()->create([ + 'name' => 'Karim Hasan', + 'email' => 'karim@example.com', + ]); + + $this->actingAs($admin) + ->delete("/admin/users/{$userToDelete->id}") + ->assertRedirect(route('admin.users.index')) + ->assertSessionHas('success'); + + expect(User::find($userToDelete->id))->toBeNull(); + + Mail::assertQueued(AccountDeletedMail::class, function (AccountDeletedMail $mail) use ($userToDelete) { + return $mail->hasTo($userToDelete->email) + && $mail->recipientName === 'Karim Hasan'; + }); +}); + +test('terms-conditions route redirects permanently to terms-service', function () { + $this->get('/terms-conditions') + ->assertRedirect('/terms-service') + ->assertStatus(301); +}); From 22938ea0b63cf6e0354fd82159c2395b4815aaeb Mon Sep 17 00:00:00 2001 From: TR Tajim Date: Fri, 9 Oct 2026 16:24:44 +0600 Subject: [PATCH 3/3] refactor(mail): link directly to /terms-service and revert web.php redirect --- app/Mail/AccountDeletedMail.php | 2 +- routes/web.php | 1 - tests/Feature/AccountDeletionMailTest.php | 8 +------- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/app/Mail/AccountDeletedMail.php b/app/Mail/AccountDeletedMail.php index fbb45203..9f404de1 100644 --- a/app/Mail/AccountDeletedMail.php +++ b/app/Mail/AccountDeletedMail.php @@ -31,7 +31,7 @@ public function content(): Content with: [ 'recipientName' => $this->recipientName, 'privacyPolicyUrl' => url('/privacy-policy'), - 'termsConditionsUrl' => url('/terms-conditions'), + 'termsConditionsUrl' => url('/terms-service'), 'appUrl' => config('app.url', url('/')), ], ); diff --git a/routes/web.php b/routes/web.php index 857d2e9e..1899a893 100644 --- a/routes/web.php +++ b/routes/web.php @@ -93,7 +93,6 @@ Route::middleware('throttle:60,1')->group(function () { Route::inertia('/privacy-policy', 'legal/PrivacyPolicy'); Route::inertia('/terms-service', 'legal/TermsConditions'); - Route::permanentRedirect('/terms-conditions', '/terms-service'); Route::inertia('/content-policy', 'legal/ContentPolicy'); Route::inertia('/donate', 'Donate')->name('donate'); Route::get('/support', [SupportTicketController::class, 'index'])->name('support.index'); diff --git a/tests/Feature/AccountDeletionMailTest.php b/tests/Feature/AccountDeletionMailTest.php index 7797aa80..cb004ea4 100644 --- a/tests/Feature/AccountDeletionMailTest.php +++ b/tests/Feature/AccountDeletionMailTest.php @@ -22,7 +22,7 @@ ->toContain('Privacy Policy') ->toContain('Terms & Conditions') ->toContain('/privacy-policy') - ->toContain('/terms-conditions') + ->toContain('/terms-service') ->toContain('Resource Archive') ->toContain('Forum') ->toContain('Global Chat') @@ -54,9 +54,3 @@ && $mail->recipientName === 'Karim Hasan'; }); }); - -test('terms-conditions route redirects permanently to terms-service', function () { - $this->get('/terms-conditions') - ->assertRedirect('/terms-service') - ->assertStatus(301); -});