Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php

namespace HiEvents\DomainObjects\Generated;

/**
* THIS FILE IS AUTOGENERATED - DO NOT EDIT IT DIRECTLY.
* @package HiEvents\DomainObjects\Generated
*/
abstract class OutgoingMessageDomainObjectAbstract extends \HiEvents\DomainObjects\AbstractDomainObject
{
final public const SINGULAR_NAME = 'outgoing_message';
final public const PLURAL_NAME = 'outgoing_messages';
final public const ID = 'id';
final public const EVENT_ID = 'event_id';
final public const MESSAGE_ID = 'message_id';
final public const SUBJECT = 'subject';
final public const RECIPIENT = 'recipient';
final public const STATUS = 'status';
final public const CREATED_AT = 'created_at';
final public const UPDATED_AT = 'updated_at';
final public const DELETED_AT = 'deleted_at';

protected int $id;
protected int $event_id;
protected int $message_id;
protected string $subject;
protected string $recipient;
protected string $status;
protected ?string $created_at = null;
protected ?string $updated_at = null;
protected ?string $deleted_at = null;

public function toArray(): array
{
return [
'id' => $this->id ?? null,
'event_id' => $this->event_id ?? null,
'message_id' => $this->message_id ?? null,
'subject' => $this->subject ?? null,
'recipient' => $this->recipient ?? null,
'status' => $this->status ?? null,
'created_at' => $this->created_at ?? null,
'updated_at' => $this->updated_at ?? null,
'deleted_at' => $this->deleted_at ?? null,
];
}

public function setId(int $id): self
{
$this->id = $id;
return $this;
}

public function getId(): int
{
return $this->id;
}

public function setEventId(int $event_id): self
{
$this->event_id = $event_id;
return $this;
}

public function getEventId(): int
{
return $this->event_id;
}

public function setMessageId(int $message_id): self
{
$this->message_id = $message_id;
return $this;
}

public function getMessageId(): int
{
return $this->message_id;
}

public function setSubject(string $subject): self
{
$this->subject = $subject;
return $this;
}

public function getSubject(): string
{
return $this->subject;
}

public function setRecipient(string $recipient): self
{
$this->recipient = $recipient;
return $this;
}

public function getRecipient(): string
{
return $this->recipient;
}

public function setStatus(string $status): self
{
$this->status = $status;
return $this;
}

public function getStatus(): string
{
return $this->status;
}

public function setCreatedAt(?string $created_at): self
{
$this->created_at = $created_at;
return $this;
}

public function getCreatedAt(): ?string
{
return $this->created_at;
}

public function setUpdatedAt(?string $updated_at): self
{
$this->updated_at = $updated_at;
return $this;
}

public function getUpdatedAt(): ?string
{
return $this->updated_at;
}

public function setDeletedAt(?string $deleted_at): self
{
$this->deleted_at = $deleted_at;
return $this;
}

public function getDeletedAt(): ?string
{
return $this->deleted_at;
}
}
7 changes: 7 additions & 0 deletions backend/app/DomainObjects/OutgoingMessageDomainObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace HiEvents\DomainObjects;

class OutgoingMessageDomainObject extends Generated\OutgoingMessageDomainObjectAbstract
{
}
9 changes: 9 additions & 0 deletions backend/app/DomainObjects/Status/OutgoingMessageStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace HiEvents\DomainObjects\Status;

enum OutgoingMessageStatus
{
case SENT;
case FAILED;
}
72 changes: 72 additions & 0 deletions backend/app/Jobs/Event/SendEventEmailJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace HiEvents\Jobs\Event;

use HiEvents\DomainObjects\Generated\OutgoingMessageDomainObjectAbstract;
use HiEvents\DomainObjects\Status\OutgoingMessageStatus;
use HiEvents\Mail\Event\EventMessage;
use HiEvents\Providers\AppServiceProvider;
use HiEvents\Repository\Interfaces\OutgoingMessageRepositoryInterface;
use HiEvents\Services\Application\Handlers\Message\DTO\SendMessageDTO;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Mail\Mailer;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\RateLimited;
use Illuminate\Queue\SerializesModels;
use Throwable;

class SendEventEmailJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

public function __construct(
private readonly string $email,
private readonly string $toName,
private readonly EventMessage $eventMessage,
private readonly SendMessageDTO $messageData,
)
{
}

public function middleware(): array
{
return [
(new RateLimited(AppServiceProvider::MAIL_RATE_LIMIT_PER_SECOND)),
];
}

