cloud: marketing emails

This commit is contained in:
Andras Bacsai
2023-09-25 20:57:52 +02:00
parent cbf9bc99ea
commit a4320b7cee
8 changed files with 118 additions and 23 deletions

View File

@@ -56,6 +56,7 @@ class Emails extends Command
$type = select( $type = select(
'Which Email should be sent?', 'Which Email should be sent?',
options: [ options: [
'updates' => 'Send Update Email to all users',
'emails-test' => 'Test', 'emails-test' => 'Test',
'application-deployment-success' => 'Application - Deployment Success', 'application-deployment-success' => 'Application - Deployment Success',
'application-deployment-failed' => 'Application - Deployment Failed', 'application-deployment-failed' => 'Application - Deployment Failed',
@@ -69,7 +70,7 @@ class Emails extends Command
'realusers-server-lost-connection' => 'REAL - Server Lost Connection', '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)) { if (!in_array($type, $emailsGathered)) {
$this->email = text('Email Address to send to'); $this->email = text('Email Address to send to');
} }
@@ -78,6 +79,38 @@ class Emails extends Command
$this->mail = new MailMessage(); $this->mail = new MailMessage();
$this->mail->subject("Test Email"); $this->mail->subject("Test Email");
switch ($type) { 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': case 'emails-test':
$this->mail = (new Test())->toMail(); $this->mail = (new Test())->toMail();
$this->sendEmail(); $this->sendEmail();
@@ -141,20 +174,20 @@ class Emails extends Command
$this->mail = (new BackupSuccess($backup, $db))->toMail(); $this->mail = (new BackupSuccess($backup, $db))->toMail();
$this->sendEmail(); $this->sendEmail();
break; break;
// case 'invitation-link': // case 'invitation-link':
// $user = User::all()->first(); // $user = User::all()->first();
// $invitation = TeamInvitation::whereEmail($user->email)->first(); // $invitation = TeamInvitation::whereEmail($user->email)->first();
// if (!$invitation) { // if (!$invitation) {
// $invitation = TeamInvitation::create([ // $invitation = TeamInvitation::create([
// 'uuid' => Str::uuid(), // 'uuid' => Str::uuid(),
// 'email' => $user->email, // 'email' => $user->email,
// 'team_id' => 1, // 'team_id' => 1,
// 'link' => 'http://example.com', // 'link' => 'http://example.com',
// ]); // ]);
// } // }
// $this->mail = (new InvitationLink($user))->toMail(); // $this->mail = (new InvitationLink($user))->toMail();
// $this->sendEmail(); // $this->sendEmail();
// break; // break;
case 'waitlist-invitation-link': case 'waitlist-invitation-link':
$this->mail = new MailMessage(); $this->mail = new MailMessage();
$this->mail->view('emails.waitlist-invitation', [ $this->mail->view('emails.waitlist-invitation', [

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\EnvironmentVariable;
use App\Models\Project; use App\Models\Project;
use App\Models\Server; use App\Models\Server;
use App\Models\Service; use App\Models\Service;
@@ -68,6 +69,7 @@ class ProjectController extends Controller
if ($type->startsWith('one-click-service-')) { if ($type->startsWith('one-click-service-')) {
$oneClickServiceName = $type->after('one-click-service-')->value(); $oneClickServiceName = $type->after('one-click-service-')->value();
$oneClickService = data_get($services, "$oneClickServiceName.compose"); $oneClickService = data_get($services, "$oneClickServiceName.compose");
$oneClickDotEnvs = collect(data_get($services, "$oneClickServiceName.envs", []));
if ($oneClickService) { if ($oneClickService) {
$service = Service::create([ $service = Service::create([
'name' => "$oneClickServiceName-" . Str::random(10), 'name' => "$oneClickServiceName-" . Str::random(10),
@@ -75,7 +77,17 @@ class ProjectController extends Controller
'environment_id' => $environment->id, 'environment_id' => $environment->id,
'server_id' => (int) $server_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); $service->parse(isNew: true);
return redirect()->route('project.service', [ return redirect()->route('project.service', [

View File

@@ -2,9 +2,6 @@
namespace App\Notifications; namespace App\Notifications;
use App\Notifications\Channels\DiscordChannel;
use App\Notifications\Channels\EmailChannel;
use App\Notifications\Channels\TelegramChannel;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;

View File

@@ -50,5 +50,8 @@ class RouteServiceProvider extends ServiceProvider
} }
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()); 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());
});
} }
} }

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('marketing_emails')->default(true);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('marketing_emails');
});
}
};

View File

@@ -6,9 +6,5 @@
"uptime-kuma": { "uptime-kuma": {
"documentation": "https://github.com/louislam/uptime-kuma", "documentation": "https://github.com/louislam/uptime-kuma",
"compose": "c2VydmljZXM6CiAgdXB0aW1lLWt1bWE6CiAgICBpbWFnZTogbG91aXNsYW0vdXB0aW1lLWt1bWE6MQogICAgdm9sdW1lczoKICAgICAgLSB1cHRpbWUta3VtYTovYXBwL2RhdGEK" "compose": "c2VydmljZXM6CiAgdXB0aW1lLWt1bWE6CiAgICBpbWFnZTogbG91aXNsYW0vdXB0aW1lLWt1bWE6MQogICAgdm9sdW1lczoKICAgICAgLSB1cHRpbWUta3VtYTovYXBwL2RhdGEK"
},
"uptime-kuma-with-database": {
"documentation": "https://github.com/louislam/uptime-kuma",
"compose": "c2VydmljZXM6CiAgdXB0aW1lLWt1bWE6CiAgICBpbWFnZTogbG91aXNsYW0vdXB0aW1lLWt1bWE6MQogICAgdm9sdW1lczoKICAgICAgLSB1cHRpbWUta3VtYTovYXBwL2RhdGEK"
} }
} }

View File

@@ -0,0 +1,5 @@
<x-emails.layout>
<br><br>
If you do not like to receive these emails, you can unsubscribe [here]({{$unsubscribeUrl}}).
</x-emails.layout>

View File

@@ -1,5 +1,6 @@
<?php <?php
use App\Models\User;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
/* /*
@@ -16,3 +17,23 @@ use Illuminate\Support\Facades\Route;
Route::get('/health', function () { Route::get('/health', function () {
return 'OK'; return 'OK';
}); });
Route::middleware(['throttle:5'])->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');
});