From f3e500da68d2c50b22b8d5e5356249f59cfb8a5f Mon Sep 17 00:00:00 2001 From: Louis Jeckel Date: Thu, 29 Oct 2020 14:05:47 +0100 Subject: [PATCH] Email history --- .idea/lettre-pharma.iml | 1 + .idea/php.xml | 1 + app/Events/DispatchMailgunEvent.php | 20 ++- app/Listeners/LogSentMessage.php | 36 +++++ app/Nova/SentEmail.php | 134 ++++++++++++++++++ app/Nova/User.php | 3 + app/Providers/EventServiceProvider.php | 5 +- app/SentEmail.php | 42 ++++++ app/User.php | 9 +- composer.json | 1 + composer.lock | 45 +++++- ..._10_29_122838_create_sent_emails_table.php | 37 +++++ .../2020_10_29_123449_add_foreign_keys.php | 34 +++++ 13 files changed, 361 insertions(+), 7 deletions(-) create mode 100644 app/Listeners/LogSentMessage.php create mode 100644 app/Nova/SentEmail.php create mode 100644 app/SentEmail.php create mode 100644 database/migrations/2020_10_29_122838_create_sent_emails_table.php create mode 100644 database/migrations/2020_10_29_123449_add_foreign_keys.php diff --git a/.idea/lettre-pharma.iml b/.idea/lettre-pharma.iml index db0d22d..d832340 100644 --- a/.idea/lettre-pharma.iml +++ b/.idea/lettre-pharma.iml @@ -38,6 +38,7 @@ + diff --git a/.idea/php.xml b/.idea/php.xml index c3e55ff..8922dea 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -211,6 +211,7 @@ + diff --git a/app/Events/DispatchMailgunEvent.php b/app/Events/DispatchMailgunEvent.php index 3ef9431..1694eaa 100644 --- a/app/Events/DispatchMailgunEvent.php +++ b/app/Events/DispatchMailgunEvent.php @@ -4,6 +4,7 @@ namespace App\Events; use App\EmailBatch; use App\MailgunEvent; +use App\SentEmail; use App\User; use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\InteractsWithSockets; @@ -37,12 +38,10 @@ class DispatchMailgunEvent implements ShouldBroadcast */ public function __construct($webhookData) { + /** @todo check webhook key */ $tags = Arr::get($webhookData, 'event-data.tags'); - - - - /** @todo check webhook key */ + $this->updateSentEmailStatus($webhookData); $this->batch_id = Str::after(Arr::first($tags, function($tag) { return Str::startsWith($tag, 'batch_id_'); @@ -83,6 +82,19 @@ class DispatchMailgunEvent implements ShouldBroadcast + } + + + /** + * @param $webhookData + */ + protected function updateSentEmailStatus($webhookData) + { + $id = Arr::get($webhookData, 'event-data.message.headers.message-id'); + if($message = SentEmail::query()->where('message_id', $id)->first()) { + $message->update(['status' => Arr::get($webhookData, 'event-data.event')]); + } + } /** diff --git a/app/Listeners/LogSentMessage.php b/app/Listeners/LogSentMessage.php new file mode 100644 index 0000000..7206a11 --- /dev/null +++ b/app/Listeners/LogSentMessage.php @@ -0,0 +1,36 @@ +message); + } catch(\Exception $exception) { + report($exception); + } + } +} diff --git a/app/Nova/SentEmail.php b/app/Nova/SentEmail.php new file mode 100644 index 0000000..00fba0f --- /dev/null +++ b/app/Nova/SentEmail.php @@ -0,0 +1,134 @@ +subject . ' à ' . $this->email; + } + + /** + * Get the fields displayed by the resource. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function fields(Request $request) + { + return [ + BelongsTo::make('Destinataire', 'user', User::class), + Text::make('Objet', 'subject'), + Iframe::make('Contenu', 'content'), + Text::make('Etat', 'status'), + DateTime::make('Envoyé le', 'created_at'), + DateTime::make('Dernier événement', 'updated_at')->onlyOnDetail() + ]; + } + + /** + * Get the cards available for the request. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function cards(Request $request) + { + return []; + } + + /** + * Get the filters available for the resource. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function filters(Request $request) + { + return []; + } + + /** + * Get the lenses available for the resource. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function lenses(Request $request) + { + return []; + } + + /** + * Get the actions available for the resource. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function actions(Request $request) + { + return []; + } +} diff --git a/app/Nova/User.php b/app/Nova/User.php index 829c2be..87d1fe6 100644 --- a/app/Nova/User.php +++ b/app/Nova/User.php @@ -28,6 +28,7 @@ use Laravel\Nova\Fields\Badge; use Laravel\Nova\Fields\BelongsTo; use Laravel\Nova\Fields\Boolean; use Laravel\Nova\Fields\Country; +use Laravel\Nova\Fields\HasMany; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Place; use Laravel\Nova\Fields\Select; @@ -98,6 +99,8 @@ class User extends Resource new Panel('Affiliation', [ BelongsTo::make('Organisation', 'organization', Organization::class)->searchable()->nullable(), ]), + + HasMany::make('Emails envoyés', 'sentEmails', SentEmail::class), ], $this->extraFields(), [ Badge::make('Etat dernier mail', fn() => MailgunEvent::STATUSES[$this->lastMailgunEvent->event ?? 'unknown']['label']) ->map(Arr::pluck(MailgunEvent::STATUSES, 'badge', 'label')), diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index cc03a34..5c2d253 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -27,7 +27,10 @@ class EventServiceProvider extends ServiceProvider ProcessBatch::class => [], PasswordReset::class => [ 'App\Listeners\PasswordResetListener' - ] + ], + \Illuminate\Mail\Events\MessageSending::class => [ + 'App\Listeners\LogSentMessage', + ], ]; /** diff --git a/app/SentEmail.php b/app/SentEmail.php new file mode 100644 index 0000000..e41673d --- /dev/null +++ b/app/SentEmail.php @@ -0,0 +1,42 @@ +create([ + 'message_id' => $message->getId(), + 'subject' => $message->getSubject(), + 'content' => $message->getBody(), + 'recipient' => array_key_first($message->getTo()), + 'status' => 'sent' + ]); + } + + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function user() + { + return $this->belongsTo(User::class, 'recipient', 'email'); + } +} diff --git a/app/User.php b/app/User.php index 8458b83..93d0b82 100644 --- a/app/User.php +++ b/app/User.php @@ -233,7 +233,6 @@ class User extends Authenticatable implements MustVerifyEmail, SendsEmails } - /** * @return HasOne */ @@ -243,6 +242,14 @@ class User extends Authenticatable implements MustVerifyEmail, SendsEmails } + /** + * @return HasMany + */ + public function sentEmails() + { + return $this->hasMany(SentEmail::class, 'recipient', 'email'); + } + /** diff --git a/composer.json b/composer.json index 3e4e85c..1054697 100644 --- a/composer.json +++ b/composer.json @@ -36,6 +36,7 @@ "league/html-to-markdown": "^4.9", "mailgun/mailgun-php": "^3.0", "masterminds/html5": "^2.7", + "metrixinfo/nova-iframe": "^1.0", "numaxlab/nova-ckeditor5-classic": "^1.1", "nyholm/psr7": "^1.2", "psq/psq-theme": "*", diff --git a/composer.lock b/composer.lock index c3ddfae..5873fbf 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ca6ddddface6393f6a339cd2a7233c9b", + "content-hash": "170a4b87161eb1a26074692e0e8292bd", "packages": [ { "name": "algolia/algoliasearch-client-php", @@ -4193,6 +4193,49 @@ ], "time": "2020-03-09T20:17:30+00:00" }, + { + "name": "metrixinfo/nova-iframe", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/metrixinfo/nova-iframe.git", + "reference": "3bbb0a1c4c43af6c5572dc861ad124d8a61e0ddb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/metrixinfo/nova-iframe/zipball/3bbb0a1c4c43af6c5572dc861ad124d8a61e0ddb", + "reference": "3bbb0a1c4c43af6c5572dc861ad124d8a61e0ddb", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Metrixinfo\\Nova\\Fields\\Iframe\\FieldServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Metrixinfo\\Nova\\Fields\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A Laravel Nova field.", + "keywords": [ + "field", + "iframe", + "laravel", + "nova" + ], + "time": "2019-01-19T20:24:59+00:00" + }, { "name": "microsoft/azure-storage-blob", "version": "1.5.1", diff --git a/database/migrations/2020_10_29_122838_create_sent_emails_table.php b/database/migrations/2020_10_29_122838_create_sent_emails_table.php new file mode 100644 index 0000000..d34d0bf --- /dev/null +++ b/database/migrations/2020_10_29_122838_create_sent_emails_table.php @@ -0,0 +1,37 @@ +id(); + $table->text('message_id'); + $table->string('subject'); + $table->text('content'); + $table->string('recipient'); + $table->string('status')->nullable(); + $table->timestamps(); + $table->foreign('recipient')->references('email')->on('users'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('sent_emails'); + } +} diff --git a/database/migrations/2020_10_29_123449_add_foreign_keys.php b/database/migrations/2020_10_29_123449_add_foreign_keys.php new file mode 100644 index 0000000..5154472 --- /dev/null +++ b/database/migrations/2020_10_29_123449_add_foreign_keys.php @@ -0,0 +1,34 @@ +foreign('user_id')->references('id')->on('users'); + }); + + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('unlocked_articles_table', function(Blueprint $table) { + $table->dropForeign('user_id'); + }); + } +} -- 2.39.5