Files
timebank-cc-public/scripts/test-transactional-emails.sh
Ronald Huynen 2547717edb Initial commit
2026-03-23 21:37:59 +01:00

982 lines
37 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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