Initial commit

This commit is contained in:
Ronald Huynen
2026-03-23 21:37:59 +01:00
commit 2547717edb
2193 changed files with 972171 additions and 0 deletions

View File

@@ -0,0 +1,981 @@
#!/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