Skip to content

Commit

Permalink
Merge pull request #16 from mailcarrierapp/feat/multiple-cc-bcc
Browse files Browse the repository at this point in the history
Allow multiple CCs and BCCs
  • Loading branch information
danilopolani authored Oct 30, 2023
2 parents 00033e4 + cae7d44 commit 27a034f
Show file tree
Hide file tree
Showing 14 changed files with 411 additions and 83 deletions.
45 changes: 45 additions & 0 deletions database/migrations/6_transform_logs_cc_bcc_array.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use MailCarrier\Models\Log;

return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
$tableName = (new Log())->getTable();

DB::table($tableName)
->whereNotNull('cc')
->orWhereNotNull('bcc')
->orderBy('id')
->each(function (object $log) use ($tableName) {
$changes = [];

if (!is_null($log->cc)) {
$changes['cc'] = [json_decode($log->cc, true)];
}

if (!is_null($log->bcc)) {
$changes['bcc'] = [json_decode($log->bcc, true)];
}

if (!empty($changes)) {
DB::table($tableName)
->where('id', $log->id)
->update($changes);
}
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};
10 changes: 6 additions & 4 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" executionOrder="random" failOnWarning="true" failOnRisky="true" failOnEmptyTestSuite="true" beStrictAboutOutputDuringTests="true" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" executionOrder="random" failOnWarning="true" failOnRisky="true" failOnEmptyTestSuite="true" beStrictAboutOutputDuringTests="true" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
<testsuites>
<testsuite name="MailCarrier Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<coverage>
<include>
<directory suffix=".php">./src</directory>
</include>
<report>
<html outputDirectory="build/coverage"/>
<text outputFile="build/coverage.txt"/>
Expand All @@ -22,4 +19,9 @@
<env name="APP_ENV" value="testing"/>
<env name="APP_KEY" value="base64:yk+bUVuZa1p86Dqjk9OjVK2R1pm6XHxC6xEKFq8utH0="/>
</php>
<source>
<include>
<directory suffix=".php">./src</directory>
</include>
</source>
</phpunit>
24 changes: 14 additions & 10 deletions resources/views/modals/details.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,26 @@
@if ($log->cc)
<div>
<p class="font-bold mb-1">Cc</p>
@if ($log->cc->name)
<p>{{ $log->cc->name }} &lt;{{ $log->cc->email }}&gt;</p>
@else
<p>{{ $log->cc->email }}</p>
@endif
@foreach ($log->cc as $cc)
@if ($cc->name)
<p>{{ $cc->name }} &lt;{{ $cc->email }}&gt;</p>
@else
<p>{{ $cc->email }}</p>
@endif
@endforeach
</div>
@endif

@if ($log->bcc)
<div>
<p class="font-bold mb-1">Bcc</p>
@if ($log->bcc->name)
<p>{{ $log->bcc->name }} &lt;{{ $log->bcc->email }}&gt;</p>
@else
<p>{{ $log->bcc->email }}</p>
@endif
@foreach ($log->bcc as $bcc)
@if ($bcc->name)
<p>{{ $bcc->name }} &lt;{{ $bcc->email }}&gt;</p>
@else
<p>{{ $bcc->email }}</p>
@endif
@endforeach
</div>
@endif

Expand Down
49 changes: 49 additions & 0 deletions src/Dto/Casters/ContactArrayCaster.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace MailCarrier\Dto\Casters;

use Illuminate\Support\Collection;
use MailCarrier\Dto\ContactDto;
use Spatie\DataTransferObject\Caster;

class ContactArrayCaster implements Caster
{
public function cast(mixed $value): ?array
{
if (is_null($value)) {
return null;
}

if ($value instanceof ContactDto) {
return [$value];
}

if (!is_array($value)) {
$value = [
'email' => $value,
];
}

if (Collection::make($value)->every(fn (mixed $value) => $value instanceof ContactDto)) {
return $value;
}

if (is_array($value) && array_is_list($value) && is_string($value[0])) {
$value = array_map(
fn (string $item) => [
'email' => $item,
],
$value
);
}

if (!array_is_list($value)) {
$value = [$value];
}

return array_map(
fn (array $item) => new ContactDto($item),
$value
);
}
}
6 changes: 4 additions & 2 deletions src/Dto/GenericMailDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ class GenericMailDto extends DataTransferObject

public ?ContactDto $sender;

public ?ContactDto $cc;
/** @var \MailCarrier\Dto\ContactDto[]|null */
public ?array $cc;

public ?ContactDto $bcc;
/** @var \MailCarrier\Dto\ContactDto[]|null */
public ?array $bcc;

public Template $template;

Expand Down
12 changes: 7 additions & 5 deletions src/Dto/RecipientDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace MailCarrier\Dto;

use MailCarrier\Dto\Casters\ContactStringCaster;
use MailCarrier\Dto\Casters\ContactArrayCaster;
use MailCarrier\Dto\Validators\Email;
use Spatie\DataTransferObject\Attributes\CastWith;
use Spatie\DataTransferObject\Casters\ArrayCaster;
Expand All @@ -16,11 +16,13 @@ class RecipientDto extends DataTransferObject
/** @var array<string, mixed> */
public array $variables = [];

#[CastWith(ContactStringCaster::class)]
public ?ContactDto $cc;
/** @var \MailCarrier\Dto\ContactDto[]|null */
#[CastWith(ContactArrayCaster::class)]
public ?array $cc;

#[CastWith(ContactStringCaster::class)]
public ?ContactDto $bcc;
/** @var \MailCarrier\Dto\ContactDto[]|null */
#[CastWith(ContactArrayCaster::class)]
public ?array $bcc;

/** @var \Illuminate\Http\UploadedFile[] */
public array $attachments = [];
Expand Down
11 changes: 7 additions & 4 deletions src/Dto/SendMailDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace MailCarrier\Dto;

use MailCarrier\Dto\Casters\ContactArrayCaster;
use MailCarrier\Dto\Casters\ContactStringCaster;
use Spatie\DataTransferObject\Attributes\CastWith;
use Spatie\DataTransferObject\Casters\ArrayCaster;
Expand All @@ -20,11 +21,13 @@ class SendMailDto extends DataTransferObject

public ?string $recipient;

#[CastWith(ContactStringCaster::class)]
public ?ContactDto $cc;
/** @var \MailCarrier\Dto\ContactDto[]|null */
#[CastWith(ContactArrayCaster::class)]
public ?array $cc;

#[CastWith(ContactStringCaster::class)]
public ?ContactDto $bcc;
/** @var \MailCarrier\Dto\ContactDto[]|null */
#[CastWith(ContactArrayCaster::class)]
public ?array $bcc;

/** @var array<string, mixed> */
public array $variables = [];
Expand Down
57 changes: 53 additions & 4 deletions src/Http/Requests/SendMailRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ public function rules(): array
'trigger' => 'sometimes|string|max:255',
'subject' => 'required|string|max:255',
'sender' => ['sometimes', new ContactRule()],
'cc' => ['sometimes', new ContactRule()],
'bcc' => ['sometimes', new ContactRule()],
'cc' => 'sometimes|array',
'bcc' => 'sometimes|array',
'cc.*' => [new ContactRule()],
'bcc.*' => [new ContactRule()],
'variables' => 'sometimes|array',
'tags' => 'sometimes|array',
'metadata' => 'sometimes|array',
Expand Down Expand Up @@ -65,8 +67,10 @@ public function rules(): array
Rule::when($this->has('recipients') && is_array($this->json('recipients.0')), 'required|email'),
],
'recipients.*.variables' => 'sometimes|array',
'recipients.*.cc' => ['sometimes', new ContactRule()],
'recipients.*.bcc' => ['sometimes', new ContactRule()],
'recipients.*.cc' => 'sometimes|array',
'recipients.*.cc.*' => [new ContactRule()],
'recipients.*.bcc' => 'sometimes|array',
'recipients.*.bcc.*' => [new ContactRule()],

