diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php index 15d8b419..587c599f 100644 --- a/app/Providers/Filament/AdminPanelProvider.php +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -21,6 +21,7 @@ use Illuminate\Session\Middleware\StartSession; use Illuminate\Support\Facades\Blade; use Illuminate\View\Middleware\ShareErrorsFromSession; +use Vormkracht10\FilamentMails\FilamentMailsPlugin; final class AdminPanelProvider extends PanelProvider { @@ -51,6 +52,7 @@ public function panel(Panel $panel): Panel ->plugins([ SpatieLaravelTranslatablePlugin::make() ->defaultLocales(['fr', 'en']), + FilamentMailsPlugin::make(), ]) ->renderHook( 'body.start', diff --git a/composer.json b/composer.json index 3d551980..1128de76 100644 --- a/composer.json +++ b/composer.json @@ -46,6 +46,7 @@ "symfony/http-client": "^7.1.8", "symfony/mailgun-mailer": "^7.1", "torchlight/torchlight-laravel": "^0.6", + "vormkracht10/filament-mails": "^1.0", "wire-elements/modal": "^2.0", "wire-elements/spotlight": "^2.0", "yarri/link-finder": "^2.7.10", diff --git a/composer.lock b/composer.lock index 2f13f04e..9248b5bb 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": "231723be1478153245cd48c8cc81d53a", + "content-hash": "255123bf274b713735b09291084080af", "packages": [ { "name": "abraham/twitteroauth", @@ -4416,6 +4416,74 @@ }, "time": "2017-11-25T19:51:26+00:00" }, + { + "name": "laravel-notification-channels/discord", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/laravel-notification-channels/discord.git", + "reference": "317117f22c6c2b9a4f78976f097c3082e40902da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel-notification-channels/discord/zipball/317117f22c6c2b9a4f78976f097c3082e40902da", + "reference": "317117f22c6c2b9a4f78976f097c3082e40902da", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/guzzle": "^6.3 || ^7.0", + "illuminate/console": "^7.0 || ^8.0 || ^9.0 || ^10.0|^11.0", + "illuminate/notifications": "^7.0 || ^8.0 || ^9.0 || ^10.0|^11.0", + "illuminate/queue": "^7.0 || ^8.0 || ^9.0 || ^10.0|^11.0", + "illuminate/support": "^7.0 || ^8.0 || ^9.0 || ^10.0|^11.0", + "php": "^7.2|^8.0", + "textalk/websocket": "^1.2" + }, + "require-dev": { + "mockery/mockery": "^1.3.3", + "orchestra/testbench": "^6.0 || ^7.0 || ^8.0|^9.0", + "phpunit/phpunit": "^8.5 || ^9.0|^10.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NotificationChannels\\Discord\\DiscordServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "NotificationChannels\\Discord\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Cody Scott", + "email": "cs475x@icloud.com", + "role": "Developer" + } + ], + "description": "Laravel notification driver for Discord.", + "homepage": "https://github.com/laravel-notification-channels/discord", + "keywords": [ + "channel", + "discord", + "driver", + "laravel", + "notification" + ], + "support": { + "issues": "https://github.com/laravel-notification-channels/discord/issues", + "source": "https://github.com/laravel-notification-channels/discord/tree/v1.6.0" + }, + "time": "2024-04-01T01:31:08+00:00" + }, { "name": "laravel-notification-channels/telegram", "version": "5.0.0", @@ -4765,6 +4833,63 @@ }, "time": "2024-12-17T22:32:08+00:00" }, + { + "name": "laravel/helpers", + "version": "v1.7.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/helpers.git", + "reference": "f28907033d7edf8a0525cfb781ab30ce6d531c35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/helpers/zipball/f28907033d7edf8a0525cfb781ab30ce6d531c35", + "reference": "f28907033d7edf8a0525cfb781ab30ce6d531c35", + "shasum": "" + }, + "require": { + "illuminate/support": "~5.8.0|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", + "php": "^7.2.0|^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^7.0|^8.0|^9.0|^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Dries Vints", + "email": "dries@laravel.com" + } + ], + "description": "Provides backwards compatibility for helpers in the latest Laravel release.", + "keywords": [ + "helpers", + "laravel" + ], + "support": { + "source": "https://github.com/laravel/helpers/tree/v1.7.1" + }, + "time": "2024-11-26T14:56:25+00:00" + }, { "name": "laravel/prompts", "version": "v0.3.2", @@ -4949,6 +5074,71 @@ }, "time": "2024-12-16T15:26:28+00:00" }, + { + "name": "laravel/slack-notification-channel", + "version": "v3.4.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/slack-notification-channel.git", + "reference": "282d52d70195283eb1b92e59d7bdc2d525361f4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/slack-notification-channel/zipball/282d52d70195283eb1b92e59d7bdc2d525361f4b", + "reference": "282d52d70195283eb1b92e59d7bdc2d525361f4b", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^7.0", + "illuminate/http": "^9.0|^10.0|^11.0", + "illuminate/notifications": "^9.0|^10.0|^11.0", + "illuminate/support": "^9.0|^10.0|^11.0", + "php": "^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "orchestra/testbench": "^7.0|^8.0|^9.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.0|^10.4" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Illuminate\\Notifications\\SlackChannelServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Notifications\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Slack Notification Channel for laravel.", + "keywords": [ + "laravel", + "notifications", + "slack" + ], + "support": { + "issues": "https://github.com/laravel/slack-notification-channel/issues", + "source": "https://github.com/laravel/slack-notification-channel/tree/v3.4.2" + }, + "time": "2024-11-29T14:59:32+00:00" + }, { "name": "laravel/socialite", "version": "v5.16.1", @@ -13314,6 +13504,55 @@ ], "time": "2024-11-08T15:48:14+00:00" }, + { + "name": "textalk/websocket", + "version": "1.5.8", + "source": { + "type": "git", + "url": "https://github.com/Textalk/websocket-php.git", + "reference": "d05dbaa97500176447ffb1f1800573f23085ab13" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Textalk/websocket-php/zipball/d05dbaa97500176447ffb1f1800573f23085ab13", + "reference": "d05dbaa97500176447ffb1f1800573f23085ab13", + "shasum": "" + }, + "require": { + "php": "^7.2 | ^8.0", + "psr/log": "^1 | ^2 | ^3" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.0", + "phpunit/phpunit": "^8.0|^9.0", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "WebSocket\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Fredrik Liljegren" + }, + { + "name": "Sören Jensen", + "email": "soren@abicart.se" + } + ], + "description": "WebSocket client and server", + "support": { + "issues": "https://github.com/Textalk/websocket-php/issues", + "source": "https://github.com/Textalk/websocket-php/tree/1.5.8" + }, + "time": "2022-04-26T06:28:24+00:00" + }, { "name": "tijsverkoyen/css-to-inline-styles", "version": "v2.3.0", @@ -13592,6 +13831,164 @@ ], "time": "2024-11-21T01:49:47+00:00" }, + { + "name": "vormkracht10/filament-mails", + "version": "v1.0.5", + "source": { + "type": "git", + "url": "https://github.com/vormkracht10/filament-mails.git", + "reference": "ab13d2b90daad93943248f7888808f78a2ab6d09" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vormkracht10/filament-mails/zipball/ab13d2b90daad93943248f7888808f78a2ab6d09", + "reference": "ab13d2b90daad93943248f7888808f78a2ab6d09", + "shasum": "" + }, + "require": { + "filament/filament": "^3.0", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.15.0", + "vormkracht10/laravel-mails": "^1.0" + }, + "require-dev": { + "laravel/pint": "^1.0", + "nunomaduro/collision": "^7.9", + "nunomaduro/larastan": "^2.0.1", + "orchestra/testbench": "^8.0", + "pestphp/pest": "^2.1", + "pestphp/pest-plugin-arch": "^2.0", + "pestphp/pest-plugin-laravel": "^2.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.0" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "FilamentMails": "Vormkracht10\\FilamentMails\\Facades\\FilamentMails" + }, + "providers": [ + "Vormkracht10\\FilamentMails\\FilamentMailsServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Vormkracht10\\FilamentMails\\": "src/", + "Vormkracht10\\FilamentMails\\Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Baspa", + "email": "hello@baspa.dev", + "role": "Developer" + } + ], + "description": "View logged mails and events in a beautiful Filament UI.", + "homepage": "https://github.com/vormkracht10/filament-mails", + "keywords": [ + "filament-mails", + "laravel", + "vormkracht10" + ], + "support": { + "issues": "https://github.com/vormkracht10/filament-mails/issues", + "source": "https://github.com/vormkracht10/filament-mails" + }, + "funding": [ + { + "url": "https://github.com/vormkracht10", + "type": "github" + } + ], + "time": "2024-12-27T09:22:16+00:00" + }, + { + "name": "vormkracht10/laravel-mails", + "version": "v1.0.5", + "source": { + "type": "git", + "url": "https://github.com/vormkracht10/laravel-mails.git", + "reference": "d18af5c155a89ae5698b8a289a4b17db0db5cf4a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vormkracht10/laravel-mails/zipball/d18af5c155a89ae5698b8a289a4b17db0db5cf4a", + "reference": "d18af5c155a89ae5698b8a289a4b17db0db5cf4a", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^10.8.0|^11.22.0", + "laravel-notification-channels/discord": "^1.6", + "laravel-notification-channels/telegram": "^4.0|5.0", + "laravel/helpers": "^1.7.0", + "laravel/slack-notification-channel": "^2.5|^3.3.2", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.14.0" + }, + "require-dev": { + "larastan/larastan": "^2.9.8", + "laravel/pint": "^1.17.0", + "nunomaduro/collision": "^7.5.0|^8.4", + "orchestra/testbench": "^8.5.0|^9.4.0", + "pestphp/pest": "^2.35.1", + "pestphp/pest-plugin-laravel": "^2.4.0", + "phpstan/extension-installer": "^1.4.2", + "phpstan/phpstan-deprecation-rules": "^1.2.0", + "phpstan/phpstan-phpunit": "^1.3.11", + "phpunit/phpunit": "^10.5.17" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Vormkracht10\\Mails\\MailsServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Vormkracht10\\Mails\\": "src", + "Vormkracht10\\Mails\\Database\\Factories\\": "database/factories" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark van Eijk", + "email": "mark@vormkracht10.nl", + "role": "Developer" + } + ], + "description": "Laravel Mails can collect everything you might want to track about the mails that has been sent by your Laravel app.", + "homepage": "https://github.com/vormkracht10/laravel-mails", + "keywords": [ + "laravel", + "laravel-mails", + "vormkracht10" + ], + "support": { + "issues": "https://github.com/vormkracht10/laravel-mails/issues", + "source": "https://github.com/vormkracht10/laravel-mails/tree/v1.0.5" + }, + "funding": [ + { + "url": "https://github.com/vormkracht10", + "type": "github" + } + ], + "time": "2024-12-24T07:21:25+00:00" + }, { "name": "webmozart/assert", "version": "1.11.0", diff --git a/config/filament-mails.php b/config/filament-mails.php new file mode 100644 index 00000000..73b8a3be --- /dev/null +++ b/config/filament-mails.php @@ -0,0 +1,13 @@ + [ + 'mail' => MailResource::class, + 'event' => EventResource::class, + ], +]; diff --git a/config/mails.php b/config/mails.php new file mode 100644 index 00000000..b2ff2a31 --- /dev/null +++ b/config/mails.php @@ -0,0 +1,145 @@ + [ + 'mail' => Mail::class, + 'event' => MailEvent::class, + 'attachment' => MailAttachment::class, + ], + + // Table names for saving sent emails and polymorphic relations to database + + 'database' => [ + 'tables' => [ + 'mails' => 'mails', + 'attachments' => 'mail_attachments', + 'events' => 'mail_events', + 'polymorph' => 'mailables', + ], + + 'pruning' => [ + 'enabled' => true, + 'after' => 30, // days + ], + ], + + 'headers' => [ + 'uuid' => 'X-Mails-UUID', + + 'associate' => 'X-Mails-Associated-Models', + ], + + 'webhooks' => [ + 'routes' => [ + 'prefix' => 'webhooks/mails', + ], + + 'queue' => env('MAILS_QUEUE_WEBHOOKS', false), + ], + + // Logging mails + 'logging' => [ + + // Enable logging of all sent mails to database + + 'enabled' => env('MAILS_LOGGING_ENABLED', true), + + // Specify attributes to log in database + + 'attributes' => [ + 'subject', + 'from', + 'to', + 'reply_to', + 'cc', + 'bcc', + 'html', + 'text', + ], + + // Encrypt all attributes saved to database + + 'encrypted' => env('MAILS_ENCRYPTED', true), + + // Track following events using webhooks from email provider + + 'tracking' => [ + 'bounces' => true, + 'clicks' => true, + 'complaints' => true, + 'deliveries' => true, + 'opens' => true, + 'unsubscribes' => true, + ], + + // Enable saving mail attachments to disk + + 'attachments' => [ + 'enabled' => env('MAILS_LOGGING_ATTACHMENTS_ENABLED', true), + 'disk' => env('FILESYSTEM_DISK', 'local'), + 'root' => 'mails/attachments', + ], + ], + + // Notifications for important mail events + + 'notifications' => [ + 'mail' => [ + 'to' => [ + env('MAIL_SUPPORT'), + ], + ], + + 'discord' => [ + // 'to' => ['1234567890'], + ], + + 'slack' => [ + // 'to' => ['https://hooks.slack.com/services/...'], + ], + + 'telegram' => [ + // 'to' => ['1234567890'], + ], + ], + + 'events' => [ + 'soft_bounced' => [ + 'notify' => ['mail'], + ], + + 'hard_bounced' => [ + 'notify' => ['mail'], + ], + + 'bouncerate' => [ + 'notify' => [], + + 'retain' => 30, // days + + 'treshold' => 1, // % + ], + + 'deliveryrate' => [ + 'treshold' => 99, + ], + + 'complained' => [ + // + ], + + 'unsent' => [ + // + ], + ], + +]; diff --git a/database/migrations/2024_12_31_093231_1_create_mails_table.php b/database/migrations/2024_12_31_093231_1_create_mails_table.php new file mode 100644 index 00000000..d74b4b3c --- /dev/null +++ b/database/migrations/2024_12_31_093231_1_create_mails_table.php @@ -0,0 +1,40 @@ +id(); + $table->string('uuid')->nullable()->index(); + $table->string('mail_class')->nullable()->index(); + $table->string('subject')->nullable(); + $table->json('from')->nullable(); + $table->json('reply_to')->nullable(); + $table->json('to')->nullable(); + $table->json('cc')->nullable(); + $table->json('bcc')->nullable(); + $table->text('html')->nullable(); + $table->text('text')->nullable(); + $table->unsignedBigInteger('opens')->default(0); + $table->unsignedBigInteger('clicks')->default(0); + $table->timestamp('sent_at')->nullable(); + $table->timestamp('resent_at')->nullable(); + $table->timestamp('accepted_at')->nullable(); + $table->timestamp('delivered_at')->nullable(); + $table->timestamp('last_opened_at')->nullable(); + $table->timestamp('last_clicked_at')->nullable(); + $table->timestamp('complained_at')->nullable(); + $table->timestamp('soft_bounced_at')->nullable(); + $table->timestamp('hard_bounced_at')->nullable(); + $table->timestamp('unsubscribed_at')->nullable(); + $table->timestamps(); + }); + } +}; diff --git a/database/migrations/2024_12_31_093232_2_create_mail_attachments_table.php b/database/migrations/2024_12_31_093232_2_create_mail_attachments_table.php new file mode 100644 index 00000000..4a48d454 --- /dev/null +++ b/database/migrations/2024_12_31_093232_2_create_mail_attachments_table.php @@ -0,0 +1,27 @@ +id(); + $table->foreignIdFor(config('mails.models.mail')) + ->constrained() + ->cascadeOnDelete(); + $table->string('disk'); + $table->string('uuid'); + $table->string('filename'); + $table->string('mime'); + $table->boolean('inline', false); + $table->bigInteger('size'); + $table->timestamps(); + }); + } +}; diff --git a/database/migrations/2024_12_31_093233_2_create_mail_events_table.php b/database/migrations/2024_12_31_093233_2_create_mail_events_table.php new file mode 100644 index 00000000..b6d31920 --- /dev/null +++ b/database/migrations/2024_12_31_093233_2_create_mail_events_table.php @@ -0,0 +1,34 @@ +id(); + $table->foreignIdFor(config('mails.models.mail')) + ->constrained() + ->cascadeOnDelete(); + $table->string('type'); + $table->string('ip_address')->nullable(); + $table->string('hostname')->nullable(); + $table->string('platform')->nullable(); + $table->string('os')->nullable(); + $table->string('browser')->nullable(); + $table->string('user_agent')->nullable(); + $table->string('city')->nullable(); + $table->char('country_code', 2)->nullable(); + $table->string('link')->nullable(); + $table->string('tag')->nullable(); + $table->json('payload')->nullable(); + $table->timestamps(); + $table->timestamp('occurred_at')->nullable(); + }); + } +}; diff --git a/database/migrations/2024_12_31_093234_2_create_mailables_table.php b/database/migrations/2024_12_31_093234_2_create_mailables_table.php new file mode 100644 index 00000000..7cf22afb --- /dev/null +++ b/database/migrations/2024_12_31_093234_2_create_mailables_table.php @@ -0,0 +1,21 @@ +id(); + $table->foreignIdFor(config('mails.models.mail')) + ->constrained() + ->cascadeOnDelete(); + $table->morphs('mailable'); + }); + } +};