/**
* @throws Throwable
*/
public function handle(
Mailer $mailer,
OutgoingMessageRepositoryInterface $outgoingMessageRepository,
): void
{
try {
$mailer
->to($this->email, $this->toName)
->send($this->eventMessage);
} catch (Throwable $exception) {
$outgoingMessageRepository->create([
OutgoingMessageDomainObjectAbstract::MESSAGE_ID => $this->messageData->id,
OutgoingMessageDomainObjectAbstract::EVENT_ID => $this->messageData->event_id,
OutgoingMessageDomainObjectAbstract::STATUS => OutgoingMessageStatus::FAILED->name,
OutgoingMessageDomainObjectAbstract::RECIPIENT => $this->email,
OutgoingMessageDomainObjectAbstract::SUBJECT => $this->messageData->subject,
]);

throw $exception;
}

$outgoingMessageRepository->create([
OutgoingMessageDomainObjectAbstract::MESSAGE_ID => $this->messageData->id,
OutgoingMessageDomainObjectAbstract::EVENT_ID => $this->messageData->event_id,
OutgoingMessageDomainObjectAbstract::STATUS => OutgoingMessageStatus::SENT->name,
OutgoingMessageDomainObjectAbstract::RECIPIENT => $this->email,
OutgoingMessageDomainObjectAbstract::SUBJECT => $this->messageData->subject,
]);
}
}
7 changes: 6 additions & 1 deletion backend/app/Models/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace HiEvents\Models;

use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;

Expand All @@ -14,6 +15,11 @@ public function sent_by_user(): HasOne
return $this->hasOne(User::class, 'id', 'sent_by_user_id');
}

public function outgoing_messages(): HasMany
{
return $this->hasMany(OutgoingMessage::class);
}

protected function getCastMap(): array
{
return [
Expand All @@ -22,5 +28,4 @@ protected function getCastMap(): array
'send_data' => 'array',
];
}

}
10 changes: 10 additions & 0 deletions backend/app/Models/OutgoingMessage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace HiEvents\Models;

use Illuminate\Database\Eloquent\SoftDeletes;

class OutgoingMessage extends BaseModel
{
use SoftDeletes;
}
78 changes: 59 additions & 19 deletions backend/app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,21 @@
use HiEvents\DomainObjects\OrganizerDomainObject;
use HiEvents\Models\Event;
use HiEvents\Models\Organizer;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;
use Stripe\StripeClient;

class AppServiceProvider extends ServiceProvider
{
public const MAIL_RATE_LIMIT_PER_SECOND = 'mail-rate-limit-per-second';

public function register(): void
{
$this->bindDoctrineConnection();
Expand All @@ -30,28 +35,25 @@ public function register(): void
*/
public function boot(): void
{
if ($this->app->environment('local')) {
URL::forceScheme('https');
URL::forceRootUrl(config('app.url'));
}
$this->handleHttpsEnforcing();

if (env('APP_DEBUG') === true && env('APP_LOG_QUERIES') === true && !app()->isProduction()) {
DB::listen(
static function ($query) {
File::append(
storage_path('/logs/query.log'),
$query->sql . ' [' . implode(', ', $query->bindings) . ']' . PHP_EOL
);
}
);
}
$this->handleQueryLogging();

Model::preventLazyLoading(!app()->isProduction());
$this->disableLazyLoading();

Relation::enforceMorphMap([
EventDomainObject::class => Event::class,
OrganizerDomainObject::class => Organizer::class,
]);
$this->registerMorphMaps();

$this->registerJobRateLimiters();
}

private function registerJobRateLimiters(): void
{
RateLimiter::for(
name: self::MAIL_RATE_LIMIT_PER_SECOND,
callback: static fn(ShouldQueue $job) => Limit::perMinute(
maxAttempts: config('mail.rate_limit_per_second')
)
);
}

private function bindDoctrineConnection(): void
Expand Down Expand Up @@ -90,4 +92,42 @@ private function bindStripeClient(): void
fn() => new StripeClient(config('services.stripe.secret_key'))
);
}

/**
* @return void
*/
private function handleQueryLogging(): void
{
if (env('APP_DEBUG') === true && env('APP_LOG_QUERIES') === true && !app()->isProduction()) {
DB::listen(
static function ($query) {
File::append(
storage_path('/logs/query.log'),
$query->sql . ' [' . implode(', ', $query->bindings) . ']' . PHP_EOL
);
}
);
}
}

private function handleHttpsEnforcing(): void
{
if ($this->app->environment('local')) {
URL::forceScheme('https');
URL::forceRootUrl(config('app.url'));
}
}

private function registerMorphMaps(): void
{
Relation::enforceMorphMap([
EventDomainObject::class => Event::class,
OrganizerDomainObject::class => Organizer::class,
]);
}

private function disableLazyLoading(): void
{
Model::preventLazyLoading(!app()->isProduction());
}
}
Loading
Loading