2023-09-01 13:52:18 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
|
2023-09-11 10:16:26 +00:00
|
|
|
use App\Jobs\SendConfirmationForWaitlistJob;
|
2023-09-01 13:52:18 +00:00
|
|
|
use App\Models\Application;
|
|
|
|
use App\Models\ApplicationPreview;
|
|
|
|
use App\Models\ScheduledDatabaseBackup;
|
2023-09-13 09:05:10 +00:00
|
|
|
use App\Models\Server;
|
2023-09-01 13:52:18 +00:00
|
|
|
use App\Models\StandalonePostgresql;
|
2023-09-12 10:03:17 +00:00
|
|
|
use App\Models\Team;
|
2023-09-11 10:16:26 +00:00
|
|
|
use App\Models\Waitlist;
|
2023-09-01 13:52:18 +00:00
|
|
|
use App\Notifications\Application\DeploymentFailed;
|
|
|
|
use App\Notifications\Application\DeploymentSuccess;
|
|
|
|
use App\Notifications\Application\StatusChanged;
|
|
|
|
use App\Notifications\Database\BackupFailed;
|
|
|
|
use App\Notifications\Database\BackupSuccess;
|
2024-03-01 17:24:14 +00:00
|
|
|
use App\Notifications\Database\DailyBackup;
|
2023-09-01 13:52:18 +00:00
|
|
|
use App\Notifications\Test;
|
|
|
|
use Exception;
|
|
|
|
use Illuminate\Console\Command;
|
|
|
|
use Illuminate\Mail\Message;
|
|
|
|
use Illuminate\Notifications\Messages\MailMessage;
|
|
|
|
use Mail;
|
|
|
|
|
2023-09-12 11:19:55 +00:00
|
|
|
use function Laravel\Prompts\confirm;
|
2023-09-01 13:52:18 +00:00
|
|
|
use function Laravel\Prompts\select;
|
2023-09-08 15:42:08 +00:00
|
|
|
use function Laravel\Prompts\text;
|
2023-09-01 13:52:18 +00:00
|
|
|
|
2023-09-12 11:19:55 +00:00
|
|
|
class Emails extends Command
|
2023-09-01 13:52:18 +00:00
|
|
|
{
|
|
|
|
/**
|
|
|
|
* The name and signature of the console command.
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
2023-09-12 11:19:55 +00:00
|
|
|
protected $signature = 'emails';
|
2023-09-01 13:52:18 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The console command description.
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
2023-09-12 11:19:55 +00:00
|
|
|
protected $description = 'Send out test / prod emails';
|
2023-09-01 13:52:18 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Execute the console command.
|
|
|
|
*/
|
|
|
|
private ?MailMessage $mail = null;
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2023-09-12 11:19:55 +00:00
|
|
|
private ?string $email = null;
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2023-09-01 13:52:18 +00:00
|
|
|
public function handle()
|
|
|
|
{
|
2023-09-08 15:42:08 +00:00
|
|
|
$type = select(
|
2023-09-01 13:52:18 +00:00
|
|
|
'Which Email should be sent?',
|
|
|
|
options: [
|
2023-09-25 18:57:52 +00:00
|
|
|
'updates' => 'Send Update Email to all users',
|
2023-09-01 13:52:18 +00:00
|
|
|
'emails-test' => 'Test',
|
2024-03-01 17:24:14 +00:00
|
|
|
'database-backup-statuses-daily' => 'Database - Backup Statuses (Daily)',
|
|
|
|
'application-deployment-success-daily' => 'Application - Deployment Success (Daily)',
|
2023-09-01 13:52:18 +00:00
|
|
|
'application-deployment-success' => 'Application - Deployment Success',
|
|
|
|
'application-deployment-failed' => 'Application - Deployment Failed',
|
|
|
|
'application-status-changed' => 'Application - Status Changed',
|
|
|
|
'backup-success' => 'Database - Backup Success',
|
|
|
|
'backup-failed' => 'Database - Backup Failed',
|
2023-09-15 09:19:36 +00:00
|
|
|
// 'invitation-link' => 'Invitation Link',
|
2023-09-01 13:52:18 +00:00
|
|
|
'waitlist-invitation-link' => 'Waitlist Invitation Link',
|
|
|
|
'waitlist-confirmation' => 'Waitlist Confirmation',
|
2023-09-12 10:03:17 +00:00
|
|
|
'realusers-before-trial' => 'REAL - Registered Users Before Trial without Subscription',
|
2023-09-13 09:05:10 +00:00
|
|
|
'realusers-server-lost-connection' => 'REAL - Server Lost Connection',
|
2023-09-01 13:52:18 +00:00
|
|
|
],
|
|
|
|
);
|
2023-09-25 18:57:52 +00:00
|
|
|
$emailsGathered = ['realusers-before-trial', 'realusers-server-lost-connection'];
|
2024-03-01 17:24:14 +00:00
|
|
|
if (isDev()) {
|
2024-06-10 20:43:34 +00:00
|
|
|
$this->email = 'test@example.com';
|
2024-03-01 17:24:14 +00:00
|
|
|
} else {
|
2024-06-10 20:43:34 +00:00
|
|
|
if (! in_array($type, $emailsGathered)) {
|
2024-03-01 17:24:14 +00:00
|
|
|
$this->email = text('Email Address to send to:');
|
|
|
|
}
|
2023-09-12 10:03:17 +00:00
|
|
|
}
|
2023-09-08 15:42:08 +00:00
|
|
|
set_transanctional_email_settings();
|
|
|
|
|
2023-09-01 13:52:18 +00:00
|
|
|
$this->mail = new MailMessage();
|
2024-06-10 20:43:34 +00:00
|
|
|
$this->mail->subject('Test Email');
|
2023-09-08 15:42:08 +00:00
|
|
|
switch ($type) {
|
2023-09-25 18:57:52 +00:00
|
|
|
case 'updates':
|
|
|
|
$teams = Team::all();
|
2024-06-10 20:43:34 +00:00
|
|
|
if (! $teams || $teams->isEmpty()) {
|
|
|
|
echo 'No teams found.'.PHP_EOL;
|
|
|
|
|
2023-09-25 18:57:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
$emails = [];
|
|
|
|
foreach ($teams as $team) {
|
|
|
|
foreach ($team->members as $member) {
|
|
|
|
if ($member->email && $member->marketing_emails) {
|
|
|
|
$emails[] = $member->email;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$emails = array_unique($emails);
|
2024-06-10 20:43:34 +00:00
|
|
|
$this->info('Sending to '.count($emails).' emails.');
|
2023-09-25 18:57:52 +00:00
|
|
|
foreach ($emails as $email) {
|
|
|
|
$this->info($email);
|
|
|
|
}
|
|
|
|
$confirmed = confirm('Are you sure?');
|
|
|
|
if ($confirmed) {
|
|
|
|
foreach ($emails as $email) {
|
|
|
|
$this->mail = new MailMessage();
|
|
|
|
$this->mail->subject('One-click Services, Docker Compose support');
|
|
|
|
$unsubscribeUrl = route('unsubscribe.marketing.emails', [
|
|
|
|
'token' => encrypt($email),
|
|
|
|
]);
|
2024-06-10 20:43:34 +00:00
|
|
|
$this->mail->view('emails.updates', ['unsubscribeUrl' => $unsubscribeUrl]);
|
2023-09-25 18:57:52 +00:00
|
|
|
$this->sendEmail($email);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2023-09-01 13:52:18 +00:00
|
|
|
case 'emails-test':
|
|
|
|
$this->mail = (new Test())->toMail();
|
2023-09-08 15:42:08 +00:00
|
|
|
$this->sendEmail();
|
2023-09-01 13:52:18 +00:00
|
|
|
break;
|
2024-03-01 17:24:14 +00:00
|
|
|
case 'database-backup-statuses-daily':
|
|
|
|
$scheduled_backups = ScheduledDatabaseBackup::all();
|
|
|
|
$databases = collect();
|
|
|
|
foreach ($scheduled_backups as $scheduled_backup) {
|
|
|
|
$last_days_backups = $scheduled_backup->get_last_days_backup_status();
|
|
|
|
if ($last_days_backups->isEmpty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$failed = $last_days_backups->where('status', 'failed');
|
|
|
|
$database = $scheduled_backup->database;
|
|
|
|
$databases->put($database->name, [
|
|
|
|
'failed_count' => $failed->count(),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
$this->mail = (new DailyBackup($databases))->toMail();
|
|
|
|
$this->sendEmail();
|
|
|
|
break;
|
|
|
|
case 'application-deployment-success-daily':
|
|
|
|
$applications = Application::all();
|
|
|
|
foreach ($applications as $application) {
|
|
|
|
$deployments = $application->get_last_days_deployments();
|
|
|
|
ray($deployments);
|
|
|
|
if ($deployments->isEmpty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$this->mail = (new DeploymentSuccess($application, 'test'))->toMail();
|
|
|
|
$this->sendEmail();
|
|
|
|
}
|
|
|
|
break;
|
2023-09-01 13:52:18 +00:00
|
|
|
case 'application-deployment-success':
|
|
|
|
$application = Application::all()->first();
|
|
|
|
$this->mail = (new DeploymentSuccess($application, 'test'))->toMail();
|
|
|
|
$this->sendEmail();
|
|
|
|
break;
|
|
|
|
case 'application-deployment-failed':
|
|
|
|
$application = Application::all()->first();
|
|
|
|
$preview = ApplicationPreview::all()->first();
|
2024-06-10 20:43:34 +00:00
|
|
|
if (! $preview) {
|
2023-09-01 13:52:18 +00:00
|
|
|
$preview = ApplicationPreview::create([
|
|
|
|
'application_id' => $application->id,
|
|
|
|
'pull_request_id' => 1,
|
|
|
|
'pull_request_html_url' => 'http://example.com',
|
|
|
|
'fqdn' => $application->fqdn,
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
$this->mail = (new DeploymentFailed($application, 'test'))->toMail();
|
|
|
|
$this->sendEmail();
|
|
|
|
$this->mail = (new DeploymentFailed($application, 'test', $preview))->toMail();
|
|
|
|
$this->sendEmail();
|
|
|
|
break;
|
|
|
|
case 'application-status-changed':
|
|
|
|
$application = Application::all()->first();
|
|
|
|
$this->mail = (new StatusChanged($application))->toMail();
|
|
|
|
$this->sendEmail();
|
|
|
|
break;
|
|
|
|
case 'backup-failed':
|
|
|
|
$backup = ScheduledDatabaseBackup::all()->first();
|
|
|
|
$db = StandalonePostgresql::all()->first();
|
2024-06-10 20:43:34 +00:00
|
|
|
if (! $backup) {
|
2023-09-01 13:52:18 +00:00
|
|
|
$backup = ScheduledDatabaseBackup::create([
|
|
|
|
'enabled' => true,
|
|
|
|
'frequency' => 'daily',
|
|
|
|
'save_s3' => false,
|
|
|
|
'database_id' => $db->id,
|
|
|
|
'database_type' => $db->getMorphClass(),
|
|
|
|
'team_id' => 0,
|
|
|
|
]);
|
|
|
|
}
|
2024-06-10 20:43:34 +00:00
|
|
|
$output = 'Because of an error, the backup of the database '.$db->name.' failed.';
|
2023-09-01 13:52:18 +00:00
|
|
|
$this->mail = (new BackupFailed($backup, $db, $output))->toMail();
|
|
|
|
$this->sendEmail();
|
|
|
|
break;
|
|
|
|
case 'backup-success':
|
|
|
|
$backup = ScheduledDatabaseBackup::all()->first();
|
|
|
|
$db = StandalonePostgresql::all()->first();
|
2024-06-10 20:43:34 +00:00
|
|
|
if (! $backup) {
|
2023-09-01 13:52:18 +00:00
|
|
|
$backup = ScheduledDatabaseBackup::create([
|
|
|
|
'enabled' => true,
|
|
|
|
'frequency' => 'daily',
|
|
|
|
'save_s3' => false,
|
|
|
|
'database_id' => $db->id,
|
|
|
|
'database_type' => $db->getMorphClass(),
|
|
|
|
'team_id' => 0,
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
$this->mail = (new BackupSuccess($backup, $db))->toMail();
|
|
|
|
$this->sendEmail();
|
|
|
|
break;
|
2023-09-25 18:57:52 +00:00
|
|
|
// case 'invitation-link':
|
|
|
|
// $user = User::all()->first();
|
|
|
|
// $invitation = TeamInvitation::whereEmail($user->email)->first();
|
|
|
|
// if (!$invitation) {
|
|
|
|
// $invitation = TeamInvitation::create([
|
|
|
|
// 'uuid' => Str::uuid(),
|
|
|
|
// 'email' => $user->email,
|
|
|
|
// 'team_id' => 1,
|
|
|
|
// 'link' => 'http://example.com',
|
|
|
|
// ]);
|
|
|
|
// }
|
|
|
|
// $this->mail = (new InvitationLink($user))->toMail();
|
|
|
|
// $this->sendEmail();
|
|
|
|
// break;
|
2023-09-01 13:52:18 +00:00
|
|
|
case 'waitlist-invitation-link':
|
|
|
|
$this->mail = new MailMessage();
|
|
|
|
$this->mail->view('emails.waitlist-invitation', [
|
2023-09-11 10:16:26 +00:00
|
|
|
'loginLink' => 'https://coolify.io',
|
2023-09-01 13:52:18 +00:00
|
|
|
]);
|
|
|
|
$this->mail->subject('Congratulations! You are invited to join Coolify Cloud.');
|
|
|
|
$this->sendEmail();
|
|
|
|
break;
|
|
|
|
case 'waitlist-confirmation':
|
2023-09-11 10:16:26 +00:00
|
|
|
$found = Waitlist::where('email', $this->email)->first();
|
|
|
|
if ($found) {
|
|
|
|
SendConfirmationForWaitlistJob::dispatch($this->email, $found->uuid);
|
|
|
|
} else {
|
|
|
|
throw new Exception('Waitlist not found');
|
|
|
|
}
|
|
|
|
|
2023-09-01 13:52:18 +00:00
|
|
|
break;
|
2023-09-12 10:03:17 +00:00
|
|
|
case 'realusers-before-trial':
|
|
|
|
$this->mail = new MailMessage();
|
|
|
|
$this->mail->view('emails.before-trial-conversion');
|
|
|
|
$this->mail->subject('Trial period has been added for all subscription plans.');
|
|
|
|
$teams = Team::doesntHave('subscription')->where('id', '!=', 0)->get();
|
2024-06-10 20:43:34 +00:00
|
|
|
if (! $teams || $teams->isEmpty()) {
|
|
|
|
echo 'No teams found.'.PHP_EOL;
|
|
|
|
|
2023-09-12 10:03:17 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
$emails = [];
|
|
|
|
foreach ($teams as $team) {
|
2023-09-12 11:19:55 +00:00
|
|
|
foreach ($team->members as $member) {
|
2023-09-12 10:03:17 +00:00
|
|
|
if ($member->email) {
|
|
|
|
$emails[] = $member->email;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$emails = array_unique($emails);
|
2024-06-10 20:43:34 +00:00
|
|
|
$this->info('Sending to '.count($emails).' emails.');
|
2023-09-12 10:03:17 +00:00
|
|
|
foreach ($emails as $email) {
|
2023-09-12 11:19:55 +00:00
|
|
|
$this->info($email);
|
2023-09-12 10:03:17 +00:00
|
|
|
}
|
2023-09-12 11:19:55 +00:00
|
|
|
$confirmed = confirm('Are you sure?');
|
|
|
|
if ($confirmed) {
|
|
|
|
foreach ($emails as $email) {
|
|
|
|
$this->sendEmail($email);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2023-09-13 09:05:10 +00:00
|
|
|
case 'realusers-server-lost-connection':
|
|
|
|
$serverId = text('Server Id');
|
|
|
|
$server = Server::find($serverId);
|
2024-06-10 20:43:34 +00:00
|
|
|
if (! $server) {
|
2023-09-13 09:05:10 +00:00
|
|
|
throw new Exception('Server not found');
|
|
|
|
}
|
|
|
|
$admins = [];
|
|
|
|
$members = $server->team->members;
|
|
|
|
foreach ($members as $member) {
|
|
|
|
if ($member->isAdmin()) {
|
|
|
|
$admins[] = $member->email;
|
|
|
|
}
|
|
|
|
}
|
2024-06-10 20:43:34 +00:00
|
|
|
$this->info('Sending to '.count($admins).' admins.');
|
2023-09-13 09:05:10 +00:00
|
|
|
foreach ($admins as $admin) {
|
|
|
|
$this->info($admin);
|
|
|
|
}
|
|
|
|
$this->mail = new MailMessage();
|
|
|
|
$this->mail->view('emails.server-lost-connection', [
|
|
|
|
'name' => $server->name,
|
|
|
|
]);
|
2024-06-10 20:43:34 +00:00
|
|
|
$this->mail->subject('Action required: Server '.$server->name.' lost connection.');
|
2023-09-13 09:05:10 +00:00
|
|
|
foreach ($admins as $email) {
|
|
|
|
$this->sendEmail($email);
|
|
|
|
}
|
|
|
|
break;
|
2023-09-01 13:52:18 +00:00
|
|
|
}
|
|
|
|
}
|
2024-06-10 20:43:34 +00:00
|
|
|
|
|
|
|
private function sendEmail(?string $email = null)
|
2023-09-01 13:52:18 +00:00
|
|
|
{
|
2023-09-12 10:03:17 +00:00
|
|
|
if ($email) {
|
|
|
|
$this->email = $email;
|
|
|
|
}
|
2023-09-01 13:52:18 +00:00
|
|
|
Mail::send(
|
|
|
|
[],
|
|
|
|
[],
|
|
|
|
fn (Message $message) => $message
|
2023-09-08 15:42:08 +00:00
|
|
|
->to($this->email)
|
2023-09-01 13:52:18 +00:00
|
|
|
->subject($this->mail->subject)
|
2024-06-10 20:43:34 +00:00
|
|
|
->html((string) $this->mail->render())
|
2023-09-01 13:52:18 +00:00
|
|
|
);
|
2023-09-12 11:19:55 +00:00
|
|
|
$this->info("Email sent to $this->email successfully. 📧");
|
2023-09-01 13:52:18 +00:00
|
|
|
}
|
|
|
|
}
|