// Recipients attachments
'recipients.*.attachments' => 'sometimes|array',
Expand Down Expand Up @@ -106,6 +110,26 @@ protected function prepareForValidation(): void
]);
}

// Wrap cc array list
if (
!is_null($this->input('cc'))
&& (!is_array($this->input('cc')) || !array_is_list($this->input('cc')))
) {
$this->merge([
'cc' => [$this->input('cc')],
]);
}

// Wrap bcc array list
if (
!is_null($this->input('bcc'))
&& (!is_array($this->input('bcc')) || !array_is_list($this->input('bcc')))
) {
$this->merge([
'bcc' => [$this->input('bcc')],
]);
}

// Wrap recipient array list into a structured data
if (is_array($this->input('recipients')) && !is_array($this->json('recipients.0'))) {
$this->merge([
Expand All @@ -118,6 +142,31 @@ protected function prepareForValidation(): void
]);
}

// Wrap recipient cc and bcc
$recipients = $this->input('recipients');

if (is_array($recipients)) {
foreach ($recipients as $i => $recipient) {
if (
array_key_exists('cc', $recipient)
&& (!is_array($this->input('cc')) || !array_is_list($this->input('cc')))
) {
$recipients[$i]['cc'] = [$recipient['cc']];
}

if (
array_key_exists('bcc', $recipient)
&& (!is_array($this->input('bcc')) || !array_is_list($this->input('bcc')))
) {
$recipients[$i]['bcc'] = [$recipient['bcc']];
}
}

$this->merge([
'recipients' => $recipients,
]);
}

// Wrap remote attachments array list into a structured data
if (is_array($this->input('remoteAttachments')) && !is_array($this->json('remoteAttachments.0'))) {
$this->merge([
Expand Down
4 changes: 2 additions & 2 deletions src/Mail/GenericMail.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ public function build(): self
)
->when(
$this->params->cc,
fn (GenericMail $mail) => $mail->cc($this->params->cc->email, $this->params->cc->name)
fn (GenericMail $mail) => $mail->cc($this->params->cc)
)
->when(
$this->params->bcc,
fn (GenericMail $mail) => $mail->bcc($this->params->bcc->email, $this->params->bcc->name)
fn (GenericMail $mail) => $mail->bcc($this->params->bcc)
);
}

Expand Down
1 change: 1 addition & 0 deletions src/MailCarrierServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public function packageConfigured(Package $package): void
'3_create_templates_table',
'4_create_logs_table',
'5_create_attachments_table',
'6_transform_logs_cc_bcc_array',
])
->runsMigrations();

Expand Down
37 changes: 37 additions & 0 deletions src/Models/Casts/CollectionOfContacts.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace MailCarrier\Models\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use MailCarrier\Dto\ContactDto;

class CollectionOfContacts implements CastsAttributes
{
/**
* Cast the given value.
*
* @param array<string, mixed> $attributes
* @return \Illuminate\Support\Collection<\MailCarrier\Dto\ContactDto>|null
*/
public function get(Model $model, string $key, mixed $value, array $attributes): ?Collection
{
if (is_null($value)) {
return null;
}

return Collection::make(json_decode($value, true))
->map(fn (array $value) => new ContactDto($value));
}

/**
* Prepare the given value for storage.
*
* @param array<string, mixed> $attributes
*/
public function set(Model $model, string $key, mixed $value, array $attributes): string
{
return json_encode($value);
}
}
Loading

0 comments on commit 27a034f

Please sign in to comment.