#!/bin/bash # Get the directory where the script is located SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # Change to the project root directory (one level up from scripts/) cd "$SCRIPT_DIR/.." || exit 1 echo "===============================================" echo "Testing Transactional Emails" echo "===============================================" echo "" # Language selection echo "Select language(s) for test emails:" echo " 1) English (en)" echo " 2) Dutch (nl)" echo " 3) German (de)" echo " 4) Spanish (es)" echo " 5) French (fr)" echo " 6) All languages" echo "" read -p "Enter your choice (1-6): " LANG_CHOICE case $LANG_CHOICE in 1) LOCALES="en" ;; 2) LOCALES="nl" ;; 3) LOCALES="de" ;; 4) LOCALES="es" ;; 5) LOCALES="fr" ;; 6) LOCALES="en nl de es fr" ;; *) echo "Invalid choice. Exiting." exit 1 ;; esac # Export LOCALES for use in PHP scripts export LOCALES echo "" echo "Selected language(s): $LOCALES" echo "" # Check mail configuration MAIL_HOST=$(php artisan tinker --execute="echo config('mail.mailers.smtp.host'); exit;" 2>/dev/null | grep -v ">>>" | grep -v "INFO" | grep -v "Psy" | tr -d '\n') if [ "$MAIL_HOST" == "localhost" ] || [ "$MAIL_HOST" == "127.0.0.1" ]; then echo "⚠️ NOTICE: Emails will be sent to Mailpit (local mail catcher)" echo "" echo "To view emails, open in your browser:" echo " → http://localhost:8025/mailpit/" echo "" echo "To send to real email, update .env with SMTP credentials" echo "See: scripts/test-transactional-emails-info.txt" echo "" read -p "Continue with Mailpit? (y/n): " CONTINUE if [ "$CONTINUE" != "y" ] && [ "$CONTINUE" != "Y" ]; then echo "Cancelled." exit 0 fi # Use default email for Mailpit TEST_EMAIL="test@test.org" echo "" echo "Using default email address: $TEST_EMAIL" else # Ask for email address when using real SMTP echo "" read -p "Enter test email address: " TEST_EMAIL if [ -z "$TEST_EMAIL" ]; then echo "Error: Email address required" exit 1 fi fi echo "" echo "Queueing emails to: $TEST_EMAIL" echo "Note: Emails will be queued on 'emails' queue" echo "" # 1. Transfer Received echo "1. Transfer Received Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$transaction = App\Models\Transaction::with(['accountFrom.accountable', 'accountTo.accountable'])->whereHas('accountFrom')->whereHas('accountTo')->first(); if (\$transaction) { foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\TransferReceived(\$transaction, \$locale))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } } else { echo ' ⚠ Skipped: No transactions found' . PHP_EOL; } exit; " # 2. Profile Edited by Admin echo "" echo "2. Profile Edited by Admin Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$user = App\Models\User::whereNull('deleted_at')->first(); if (\$user) { \$changedFields = ['name', 'email', 'about_short']; foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$user->lang_preference = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ProfileEditedByAdminMail(\$user, \$changedFields))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } } exit; " # 3. Profile Link Changed echo "" echo "3. Profile Link Changed Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$user1 = App\Models\User::whereNull('deleted_at')->first(); \$user2 = App\Models\User::whereNull('deleted_at')->skip(1)->first() ?? \$user1; if (\$user1 && \$user2) { \$user1->lang_preference = 'en'; foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$user1->lang_preference = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ProfileLinkChangedMail(\$user1, \$user2, 'attached'))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } } exit; " # 4. User Deleted (Manual deletion) echo "" echo "4a. User Deleted Email (Manual deletion)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$user = App\Models\User::whereNull('deleted_at')->first(); if (\$user) { foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$data = [ 'time' => now()->format('Y-m-d H:i:s'), 'deletedUser' => (object)['name' => \$user->name, 'full_name' => \$user->name, 'lang_preference' => \$locale], 'mail' => '$TEST_EMAIL', 'balanceHandlingOption' => 'delete', 'totalBalance' => 500, 'donationAccountId' => null, 'donationAccountName' => null, 'donationOrganizationName' => null, 'autoDeleted' => false, ]; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\UserDeletedMail(\$data))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued (manual)' . PHP_EOL; } } exit; " # 4b. User Deleted (Auto-deletion with inactivity info) echo "" echo "4b. User Deleted Email (Auto-deletion)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$user = App\Models\User::whereNull('deleted_at')->first(); if (\$user) { // Get config values \$daysNotLoggedIn = timebank_config('profile_inactive.days_not_logged_in'); \$daysAfterInactive = timebank_config('delete_profile.days_after_inactive.run_delete'); \$totalDaysToDelete = \$daysNotLoggedIn + \$daysAfterInactive; foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$data = [ 'time' => now()->format('Y-m-d H:i:s'), 'deletedUser' => (object)['name' => \$user->name, 'full_name' => \$user->name, 'lang_preference' => \$locale], 'mail' => '$TEST_EMAIL', 'balanceHandlingOption' => 'delete', 'totalBalance' => 500, 'donationAccountId' => null, 'donationAccountName' => null, 'donationOrganizationName' => null, 'autoDeleted' => true, 'daysNotLoggedIn' => \$daysNotLoggedIn, 'daysAfterInactive' => \$daysAfterInactive, 'totalDaysToDelete' => \$totalDaysToDelete, ]; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\UserDeletedMail(\$data))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued (auto-delete: ' . \$totalDaysToDelete . ' days total)' . PHP_EOL; } } exit; " # 5. Email Verification echo "" echo "5. Email Verification Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$user = App\Models\User::whereNull('deleted_at')->first(); if (\$user) { foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$user->lang_preference = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\VerifyProfileEmailMailable(\$user))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } } exit; " # 6. Inactive Profile Warning 1 echo "" echo "6. Inactive Profile Warning 1 Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$user = App\Models\User::whereNull('deleted_at')->first(); if (\$user) { // Get config values \$daysNotLoggedIn = timebank_config('profile_inactive.days_not_logged_in'); \$warningDay1 = timebank_config('delete_profile.days_after_inactive.warning_1'); \$deleteDay = timebank_config('delete_profile.days_after_inactive.run_delete'); // Calculate days for warning 1 \$daysElapsed = \$daysNotLoggedIn + \$warningDay1; \$daysRemaining = \$deleteDay - \$warningDay1; // Format accounts data as expected by the mail class \$accountsData = []; \$totalBalance = 0; \$profileAccounts = \$user->accounts()->active()->notRemoved()->get(); foreach (\$profileAccounts as \$account) { \$accountsData[] = [ 'id' => \$account->id, 'name' => \$account->name, 'balance' => \$account->balance, 'balanceFormatted' => tbFormat(\$account->balance), ]; \$totalBalance += \$account->balance; } foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { app()->setLocale(\$locale); \$timeRemaining = trans_choice('days_remaining', \$daysRemaining, ['count' => \$daysRemaining]); \$user->lang_preference = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\InactiveProfileWarning1Mail(\$user, 'User', \$timeRemaining, \$daysRemaining, \$accountsData, \$totalBalance, \$daysElapsed))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued (days elapsed: ' . \$daysElapsed . ', days remaining: ' . \$daysRemaining . ')' . PHP_EOL; } } exit; " # 7. Inactive Profile Warning 2 echo "" echo "7. Inactive Profile Warning 2 Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$user = App\Models\User::whereNull('deleted_at')->first(); if (\$user) { // Get config values \$daysNotLoggedIn = timebank_config('profile_inactive.days_not_logged_in'); \$warningDay2 = timebank_config('delete_profile.days_after_inactive.warning_2'); \$deleteDay = timebank_config('delete_profile.days_after_inactive.run_delete'); // Calculate days for warning 2 \$daysElapsed = \$daysNotLoggedIn + \$warningDay2; \$daysRemaining = \$deleteDay - \$warningDay2; // Format accounts data as expected by the mail class \$accountsData = []; \$totalBalance = 0; \$profileAccounts = \$user->accounts()->active()->notRemoved()->get(); foreach (\$profileAccounts as \$account) { \$accountsData[] = [ 'id' => \$account->id, 'name' => \$account->name, 'balance' => \$account->balance, 'balanceFormatted' => tbFormat(\$account->balance), ]; \$totalBalance += \$account->balance; } foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { app()->setLocale(\$locale); \$timeRemaining = trans_choice('days_remaining', \$daysRemaining, ['count' => \$daysRemaining]); \$user->lang_preference = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\InactiveProfileWarning2Mail(\$user, 'User', \$timeRemaining, \$daysRemaining, \$accountsData, \$totalBalance, \$daysElapsed))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued (days elapsed: ' . \$daysElapsed . ', days remaining: ' . \$daysRemaining . ')' . PHP_EOL; } } exit; " # 8. Inactive Profile Warning Final echo "" echo "8. Inactive Profile Warning Final Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$user = App\Models\User::whereNull('deleted_at')->first(); if (\$user) { // Get config values \$daysNotLoggedIn = timebank_config('profile_inactive.days_not_logged_in'); \$warningFinal = timebank_config('delete_profile.days_after_inactive.warning_final'); \$deleteDay = timebank_config('delete_profile.days_after_inactive.run_delete'); // Calculate days for final warning \$daysElapsed = \$daysNotLoggedIn + \$warningFinal; \$daysRemaining = \$deleteDay - \$warningFinal; // Format accounts data as expected by the mail class \$accountsData = []; \$totalBalance = 0; \$profileAccounts = \$user->accounts()->active()->notRemoved()->get(); foreach (\$profileAccounts as \$account) { \$accountsData[] = [ 'id' => \$account->id, 'name' => \$account->name, 'balance' => \$account->balance, 'balanceFormatted' => tbFormat(\$account->balance), ]; \$totalBalance += \$account->balance; } foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { app()->setLocale(\$locale); \$timeRemaining = trans_choice('days_remaining', \$daysRemaining, ['count' => \$daysRemaining]); \$user->lang_preference = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\InactiveProfileWarningFinalMail(\$user, 'User', \$timeRemaining, \$daysRemaining, \$accountsData, \$totalBalance, \$daysElapsed))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued (days elapsed: ' . \$daysElapsed . ', days remaining: ' . \$daysRemaining . ')' . PHP_EOL; } } exit; " # 9. New Message (Chat) - User to User echo "" echo "9. New Message Email (User to User)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$conversation = Namu\WireChat\Models\Conversation::with(['messages.conversation.participants', 'participants.participantable']) ->whereHas('participants', function(\$query) { \$query->whereNotNull('participantable_id')->whereNotNull('participantable_type'); }) ->has('messages') ->first(); if (\$conversation && \$conversation->messages->count() > 0) { \$message = \$conversation->messages->first(); // Ensure the conversation relationship is loaded if (!\$message->relationLoaded('conversation')) { \$message->load('conversation.participants'); } \$participants = \$conversation->participants->filter(function(\$p) { return \$p->participantable !== null; }); if (\$participants->count() >= 2) { \$sender = \$participants->first()->participantable; \$recipient = \$participants->skip(1)->first()->participantable; \$event = new Namu\WireChat\Events\MessageCreated(\$message); foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\NewMessageMail(\$event, \$sender, \$recipient, \$locale))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } } else { echo ' ⚠ Skipped: Not enough valid participants' . PHP_EOL; } } else { echo ' ⚠ Skipped: No conversations with messages and participants found' . PHP_EOL; } exit; " # 9b. New Message (Chat) - User to Organization echo "" echo "9b. New Message Email (User to Organization)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" // Use specific Organization 1 and conversation 7 \$organization = App\Models\Organization::find(1); if (!\$organization) { echo ' ⚠ Skipped: Organization 1 not found' . PHP_EOL; exit; } // Find conversation 7 \$conversation = Namu\WireChat\Models\Conversation::find(7); if (!\$conversation) { echo ' ⚠ Skipped: Conversation 7 not found' . PHP_EOL; exit; } // Get a message from this conversation \$message = \$conversation->messages()->first(); if (!\$message) { echo ' ⚠ Skipped: No messages found in conversation 7' . PHP_EOL; exit; } // Ensure relationships are loaded \$message->load('conversation.participants.participantable'); // Get the sender (should be a user) \$participants = \$conversation->participants->filter(function(\$p) { return \$p->participantable !== null; }); \$sender = null; foreach (\$participants as \$participant) { if (\$participant->participantable_type === 'App\\\\Models\\\\User') { \$sender = \$participant->participantable; break; } } if (!\$sender) { echo ' ⚠ Skipped: No user participant found in conversation' . PHP_EOL; exit; } // Create the event \$event = new Namu\WireChat\Events\MessageCreated(\$message); // The organization is the recipient // The email should be sent to the organization's email // When clicked, it should prompt user login first, then organization login foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\NewMessageMail(\$event, \$sender, \$organization, \$locale))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued (sender: ' . \$sender->name . ', recipient: ' . \$organization->name . ')' . PHP_EOL; } echo ' → Conversation URL will require organization login after user authentication' . PHP_EOL; echo ' → Conversation ID: 7' . PHP_EOL; echo ' → Organization ID: 1' . PHP_EOL; exit; " # 9c. New Message (Chat) - Organization to Bank echo "" echo "9c. New Message Email (Organization to Bank)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" // Use specific Bank 6 and conversation 18 \$bank = App\Models\Bank::find(6); if (!\$bank) { echo ' ⚠ Skipped: Bank 6 not found' . PHP_EOL; exit; } // Find conversation 18 (between Organization 1 and Bank 6) \$conversation = Namu\WireChat\Models\Conversation::find(18); if (!\$conversation) { echo ' ⚠ Skipped: Conversation 18 not found' . PHP_EOL; exit; } // Get a message from this conversation \$message = \$conversation->messages()->first(); if (!\$message) { echo ' ⚠ Skipped: No messages found in conversation 18' . PHP_EOL; exit; } // Ensure relationships are loaded \$message->load('conversation.participants.participantable'); // Get the sender (should be the organization) \$participants = \$conversation->participants->filter(function(\$p) { return \$p->participantable !== null; }); \$sender = null; foreach (\$participants as \$participant) { if (\$participant->participantable_type === 'App\\\\Models\\\\Organization') { \$sender = \$participant->participantable; break; } } if (!\$sender) { echo ' ⚠ Skipped: No organization participant found in conversation' . PHP_EOL; exit; } // Create the event \$event = new Namu\WireChat\Events\MessageCreated(\$message); // The bank is the recipient // The email should be sent to the bank's email // When clicked, it should prompt user login first, then bank login foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\NewMessageMail(\$event, \$sender, \$bank, \$locale))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued (sender: ' . \$sender->name . ', recipient: ' . \$bank->name . ')' . PHP_EOL; } echo ' → Conversation URL will require bank login after user authentication' . PHP_EOL; echo ' → Conversation ID: 18' . PHP_EOL; echo ' → Bank ID: 6' . PHP_EOL; exit; " # 10. Reaction Created (Star) echo "" echo "10. Reaction Created Email (Star)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" // Find Star reaction type \$starType = Cog\Laravel\Love\ReactionType\Models\ReactionType::where('name', 'Star')->first(); if (\$starType) { // Find a Star reaction or create a test one \$reaction = Cog\Laravel\Love\Reaction\Models\Reaction::with(['reactant', 'reacter']) ->where('reaction_type_id', \$starType->getId()) ->whereHas('reactant') ->whereHas('reacter') ->first(); if (!\$reaction) { // Create a test star reaction \$user = App\Models\User::whereNull('deleted_at')->first(); \$targetUser = App\Models\User::whereNull('deleted_at')->skip(1)->first() ?? \$user; if (\$user && \$targetUser) { \$reacter = \$user->getLoveReacter(); \$reactant = \$targetUser->getLoveReactant(); \$reaction = \$reactant->createReactionBy(\$reacter, \$starType); } } if (\$reaction) { foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { // Temporarily set recipient locale \$recipient = \$reaction->getReactant()->getReactable(); \$originalLocale = \$recipient->lang_preference; \$recipient->lang_preference = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ReactionCreatedMail(\$reaction))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; // Restore original locale \$recipient->lang_preference = \$originalLocale; } } else { echo ' ⚠ Skipped: Could not create or find Star reaction' . PHP_EOL; } } else { echo ' ⚠ Skipped: Star reaction type not found' . PHP_EOL; } exit; " # 11. Tag Added echo "" echo "11. Tag Added Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$tag = App\Models\Tag::first(); if (\$tag) { foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\TagAddedMail(\$tag->tag_id, \$locale))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } } else { echo ' ⚠ Skipped: No tags found' . PHP_EOL; } exit; " # 12. Reservation Created echo "" echo "12. Reservation Created Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$post = App\Models\Post::with(['meeting'])->whereHas('meeting')->first(); if (\$post) { \$user = App\Models\User::whereNull('deleted_at')->first(); if (\$user) { // Create a mock reaction for the reservation \$reactionType = Cog\Laravel\Love\ReactionType\Models\ReactionType::where('name', 'Reservation')->first(); if (\$reactionType) { \$reactant = \$post->getLoveReactant(); \$reacter = \$user->getLoveReacter(); // Try to find or create a reaction \$reaction = Cog\Laravel\Love\Reaction\Models\Reaction::where('reactant_id', \$reactant->getId()) ->where('reacter_id', \$reacter->getId()) ->where('reaction_type_id', \$reactionType->getId()) ->first(); if (!\$reaction) { \$reaction = \$reactant->createReactionBy(\$reacter, \$reactionType); } foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$user->lang_preference = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ReservationCreatedMail(\$reaction))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } } else { echo ' ⚠ Skipped: Reservation reaction type not found' . PHP_EOL; } } else { echo ' ⚠ Skipped: No users found' . PHP_EOL; } } else { echo ' ⚠ Skipped: No posts with meetings found' . PHP_EOL; } exit; " # 13. Reservation Cancelled echo "" echo "13. Reservation Cancelled Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$post = App\Models\Post::with(['meeting', 'translations'])->whereHas('meeting')->first(); if (\$post) { \$user = App\Models\User::whereNull('deleted_at')->first(); if (\$user) { foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$data = [ 'reacter_type' => get_class(\$user), 'reacter_id' => \$user->id, 'reacter_name' => \$user->name, 'reacter_locale' => \$locale, 'post_id' => \$post->id, ]; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ReservationCancelledMail(\$data))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } } else { echo ' ⚠ Skipped: No users found' . PHP_EOL; } } else { echo ' ⚠ Skipped: No posts with meetings found' . PHP_EOL; } exit; " # 14. Reservation Update echo "" echo "14. Reservation Update Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$post = App\Models\Post::with(['meeting', 'translations', 'author'])->whereHas('meeting')->first(); if (\$post) { \$user = App\Models\User::whereNull('deleted_at')->first(); \$organizer = \$post->author ?? \$post->postable ?? \$user; if (\$user && \$organizer) { \$message = 'This is a test update message from the event organizer.'; foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$user->lang_preference = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ReservationUpdateMail(\$user, \$post, \$message, \$organizer))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } } else { echo ' ⚠ Skipped: No users or organizer found' . PHP_EOL; } } else { echo ' ⚠ Skipped: No posts with meetings found' . PHP_EOL; } exit; " # 15. Call Expiry Emails echo "" echo "15a. Call Expired Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$user = App\Models\User::whereNull('deleted_at')->first(); \$call = App\Models\Call::where('callable_type', App\Models\User::class) ->where('callable_id', \$user->id) ->with(['tag']) ->first() ?? App\Models\Call::with(['tag'])->first(); if (\$call && \$user) { foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$user->lang_preference = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\CallExpiredMail(\$call, \$user, 'User'))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } } else { echo ' ⚠ Skipped: No calls found' . PHP_EOL; } exit; " echo "" echo "15b. Call Expiring Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$user = App\Models\User::whereNull('deleted_at')->first(); \$call = App\Models\Call::where('callable_type', App\Models\User::class) ->where('callable_id', \$user->id) ->with(['tag']) ->first() ?? App\Models\Call::with(['tag'])->first(); if (\$call && \$user) { foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$user->lang_preference = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\CallExpiringMail(\$call, \$user, 'User', 7))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } } else { echo ' ⚠ Skipped: No calls found' . PHP_EOL; } exit; " echo "" echo "15c. Call Blocked Email" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$user = App\Models\User::whereNull('deleted_at')->first(); \$call = App\Models\Call::where('callable_type', App\Models\User::class) ->where('callable_id', \$user->id) ->with(['tag']) ->first() ?? App\Models\Call::with(['tag'])->first(); if (\$call && \$user) { foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$user->lang_preference = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\CallBlockedMail(\$call, \$user, 'User'))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } } else { echo ' ⚠ Skipped: No calls found' . PHP_EOL; } exit; " # 16a. Contact Form - General Contact (to recipient) echo "" echo "15a. Contact Form Email - General Contact (to recipient)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$testData = [ 'name' => 'Test User', 'full_name' => 'Test User Full Name', 'email' => '$TEST_EMAIL', 'subject' => 'General Question About Timebanking', 'message' => 'Hi, I have some questions about how timebanking works. Can you provide more information about creating an account?', 'context' => 'contact', 'is_authenticated' => false, 'browser_locale' => 'en', ]; foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$testData['browser_locale'] = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ContactFormMailable(\$testData))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } exit; " # 15b. Contact Form - Report Issue (to recipient) echo "" echo "15b. Contact Form Email - Report Issue (to recipient)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$testData = [ 'name' => 'Test User', 'full_name' => 'Test User Full Name', 'email' => '$TEST_EMAIL', 'subject' => 'Inappropriate Profile Content', 'message' => 'I found a profile that contains inappropriate content and violates the community guidelines.', 'context' => 'report-issue', 'is_authenticated' => true, 'browser_locale' => 'en', ]; foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$testData['browser_locale'] = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ContactFormMailable(\$testData))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } exit; " # 15c. Contact Form - Report Error (to recipient) echo "" echo "15c. Contact Form Email - Report Error (to recipient)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$testData = [ 'name' => 'Test User', 'full_name' => 'Test User Full Name', 'email' => '$TEST_EMAIL', 'subject' => '', 'message' => 'When I tried to send a transaction, I got a 500 error. The page just showed a blank screen.', 'url' => 'http://localhost:8000/nl/betalen', 'context' => 'report-error', 'is_authenticated' => true, 'browser_locale' => 'en', ]; foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$testData['browser_locale'] = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ContactFormMailable(\$testData))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } exit; " # 15d. Contact Form - Delete Profile Request (to recipient) echo "" echo "15d. Contact Form Email - Delete Profile Request (to recipient)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$testData = [ 'name' => 'Test User', 'full_name' => 'Test User Full Name', 'email' => '$TEST_EMAIL', 'subject' => '', 'message' => 'I would like to permanently delete my account and all associated data from the system.', 'context' => 'delete-profile', 'is_authenticated' => true, 'browser_locale' => 'en', ]; foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$testData['browser_locale'] = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ContactFormMailable(\$testData))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } exit; " # 16a. Contact Form Copy - General Contact (to submitter) echo "" echo "16a. Contact Form Copy Email - General Contact (to submitter)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$testData = [ 'name' => 'Test User', 'full_name' => 'Test User Full Name', 'email' => '$TEST_EMAIL', 'subject' => 'General Question About Timebanking', 'message' => 'Hi, I have some questions about how timebanking works. Can you provide more information about creating an account?', 'context' => 'contact', 'is_authenticated' => false, 'browser_locale' => 'en', ]; foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$testData['browser_locale'] = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ContactFormCopyMailable(\$testData))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } exit; " # 16b. Contact Form Copy - Report Issue (to submitter) echo "" echo "16b. Contact Form Copy Email - Report Issue (to submitter)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$testData = [ 'name' => 'Test User', 'full_name' => 'Test User Full Name', 'email' => '$TEST_EMAIL', 'subject' => 'Inappropriate Profile Content', 'message' => 'I found a profile that contains inappropriate content and violates the community guidelines.', 'context' => 'report-issue', 'is_authenticated' => true, 'browser_locale' => 'en', ]; foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$testData['browser_locale'] = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ContactFormCopyMailable(\$testData))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } exit; " # 16c. Contact Form Copy - Report Error (to submitter) echo "" echo "16c. Contact Form Copy Email - Report Error (to submitter)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$testData = [ 'name' => 'Test User', 'full_name' => 'Test User Full Name', 'email' => '$TEST_EMAIL', 'subject' => '', 'message' => 'When I tried to send a transaction, I got a 500 error. The page just showed a blank screen.', 'url' => 'http://localhost:8000/nl/betalen', 'context' => 'report-error', 'is_authenticated' => true, 'browser_locale' => 'en', ]; foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$testData['browser_locale'] = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ContactFormCopyMailable(\$testData))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } exit; " # 16d. Contact Form Copy - Delete Profile Request (to submitter) echo "" echo "16d. Contact Form Copy Email - Delete Profile Request (to submitter)" echo "--------------------------------------------------------------------------------" php artisan tinker --execute=" \$testData = [ 'name' => 'Test User', 'full_name' => 'Test User Full Name', 'email' => '$TEST_EMAIL', 'subject' => '', 'message' => 'I would like to permanently delete my account and all associated data from the system.', 'context' => 'delete-profile', 'is_authenticated' => true, 'browser_locale' => 'en', ]; foreach (explode(' ', getenv('LOCALES') ?: 'en nl de es fr') as \$locale) { \$testData['browser_locale'] = \$locale; Illuminate\Support\Facades\Mail::to('$TEST_EMAIL')->queue((new App\Mail\ContactFormCopyMailable(\$testData))->onQueue('emails')); echo ' ✓ ' . \$locale . ': Queued' . PHP_EOL; } exit; " echo "" echo "===============================================" echo "All emails queued! Processing queue..." echo "===============================================" echo "" php artisan queue:work --queue=emails --stop-when-empty --timeout=60 echo "" echo "===============================================" echo "All emails sent successfully!" echo "===============================================" echo "" if [ "$MAIL_HOST" == "localhost" ] || [ "$MAIL_HOST" == "127.0.0.1" ]; then echo "📧 Emails sent to: $TEST_EMAIL (via Mailpit)" echo "" echo "To view the emails, open in your browser:" echo " → http://localhost:8025/mailpit/" echo "" echo "Total emails sent: 100 (5 locales × 20 email types)" echo "" echo "Email types tested:" echo " 1. Transfer Received" echo " 2. Profile Edited by Admin" echo " 3. Profile Link Changed" echo " 4a. User Deleted (Manual)" echo " 4b. User Deleted (Auto-deletion)" echo " 5. Email Verification" echo " 6. Inactive Profile Warning 1" echo " 7. Inactive Profile Warning 2" echo " 8. Inactive Profile Warning Final" echo " 9. New Message (Chat)" echo " 10. Reaction Created (Star)" echo " 11. Tag Added" echo " 12. Reservation Created" echo " 13. Reservation Cancelled" echo " 14. Reservation Update" echo " 15a. Call Expired" echo " 15b. Call Expiring" echo " 15c. Call Blocked" echo " 16a. Contact Form - General Contact (to recipient)" echo " 16b. Contact Form - Report Issue (to recipient)" echo " 16c. Contact Form - Report Error (to recipient)" echo " 16d. Contact Form - Delete Profile (to recipient)" echo " 17a. Contact Form Copy - General Contact (to submitter)" echo " 17b. Contact Form Copy - Report Issue (to submitter)" echo " 17c. Contact Form Copy - Report Error (to submitter)" echo " 17d. Contact Form Copy - Delete Profile (to submitter)" else echo "Done! Check your inbox at $TEST_EMAIL" echo "" echo "Total emails sent: 115 (5 locales × 23 email types)" fi