diff --git a/app/Console/Commands/Emails.php b/app/Console/Commands/Emails.php index 7324ad694..821041002 100644 --- a/app/Console/Commands/Emails.php +++ b/app/Console/Commands/Emails.php @@ -56,6 +56,7 @@ public function handle() $type = select( 'Which Email should be sent?', options: [ + 'updates' => 'Send Update Email to all users', 'emails-test' => 'Test', 'application-deployment-success' => 'Application - Deployment Success', 'application-deployment-failed' => 'Application - Deployment Failed', @@ -69,7 +70,7 @@ public function handle() 'realusers-server-lost-connection' => 'REAL - Server Lost Connection', ], ); - $emailsGathered = ['realusers-before-trial','realusers-server-lost-connection']; + $emailsGathered = ['realusers-before-trial', 'realusers-server-lost-connection']; if (!in_array($type, $emailsGathered)) { $this->email = text('Email Address to send to'); } @@ -78,6 +79,38 @@ public function handle() $this->mail = new MailMessage(); $this->mail->subject("Test Email"); switch ($type) { + case 'updates': + $teams = Team::all(); + if (!$teams || $teams->isEmpty()) { + echo 'No teams found.' . PHP_EOL; + return; + } + $emails = []; + foreach ($teams as $team) { + foreach ($team->members as $member) { + if ($member->email && $member->marketing_emails) { + $emails[] = $member->email; + } + } + } + $emails = array_unique($emails); + $this->info("Sending to " . count($emails) . " emails."); + 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), + ]); + $this->mail->view('emails.updates',["unsubscribeUrl" => $unsubscribeUrl]); + $this->sendEmail($email); + } + } + break; case 'emails-test': $this->mail = (new Test())->toMail(); $this->sendEmail(); @@ -141,20 +174,20 @@ public function handle() $this->mail = (new BackupSuccess($backup, $db))->toMail(); $this->sendEmail(); break; - // 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; + // 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; case 'waitlist-invitation-link': $this->mail = new MailMessage(); $this->mail->view('emails.waitlist-invitation', [ diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index 26b90aa3f..a0038a597 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Models\EnvironmentVariable; use App\Models\Project; use App\Models\Server; use App\Models\Service; @@ -68,6 +69,7 @@ public function new() if ($type->startsWith('one-click-service-')) { $oneClickServiceName = $type->after('one-click-service-')->value(); $oneClickService = data_get($services, "$oneClickServiceName.compose"); + $oneClickDotEnvs = collect(data_get($services, "$oneClickServiceName.envs", [])); if ($oneClickService) { $service = Service::create([ 'name' => "$oneClickServiceName-" . Str::random(10), @@ -75,7 +77,17 @@ public function new() 'environment_id' => $environment->id, 'server_id' => (int) $server_id, ]); - + if ($oneClickDotEnvs->count() > 0) { + $oneClickDotEnvs->each(function ($value, $key) use ($service) { + EnvironmentVariable::create([ + 'key' => $key, + 'value' => $value, + 'service_id' => $service->id, + 'is_build_time' => false, + 'is_preview' => false, + ]); + }); + } $service->parse(isNew: true); return redirect()->route('project.service', [ diff --git a/app/Notifications/Test.php b/app/Notifications/Test.php index fbbd7a1fb..098a94920 100644 --- a/app/Notifications/Test.php +++ b/app/Notifications/Test.php @@ -2,9 +2,6 @@ namespace App\Notifications; -use App\Notifications\Channels\DiscordChannel; -use App\Notifications\Channels\EmailChannel; -use App\Notifications\Channels\TelegramChannel; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 0c4bfec72..f78ed363f 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -50,5 +50,8 @@ protected function configureRateLimiting(): void } return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()); }); + RateLimiter::for('5', function (Request $request) { + return Limit::perMinute(5)->by($request->user()?->id ?: $request->ip()); + }); } } diff --git a/database/migrations/2023_09_23_111813_update_users_databases_table.php b/database/migrations/2023_09_23_111813_update_users_databases_table.php new file mode 100644 index 000000000..d79b9471c --- /dev/null +++ b/database/migrations/2023_09_23_111813_update_users_databases_table.php @@ -0,0 +1,28 @@ +boolean('marketing_emails')->default(true); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('marketing_emails'); + }); + } +}; diff --git a/examples/service-templates.json b/examples/service-templates.json index 83f7b7ffa..a102b8784 100644 --- a/examples/service-templates.json +++ b/examples/service-templates.json @@ -6,9 +6,5 @@ "uptime-kuma": { "documentation": "https://github.com/louislam/uptime-kuma", "compose": "c2VydmljZXM6CiAgdXB0aW1lLWt1bWE6CiAgICBpbWFnZTogbG91aXNsYW0vdXB0aW1lLWt1bWE6MQogICAgdm9sdW1lczoKICAgICAgLSB1cHRpbWUta3VtYTovYXBwL2RhdGEK" - }, - "uptime-kuma-with-database": { - "documentation": "https://github.com/louislam/uptime-kuma", - "compose": "c2VydmljZXM6CiAgdXB0aW1lLWt1bWE6CiAgICBpbWFnZTogbG91aXNsYW0vdXB0aW1lLWt1bWE6MQogICAgdm9sdW1lczoKICAgICAgLSB1cHRpbWUta3VtYTovYXBwL2RhdGEK" } } diff --git a/resources/views/emails/updates.blade.php b/resources/views/emails/updates.blade.php new file mode 100644 index 000000000..e038b5cbc --- /dev/null +++ b/resources/views/emails/updates.blade.php @@ -0,0 +1,5 @@ + + +

+If you do not like to receive these emails, you can unsubscribe [here]({{$unsubscribeUrl}}). +
diff --git a/routes/api.php b/routes/api.php index 1bac5f6b2..90507a496 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,5 +1,6 @@ group(function () { + Route::get('/unsubscribe/{token}', function() { + try { + $token = request()->token; + $email = decrypt($token); + if (!User::whereEmail($email)->exists()) { + return redirect('/'); + } + if (User::whereEmail($email)->first()->marketing_emails === false) { + return 'You have already unsubscribed from marketing emails.'; + } + User::whereEmail($email)->update(['marketing_emails' => false]); + return 'You have been unsubscribed from marketing emails.'; + } catch (\Throwable $e) { + return 'Something went wrong. Please try again or contact support.'; + } + + })->name('unsubscribe.marketing.emails'); +});