diff --git a/.env.example b/.env.example index 7a44f3e42..838583efe 100644 --- a/.env.example +++ b/.env.example @@ -55,3 +55,8 @@ SCOUT_DRIVER=meilisearch SCOUT_QUEUE=true MEILISEARCH_HOST= MEILISEARCH_KEY= + +# Notification channels +TELEGRAM_BOT_TOKEN= +TELEGRAM_BOT_URL= +TELEGRAM_BOT_WEBHOOK_URL= diff --git a/.env.testing b/.env.testing new file mode 100644 index 000000000..fe5d0ee9d --- /dev/null +++ b/.env.testing @@ -0,0 +1,27 @@ +APP_NAME=Monica +APP_ENV=local +APP_KEY=base64:G7wjzcmJ8lVlpDtY1LRYxQvCt7HeKXhkiUc2314OeUQ= +APP_DEBUG=true +APP_URL=https://ross.test + +LOG_CHANNEL=daily +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +# Used for SQLite testing +DB_TEST_DRIVER=sqlite +DB_TEST_DATABASE=public/css/sqlite_test +DB_TEST_HOST=127.0.0.1 +DB_TEST_USERNAME=root +DB_TEST_PASSWORD=root + +BROADCAST_DRIVER=log +CACHE_DRIVER=file +FILESYSTEM_DRIVER=local +QUEUE_CONNECTION=database +SESSION_DRIVER=file +SESSION_LIFETIME=120 + +TELEGRAM_BOT_TOKEN=123 +TELEGRAM_BOT_URL=https://t.me/randombot +TELEGRAM_BOT_WEBHOOK_URL=123 diff --git a/app/Console/Commands/TestReminders.php b/app/Console/Commands/TestReminders.php index 5fb35b83a..829fc615b 100644 --- a/app/Console/Commands/TestReminders.php +++ b/app/Console/Commands/TestReminders.php @@ -3,11 +3,15 @@ namespace App\Console\Commands; use App\Contact\ManageReminders\Services\RescheduleContactReminderForChannel; -use App\Jobs\Notifications\SendEmailNotification; +use App\Helpers\NameHelper; +use App\Models\ContactReminder; use App\Models\UserNotificationChannel; +use App\Notifications\ReminderTriggered; use Illuminate\Console\Command; +use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Notification; class TestReminders extends Command { @@ -43,18 +47,25 @@ class TestReminders extends Command foreach ($scheduledContactReminders as $scheduledReminder) { $channel = UserNotificationChannel::findOrFail($scheduledReminder->user_notification_channel_id); - if ($channel->type == UserNotificationChannel::TYPE_EMAIL) { - SendEmailNotification::dispatch( - $scheduledReminder->user_notification_channel_id, - $scheduledReminder->contact_reminder_id - )->onQueue('low'); + if ($channel->type == UserNotificationChannel::TYPE_EMAIL && $channel->active) { + $contactReminder = ContactReminder::findOrFail($scheduledReminder->contact_reminder_id); + + $contact = $contactReminder->contact; + $contactName = NameHelper::formatContactName($channel->user, $contact); + + Notification::route('mail', $channel->content) + ->notify(new ReminderTriggered($channel, $contactReminder->label, $contactName)); } - (new RescheduleContactReminderForChannel())->execute([ - 'contact_reminder_id' => $scheduledReminder->contact_reminder_id, - 'user_notification_channel_id' => $scheduledReminder->user_notification_channel_id, - 'contact_reminder_scheduled_id' => $scheduledReminder->id, - ]); + try { + (new RescheduleContactReminderForChannel())->execute([ + 'contact_reminder_id' => $scheduledReminder->contact_reminder_id, + 'user_notification_channel_id' => $scheduledReminder->user_notification_channel_id, + 'contact_reminder_scheduled_id' => $scheduledReminder->id, + ]); + } catch (ModelNotFoundException) { + continue; + } } } } diff --git a/app/Helpers/NameHelper.php b/app/Helpers/NameHelper.php index 1db0ae578..4b52da241 100644 --- a/app/Helpers/NameHelper.php +++ b/app/Helpers/NameHelper.php @@ -2,6 +2,7 @@ namespace App\Helpers; +use Illuminate\Support\Str; use App\Models\Contact; use App\Models\User; @@ -48,6 +49,12 @@ class NameHelper } } + // in some cases, the user will add parenthesis to add, for instance, + // the nickname, but if the nickname is not set, we need to remove them + // from being displayed + $completeName = str_replace('()', '', $completeName); + $completeName = Str::of($completeName)->rtrim(); + return $completeName; } } diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index 0c13b8548..4fd16238f 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -12,6 +12,6 @@ class VerifyCsrfToken extends Middleware * @var array */ protected $except = [ - // + '/telegram/webhook/*', ]; } diff --git a/app/Jobs/Notifications/SendEmailNotification.php b/app/Jobs/Notifications/SendEmailNotification.php deleted file mode 100644 index 0a0a4ff47..000000000 --- a/app/Jobs/Notifications/SendEmailNotification.php +++ /dev/null @@ -1,62 +0,0 @@ -userNotificationChannel = UserNotificationChannel::findOrFail($userNotificationChannelId); - $this->contactReminder = ContactReminder::findOrFail($contactReminderId); - } - - /** - * Execute the job. - * - * @return void - */ - public function handle() - { - $emailAddress = $this->userNotificationChannel->content; - $user = $this->userNotificationChannel->user; - - Mail::to($emailAddress) - ->queue( - (new SendReminder($this->contactReminder, $user)) - ->onQueue('low') - ); - - UserNotificationSent::create([ - 'user_notification_channel_id' => $this->userNotificationChannel->id, - 'sent_at' => Carbon::now(), - 'subject_line' => $this->contactReminder->label, - ]); - } -} diff --git a/app/Mail/SendReminder.php b/app/Mail/SendReminder.php deleted file mode 100644 index f845d9bd4..000000000 --- a/app/Mail/SendReminder.php +++ /dev/null @@ -1,50 +0,0 @@ -contactReminder = $contactReminder; - $this->user = $user; - } - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - $contact = $this->contactReminder->contact; - $contactName = NameHelper::formatContactName($this->user, $contact); - - $reason = $this->contactReminder->label; - - return $this->subject(trans('email.notification_reminder_email', ['name' => $contactName])) - ->markdown('emails.notifications.reminder', [ - 'name' => $this->user->name, - 'reason' => $reason, - 'contactName' => $contactName, - ]); - } -} diff --git a/app/Mail/UserNotificationChannelEmailCreated.php b/app/Mail/UserNotificationChannelEmailCreated.php index c1132c1e6..bee0cdd5b 100644 --- a/app/Mail/UserNotificationChannelEmailCreated.php +++ b/app/Mail/UserNotificationChannelEmailCreated.php @@ -33,7 +33,10 @@ class UserNotificationChannelEmailCreated extends Mailable { return $this->subject('Please validate your email address') ->markdown('emails.notifications.validate-email', [ - 'url' => $this->channel->email_verification_link, + 'url' => route('settings.notifications.verification.store', [ + 'notification' => $this->channel->id, + 'uuid' => $this->channel->verification_token, + ]), ]); } } diff --git a/app/Models/UserNotificationChannel.php b/app/Models/UserNotificationChannel.php index 43162df4d..cdcb320d7 100644 --- a/app/Models/UserNotificationChannel.php +++ b/app/Models/UserNotificationChannel.php @@ -18,6 +18,7 @@ class UserNotificationChannel extends Model * Possible type. */ public const TYPE_EMAIL = 'email'; + public const TYPE_TELEGRAM = 'telegram'; /** * The attributes that are mass assignable. @@ -32,7 +33,7 @@ class UserNotificationChannel extends Model 'active', 'verified_at', 'preferred_time', - 'email_verification_link', + 'verification_token', ]; /** diff --git a/app/Notifications/ReminderTriggered.php b/app/Notifications/ReminderTriggered.php new file mode 100644 index 000000000..bfe7713d5 --- /dev/null +++ b/app/Notifications/ReminderTriggered.php @@ -0,0 +1,92 @@ +content = $content; + $this->contactName = $contactName; + $this->channel = $channel; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via($notifiable) + { + return ['mail', 'telegram']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + UserNotificationSent::create([ + 'user_notification_channel_id' => $this->channel->id, + 'sent_at' => Carbon::now(), + 'subject_line' => $this->content, + ]); + + return (new MailMessage()) + ->subject(trans('email.notification_reminder_email', ['name' => $this->contactName])) + ->line(trans('email.reminder_triggered_intro')) + ->line($this->content) + ->line(trans('email.reminder_triggered_for')) + ->line($this->contactName) + ->line(trans('email.reminder_triggered_signature')); + } + + public function toTelegram($notifiable) + { + UserNotificationSent::create([ + 'user_notification_channel_id' => $this->channel->id, + 'sent_at' => Carbon::now(), + 'subject_line' => $this->content, + ]); + + return TelegramMessage::create() + ->to($this->channel->content) + ->content($this->content); + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + // + ]; + } +} diff --git a/composer.json b/composer.json index ad8ca44cc..f89b1cb0f 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "http-interop/http-factory-guzzle": "^1.2", "inertiajs/inertia-laravel": "^0.6.2", "itsgoingd/clockwork": "^5.1", - "laravel-notification-channels/telegram": "^2.0", + "laravel-notification-channels/telegram": "^2.1", "laravel/framework": "^9.0", "laravel/sanctum": "^2.6", "laravel/scout": "^9.4", diff --git a/composer.lock b/composer.lock index 023e01b6c..0967566b5 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": "efc65da104294a065a51d76bff968d03", + "content-hash": "7b49550f8e7a6f67670354298f2dfbfb", "packages": [ { "name": "asm89/stack-cors", @@ -1154,16 +1154,16 @@ }, { "name": "inertiajs/inertia-laravel", - "version": "v0.6.2", + "version": "v0.6.3", "source": { "type": "git", "url": "https://github.com/inertiajs/inertia-laravel.git", - "reference": "75859fb1586c3d37ed8705500b5f43e87eee3cb2" + "reference": "540b953ec383364264f9bd633849db16560a4461" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/inertiajs/inertia-laravel/zipball/75859fb1586c3d37ed8705500b5f43e87eee3cb2", - "reference": "75859fb1586c3d37ed8705500b5f43e87eee3cb2", + "url": "https://api.github.com/repos/inertiajs/inertia-laravel/zipball/540b953ec383364264f9bd633849db16560a4461", + "reference": "540b953ec383364264f9bd633849db16560a4461", "shasum": "" }, "require": { @@ -1211,7 +1211,7 @@ ], "support": { "issues": "https://github.com/inertiajs/inertia-laravel/issues", - "source": "https://github.com/inertiajs/inertia-laravel/tree/v0.6.2" + "source": "https://github.com/inertiajs/inertia-laravel/tree/v0.6.3" }, "funding": [ { @@ -1219,7 +1219,7 @@ "type": "github" } ], - "time": "2022-05-25T02:00:06+00:00" + "time": "2022-06-27T23:21:15+00:00" }, { "name": "itsgoingd/clockwork", @@ -1291,16 +1291,16 @@ }, { "name": "laravel-notification-channels/telegram", - "version": "2.0.0", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/laravel-notification-channels/telegram.git", - "reference": "63f6727c3f9953e11ee9a690c29ce0db456d69a1" + "reference": "76299fa06f48cb175e17ea951ccf3b185329a1ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel-notification-channels/telegram/zipball/63f6727c3f9953e11ee9a690c29ce0db456d69a1", - "reference": "63f6727c3f9953e11ee9a690c29ce0db456d69a1", + "url": "https://api.github.com/repos/laravel-notification-channels/telegram/zipball/76299fa06f48cb175e17ea951ccf3b185329a1ac", + "reference": "76299fa06f48cb175e17ea951ccf3b185329a1ac", "shasum": "" }, "require": { @@ -1351,22 +1351,22 @@ ], "support": { "issues": "https://github.com/laravel-notification-channels/telegram/issues", - "source": "https://github.com/laravel-notification-channels/telegram/tree/2.0.0" + "source": "https://github.com/laravel-notification-channels/telegram/tree/2.1.0" }, - "time": "2022-02-10T19:29:50+00:00" + "time": "2022-07-01T02:14:31+00:00" }, { "name": "laravel/framework", - "version": "v9.18.0", + "version": "v9.19.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "93a1296bca43c1ca8dcb5df8f97107e819a71499" + "reference": "bbce25bd823133f6a5a724f2d62680b711f1d0df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/93a1296bca43c1ca8dcb5df8f97107e819a71499", - "reference": "93a1296bca43c1ca8dcb5df8f97107e819a71499", + "url": "https://api.github.com/repos/laravel/framework/zipball/bbce25bd823133f6a5a724f2d62680b711f1d0df", + "reference": "bbce25bd823133f6a5a724f2d62680b711f1d0df", "shasum": "" }, "require": { @@ -1532,7 +1532,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2022-06-21T14:40:11+00:00" + "time": "2022-06-28T14:33:19+00:00" }, { "name": "laravel/sanctum", @@ -1988,16 +1988,16 @@ }, { "name": "league/flysystem", - "version": "3.0.21", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "8f1fcf9d2304ff77a006aa36dd2cb5f236999b12" + "reference": "34a68067b7ae3b836ea5e57e1fc432478372a4f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/8f1fcf9d2304ff77a006aa36dd2cb5f236999b12", - "reference": "8f1fcf9d2304ff77a006aa36dd2cb5f236999b12", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/34a68067b7ae3b836ea5e57e1fc432478372a4f5", + "reference": "34a68067b7ae3b836ea5e57e1fc432478372a4f5", "shasum": "" }, "require": { @@ -2058,7 +2058,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.0.21" + "source": "https://github.com/thephpleague/flysystem/tree/3.1.0" }, "funding": [ { @@ -2074,7 +2074,7 @@ "type": "tidelift" } ], - "time": "2022-06-12T17:54:28+00:00" + "time": "2022-06-29T17:29:54+00:00" }, { "name": "league/mime-type-detection", @@ -2305,16 +2305,16 @@ }, { "name": "nesbot/carbon", - "version": "2.58.0", + "version": "2.59.1", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "97a34af22bde8d0ac20ab34b29d7bfe360902055" + "reference": "a9000603ea337c8df16cc41f8b6be95a65f4d0f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/97a34af22bde8d0ac20ab34b29d7bfe360902055", - "reference": "97a34af22bde8d0ac20ab34b29d7bfe360902055", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/a9000603ea337c8df16cc41f8b6be95a65f4d0f5", + "reference": "a9000603ea337c8df16cc41f8b6be95a65f4d0f5", "shasum": "" }, "require": { @@ -2329,11 +2329,12 @@ "doctrine/orm": "^2.7", "friendsofphp/php-cs-fixer": "^3.0", "kylekatarnls/multi-tester": "^2.0", + "ondrejmirtes/better-reflection": "*", "phpmd/phpmd": "^2.9", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.54 || ^1.0", - "phpunit/php-file-iterator": "^2.0.5", - "phpunit/phpunit": "^7.5.20 || ^8.5.23", + "phpstan/phpstan": "^0.12.99 || ^1.7.14", + "phpunit/php-file-iterator": "^2.0.5 || ^3.0.6", + "phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20", "squizlabs/php_codesniffer": "^3.4" }, "bin": [ @@ -2390,15 +2391,19 @@ }, "funding": [ { - "url": "https://opencollective.com/Carbon", - "type": "open_collective" + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", "type": "tidelift" } ], - "time": "2022-04-25T19:31:17+00:00" + "time": "2022-06-29T21:43:55+00:00" }, { "name": "nette/schema", @@ -2680,16 +2685,16 @@ }, { "name": "php-http/discovery", - "version": "1.14.2", + "version": "1.14.3", "source": { "type": "git", "url": "https://github.com/php-http/discovery.git", - "reference": "c8d48852fbc052454af42f6de27635ddd916b959" + "reference": "31d8ee46d0215108df16a8527c7438e96a4d7735" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/discovery/zipball/c8d48852fbc052454af42f6de27635ddd916b959", - "reference": "c8d48852fbc052454af42f6de27635ddd916b959", + "url": "https://api.github.com/repos/php-http/discovery/zipball/31d8ee46d0215108df16a8527c7438e96a4d7735", + "reference": "31d8ee46d0215108df16a8527c7438e96a4d7735", "shasum": "" }, "require": { @@ -2741,9 +2746,9 @@ ], "support": { "issues": "https://github.com/php-http/discovery/issues", - "source": "https://github.com/php-http/discovery/tree/1.14.2" + "source": "https://github.com/php-http/discovery/tree/1.14.3" }, - "time": "2022-05-25T07:26:05+00:00" + "time": "2022-07-11T14:04:40+00:00" }, { "name": "php-http/httplug", @@ -3429,16 +3434,16 @@ }, { "name": "psy/psysh", - "version": "v0.11.5", + "version": "v0.11.7", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "c23686f9c48ca202710dbb967df8385a952a2daf" + "reference": "77fc7270031fbc28f9a7bea31385da5c4855cb7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/c23686f9c48ca202710dbb967df8385a952a2daf", - "reference": "c23686f9c48ca202710dbb967df8385a952a2daf", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/77fc7270031fbc28f9a7bea31385da5c4855cb7a", + "reference": "77fc7270031fbc28f9a7bea31385da5c4855cb7a", "shasum": "" }, "require": { @@ -3499,9 +3504,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.11.5" + "source": "https://github.com/bobthecow/psysh/tree/v0.11.7" }, - "time": "2022-05-27T18:03:49+00:00" + "time": "2022-07-07T13:49:11+00:00" }, { "name": "ralouphie/getallheaders", @@ -3722,16 +3727,16 @@ }, { "name": "symfony/console", - "version": "v6.1.1", + "version": "v6.1.2", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "6187424023fbffcd757789aeb517c9161b1eabee" + "reference": "7a86c1c42fbcb69b59768504c7bca1d3767760b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/6187424023fbffcd757789aeb517c9161b1eabee", - "reference": "6187424023fbffcd757789aeb517c9161b1eabee", + "url": "https://api.github.com/repos/symfony/console/zipball/7a86c1c42fbcb69b59768504c7bca1d3767760b7", + "reference": "7a86c1c42fbcb69b59768504c7bca1d3767760b7", "shasum": "" }, "require": { @@ -3798,7 +3803,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.1.1" + "source": "https://github.com/symfony/console/tree/v6.1.2" }, "funding": [ { @@ -3814,7 +3819,7 @@ "type": "tidelift" } ], - "time": "2022-06-08T14:02:09+00:00" + "time": "2022-06-26T13:01:30+00:00" }, { "name": "symfony/css-selector", @@ -3883,7 +3888,7 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -3930,7 +3935,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.1" }, "funding": [ { @@ -4104,7 +4109,7 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", @@ -4163,7 +4168,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.1.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.1.1" }, "funding": [ { @@ -4247,16 +4252,16 @@ }, { "name": "symfony/http-foundation", - "version": "v6.1.1", + "version": "v6.1.2", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "a58dc88d56e04e57993d96c1407a17407610e1df" + "reference": "86119d294e51afe4d8e07da96b63332bd1f3f52c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a58dc88d56e04e57993d96c1407a17407610e1df", - "reference": "a58dc88d56e04e57993d96c1407a17407610e1df", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/86119d294e51afe4d8e07da96b63332bd1f3f52c", + "reference": "86119d294e51afe4d8e07da96b63332bd1f3f52c", "shasum": "" }, "require": { @@ -4299,7 +4304,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.1.1" + "source": "https://github.com/symfony/http-foundation/tree/v6.1.2" }, "funding": [ { @@ -4315,20 +4320,20 @@ "type": "tidelift" } ], - "time": "2022-05-31T14:28:03+00:00" + "time": "2022-06-19T13:21:48+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.1.1", + "version": "v6.1.2", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "86c4d6f6c5b6cd012df41e3b950c924b3ffdc019" + "reference": "8aaede489900dda61aee208557f63bfa1bca0877" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/86c4d6f6c5b6cd012df41e3b950c924b3ffdc019", - "reference": "86c4d6f6c5b6cd012df41e3b950c924b3ffdc019", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8aaede489900dda61aee208557f63bfa1bca0877", + "reference": "8aaede489900dda61aee208557f63bfa1bca0877", "shasum": "" }, "require": { @@ -4409,7 +4414,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.1.1" + "source": "https://github.com/symfony/http-kernel/tree/v6.1.2" }, "funding": [ { @@ -4425,20 +4430,20 @@ "type": "tidelift" } ], - "time": "2022-06-09T17:31:33+00:00" + "time": "2022-06-26T17:06:14+00:00" }, { "name": "symfony/mailer", - "version": "v6.1.1", + "version": "v6.1.2", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "db6a19a5c896139901c2de59fc9849379e0ff3b6" + "reference": "8fa150355115ea09238858ae3cfaf249fd1fd5ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/db6a19a5c896139901c2de59fc9849379e0ff3b6", - "reference": "db6a19a5c896139901c2de59fc9849379e0ff3b6", + "url": "https://api.github.com/repos/symfony/mailer/zipball/8fa150355115ea09238858ae3cfaf249fd1fd5ed", + "reference": "8fa150355115ea09238858ae3cfaf249fd1fd5ed", "shasum": "" }, "require": { @@ -4483,7 +4488,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v6.1.1" + "source": "https://github.com/symfony/mailer/tree/v6.1.2" }, "funding": [ { @@ -4499,7 +4504,7 @@ "type": "tidelift" } ], - "time": "2022-06-06T19:15:01+00:00" + "time": "2022-06-19T13:21:48+00:00" }, { "name": "symfony/mime", @@ -5455,16 +5460,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "d66cd8ab656780f62c4215b903a420eb86358957" + "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d66cd8ab656780f62c4215b903a420eb86358957", - "reference": "d66cd8ab656780f62c4215b903a420eb86358957", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/925e713fe8fcacf6bc05e936edd8dd5441a21239", + "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239", "shasum": "" }, "require": { @@ -5520,7 +5525,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.1.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.1.1" }, "funding": [ { @@ -5536,20 +5541,20 @@ "type": "tidelift" } ], - "time": "2022-05-07T08:07:09+00:00" + "time": "2022-05-30T19:18:58+00:00" }, { "name": "symfony/string", - "version": "v6.1.0", + "version": "v6.1.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529" + "reference": "1903f2879875280c5af944625e8246d81c2f0604" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/d3edc75baf9f1d4f94879764dda2e1ac33499529", - "reference": "d3edc75baf9f1d4f94879764dda2e1ac33499529", + "url": "https://api.github.com/repos/symfony/string/zipball/1903f2879875280c5af944625e8246d81c2f0604", + "reference": "1903f2879875280c5af944625e8246d81c2f0604", "shasum": "" }, "require": { @@ -5605,7 +5610,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.1.0" + "source": "https://github.com/symfony/string/tree/v6.1.2" }, "funding": [ { @@ -5621,7 +5626,7 @@ "type": "tidelift" } ], - "time": "2022-04-22T08:18:23+00:00" + "time": "2022-06-26T16:35:04+00:00" }, { "name": "symfony/translation", @@ -5721,16 +5726,16 @@ }, { "name": "symfony/translation-contracts", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "bfddd2a1faa271b782b791c361cc16e2dd49dfaa" + "reference": "606be0f48e05116baef052f7f3abdb345c8e02cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/bfddd2a1faa271b782b791c361cc16e2dd49dfaa", - "reference": "bfddd2a1faa271b782b791c361cc16e2dd49dfaa", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/606be0f48e05116baef052f7f3abdb345c8e02cc", + "reference": "606be0f48e05116baef052f7f3abdb345c8e02cc", "shasum": "" }, "require": { @@ -5782,7 +5787,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.1.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.1.1" }, "funding": [ { @@ -5798,7 +5803,7 @@ "type": "tidelift" } ], - "time": "2022-04-22T07:30:54+00:00" + "time": "2022-06-27T17:24:16+00:00" }, { "name": "symfony/var-dumper", @@ -6602,16 +6607,16 @@ }, { "name": "brianium/paratest", - "version": "v6.5.1", + "version": "v6.6.0", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "41fc4cc01422dae2d6bf6a0ce39756f57ac7d8a9" + "reference": "bce7b965a5fe5028a53c3151042ca12777600acd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/41fc4cc01422dae2d6bf6a0ce39756f57ac7d8a9", - "reference": "41fc4cc01422dae2d6bf6a0ce39756f57ac7d8a9", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/bce7b965a5fe5028a53c3151042ca12777600acd", + "reference": "bce7b965a5fe5028a53c3151042ca12777600acd", "shasum": "" }, "require": { @@ -6626,18 +6631,18 @@ "phpunit/php-timer": "^5.0.3", "phpunit/phpunit": "^9.5.21", "sebastian/environment": "^5.1.4", - "symfony/console": "^5.4.9 || ^6.1.1", + "symfony/console": "^5.4.9 || ^6.1.2", "symfony/process": "^5.4.8 || ^6.1.0" }, "require-dev": { "doctrine/coding-standard": "^9.0.0", "ext-pcov": "*", "ext-posix": "*", - "infection/infection": "^0.26.12", + "infection/infection": "^0.26.13", "malukenho/mcbumpface": "^1.1.5", "squizlabs/php_codesniffer": "^3.7.1", "symfony/filesystem": "^5.4.9 || ^6.1.0", - "vimeo/psalm": "^4.23.0" + "vimeo/psalm": "^4.24.0" }, "bin": [ "bin/paratest", @@ -6678,7 +6683,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v6.5.1" + "source": "https://github.com/paratestphp/paratest/tree/v6.6.0" }, "funding": [ { @@ -6690,7 +6695,7 @@ "type": "paypal" } ], - "time": "2022-06-24T16:02:27+00:00" + "time": "2022-07-12T07:15:58+00:00" }, { "name": "composer/package-versions-deprecated", @@ -7835,16 +7840,16 @@ }, { "name": "laravel/breeze", - "version": "v1.9.4", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/laravel/breeze.git", - "reference": "98c79a68ae53c2193367238c019a2f988be44f4f" + "reference": "e98e855ab4bde5bf0083c4a4d73c0f5b474241ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/breeze/zipball/98c79a68ae53c2193367238c019a2f988be44f4f", - "reference": "98c79a68ae53c2193367238c019a2f988be44f4f", + "url": "https://api.github.com/repos/laravel/breeze/zipball/e98e855ab4bde5bf0083c4a4d73c0f5b474241ae", + "reference": "e98e855ab4bde5bf0083c4a4d73c0f5b474241ae", "shasum": "" }, "require": { @@ -7888,7 +7893,7 @@ "issues": "https://github.com/laravel/breeze/issues", "source": "https://github.com/laravel/breeze" }, - "time": "2022-06-13T18:41:50+00:00" + "time": "2022-06-28T11:52:06+00:00" }, { "name": "laravel/pint", @@ -7957,16 +7962,16 @@ }, { "name": "laravel/sail", - "version": "v1.14.11", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "6edf45a247b3688e0d07e149570a62fd9bc11c73" + "reference": "676e1ff33c1b8af657779f62f57360c376cba666" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/6edf45a247b3688e0d07e149570a62fd9bc11c73", - "reference": "6edf45a247b3688e0d07e149570a62fd9bc11c73", + "url": "https://api.github.com/repos/laravel/sail/zipball/676e1ff33c1b8af657779f62f57360c376cba666", + "reference": "676e1ff33c1b8af657779f62f57360c376cba666", "shasum": "" }, "require": { @@ -8013,7 +8018,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2022-06-13T18:32:48+00:00" + "time": "2022-06-24T13:56:11+00:00" }, { "name": "mockery/mockery", @@ -8199,16 +8204,16 @@ }, { "name": "nunomaduro/collision", - "version": "v6.2.0", + "version": "v6.2.1", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "c379636dc50e829edb3a8bcb944a01aa1aed8f25" + "reference": "5f058f7e39278b701e455b3c82ec5298cf001d89" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/c379636dc50e829edb3a8bcb944a01aa1aed8f25", - "reference": "c379636dc50e829edb3a8bcb944a01aa1aed8f25", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/5f058f7e39278b701e455b3c82ec5298cf001d89", + "reference": "5f058f7e39278b701e455b3c82ec5298cf001d89", "shasum": "" }, "require": { @@ -8220,6 +8225,7 @@ "require-dev": { "brianium/paratest": "^6.4.1", "laravel/framework": "^9.7", + "laravel/pint": "^0.2.1", "nunomaduro/larastan": "^1.0.2", "nunomaduro/mock-final-classes": "^1.1.0", "orchestra/testbench": "^7.3.0", @@ -8282,7 +8288,7 @@ "type": "patreon" } ], - "time": "2022-04-05T15:31:38+00:00" + "time": "2022-06-27T16:11:16+00:00" }, { "name": "nunomaduro/larastan", @@ -8848,16 +8854,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.7.15", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "cd0202ea1b1fc6d1bbe156c6e2e18a03e0ff160a" + "reference": "8dbba631fa32f4b289404469c2afd6122fd61d67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cd0202ea1b1fc6d1bbe156c6e2e18a03e0ff160a", - "reference": "cd0202ea1b1fc6d1bbe156c6e2e18a03e0ff160a", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/8dbba631fa32f4b289404469c2afd6122fd61d67", + "reference": "8dbba631fa32f4b289404469c2afd6122fd61d67", "shasum": "" }, "require": { @@ -8883,7 +8889,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.7.15" + "source": "https://github.com/phpstan/phpstan/tree/1.8.1" }, "funding": [ { @@ -8903,7 +8909,7 @@ "type": "tidelift" } ], - "time": "2022-06-20T08:29:01+00:00" + "time": "2022-07-12T16:08:06+00:00" }, { "name": "phpunit/php-code-coverage", @@ -10686,16 +10692,16 @@ }, { "name": "vimeo/psalm", - "version": "4.23.0", + "version": "4.24.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "f1fe6ff483bf325c803df9f510d09a03fd796f88" + "reference": "06dd975cb55d36af80f242561738f16c5f58264f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/f1fe6ff483bf325c803df9f510d09a03fd796f88", - "reference": "f1fe6ff483bf325c803df9f510d09a03fd796f88", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/06dd975cb55d36af80f242561738f16c5f58264f", + "reference": "06dd975cb55d36af80f242561738f16c5f58264f", "shasum": "" }, "require": { @@ -10787,9 +10793,9 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/4.23.0" + "source": "https://github.com/vimeo/psalm/tree/4.24.0" }, - "time": "2022-04-28T17:35:49+00:00" + "time": "2022-06-26T11:47:54+00:00" }, { "name": "webmozart/path-util", diff --git a/config/services.php b/config/services.php index 7c6ec9824..720277d66 100644 --- a/config/services.php +++ b/config/services.php @@ -31,7 +31,9 @@ return [ ], 'telegram-bot-api' => [ - 'token' => env('TELEGRAM_BOT_TOKEN', 'YOUR BOT TOKEN HERE'), + 'token' => env('TELEGRAM_BOT_TOKEN', null), + 'bot_url' => env('TELEGRAM_BOT_URL'), + 'webhook' => env('TELEGRAM_BOT_WEBHOOK_URL'), ], ]; diff --git a/database/migrations/2022_02_18_215852_create_reminders_table.php b/database/migrations/2022_02_18_215852_create_reminders_table.php index 1306021ee..7bb6c2c86 100644 --- a/database/migrations/2022_02_18_215852_create_reminders_table.php +++ b/database/migrations/2022_02_18_215852_create_reminders_table.php @@ -34,12 +34,12 @@ return new class () extends Migration { $table->id(); $table->unsignedBigInteger('user_id')->nullable(); $table->string('type'); - $table->string('label'); + $table->string('label')->nullable(); $table->text('content'); $table->time('preferred_time')->nullable(); $table->boolean('active')->default(false); $table->datetime('verified_at')->nullable(); - $table->string('email_verification_link')->nullable(); + $table->string('verification_token')->nullable(); $table->timestamps(); $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); }); diff --git a/domains/Contact/ManageReminders/Jobs/ProcessScheduledContactReminders.php b/domains/Contact/ManageReminders/Jobs/ProcessScheduledContactReminders.php index 99643bae8..de7a821ec 100644 --- a/domains/Contact/ManageReminders/Jobs/ProcessScheduledContactReminders.php +++ b/domains/Contact/ManageReminders/Jobs/ProcessScheduledContactReminders.php @@ -3,8 +3,11 @@ namespace App\Contact\ManageReminders\Jobs; use App\Contact\ManageReminders\Services\RescheduleContactReminderForChannel; -use App\Jobs\Notifications\SendEmailNotification; +use App\Helpers\NameHelper; +use App\Models\ContactReminder; use App\Models\UserNotificationChannel; +use App\Models\UserNotificationSent; +use App\Notifications\ReminderTriggered; use Carbon\Carbon; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; @@ -12,6 +15,7 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Notification; class ProcessScheduledContactReminders implements ShouldQueue { @@ -51,10 +55,18 @@ class ProcessScheduledContactReminders implements ShouldQueue $channel = UserNotificationChannel::findOrFail($scheduledReminder->user_notification_channel_id); if ($channel->type == UserNotificationChannel::TYPE_EMAIL) { - SendEmailNotification::dispatch( - $scheduledReminder->user_notification_channel_id, - $scheduledReminder->contact_reminder_id - )->onQueue('low'); + $contactReminder = ContactReminder::find($scheduledReminder->contact_reminder_id); + $contact = $contactReminder->contact; + $contactName = NameHelper::formatContactName($channel->user, $contact); + + Notification::route('mail', $channel->content) + ->notify(new ReminderTriggered($channel, $contactReminder->label, $contactName)); + + UserNotificationSent::create([ + 'user_notification_channel_id' => $channel->id, + 'sent_at' => Carbon::now(), + 'subject_line' => $contactReminder->label, + ]); } $this->updateScheduledContactReminderTriggeredAt($scheduledReminder->id); diff --git a/domains/Settings/ManageNotificationChannels/Services/CreateUserNotificationChannel.php b/domains/Settings/ManageNotificationChannels/Services/CreateUserNotificationChannel.php index 1b7f65faa..1c6edf69f 100644 --- a/domains/Settings/ManageNotificationChannels/Services/CreateUserNotificationChannel.php +++ b/domains/Settings/ManageNotificationChannels/Services/CreateUserNotificationChannel.php @@ -85,16 +85,8 @@ class CreateUserNotificationChannel extends BaseService implements ServiceInterf 'preferred_time' => $this->data['preferred_time'], ]); - // add a verification link if the channel is email - if ($this->data['verify_email']) { - $uuid = Str::uuid(); - - $this->userNotificationChannel->email_verification_link = route('settings.notifications.verification.store', [ - 'notification' => $this->userNotificationChannel->id, - 'uuid' => $uuid, - ]); - $this->userNotificationChannel->save(); - } + $this->userNotificationChannel->verification_token = (string) Str::uuid(); + $this->userNotificationChannel->save(); } private function verifyChannel(): void diff --git a/domains/Settings/ManageNotificationChannels/Services/SendTestEmail.php b/domains/Settings/ManageNotificationChannels/Services/SendTestEmail.php index 589047bb0..d83c2ff1b 100644 --- a/domains/Settings/ManageNotificationChannels/Services/SendTestEmail.php +++ b/domains/Settings/ManageNotificationChannels/Services/SendTestEmail.php @@ -4,7 +4,6 @@ namespace App\Settings\ManageNotificationChannels\Services; use App\Interfaces\ServiceInterface; use App\Mail\TestEmailSent; -use App\Models\User; use App\Models\UserNotificationChannel; use App\Models\UserNotificationSent; use App\Services\BaseService; diff --git a/domains/Settings/ManageNotificationChannels/Services/SendTestTelegramNotification.php b/domains/Settings/ManageNotificationChannels/Services/SendTestTelegramNotification.php new file mode 100644 index 000000000..e6a3a3b43 --- /dev/null +++ b/domains/Settings/ManageNotificationChannels/Services/SendTestTelegramNotification.php @@ -0,0 +1,80 @@ + 'required|integer|exists:accounts,id', + 'author_id' => 'required|integer|exists:users,id', + 'user_notification_channel_id' => 'required|integer|exists:user_notification_channels,id', + ]; + } + + /** + * Get the permissions that apply to the user calling the service. + * + * @return array + */ + public function permissions(): array + { + return [ + 'author_must_belong_to_account', + ]; + } + + /** + * Send a test notification to Telegram. + * + * @param array $data + * @return UserNotificationChannel + */ + public function execute(array $data): UserNotificationChannel + { + $this->data = $data; + $this->validate(); + $this->send(); + + return $this->userNotificationChannel; + } + + private function validate(): void + { + $this->validateRules($this->data); + + $this->userNotificationChannel = UserNotificationChannel::where('user_id', $this->data['author_id']) + ->findOrFail($this->data['user_notification_channel_id']); + + if ($this->userNotificationChannel->type !== UserNotificationChannel::TYPE_TELEGRAM) { + throw new Exception('Only telegram messages can be sent.'); + } + } + + private function send(): void + { + $content = trans('settings.notification_channels_telegram_test_notification', ['name' => $this->author->name]); + + Notification::route('telegram', $this->userNotificationChannel->content) + ->notify(new ReminderTriggered($this->userNotificationChannel, $content, 'Test')); + } +} diff --git a/domains/Settings/ManageNotificationChannels/Web/Controllers/NotificationsController.php b/domains/Settings/ManageNotificationChannels/Web/Controllers/NotificationsController.php index 9f6d1f5b2..3e91e6149 100644 --- a/domains/Settings/ManageNotificationChannels/Web/Controllers/NotificationsController.php +++ b/domains/Settings/ManageNotificationChannels/Web/Controllers/NotificationsController.php @@ -39,7 +39,7 @@ class NotificationsController extends Controller $channel = (new CreateUserNotificationChannel())->execute($data); return response()->json([ - 'data' => NotificationsIndexViewHelper::dtoEmail($channel, Auth::user()), + 'data' => NotificationsIndexViewHelper::dtoEmail($channel), ], 200); } diff --git a/domains/Settings/ManageNotificationChannels/Web/Controllers/NotificationsTestController.php b/domains/Settings/ManageNotificationChannels/Web/Controllers/NotificationsTestController.php index 1f7e4d648..4f8bc63c5 100644 --- a/domains/Settings/ManageNotificationChannels/Web/Controllers/NotificationsTestController.php +++ b/domains/Settings/ManageNotificationChannels/Web/Controllers/NotificationsTestController.php @@ -3,7 +3,9 @@ namespace App\Settings\ManageNotificationChannels\Web\Controllers; use App\Http\Controllers\Controller; +use App\Models\UserNotificationChannel; use App\Settings\ManageNotificationChannels\Services\SendTestEmail; +use App\Settings\ManageNotificationChannels\Services\SendTestTelegramNotification; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; @@ -17,7 +19,15 @@ class NotificationsTestController extends Controller 'user_notification_channel_id' => $userNotificationChannelId, ]; - (new SendTestEmail())->execute($data); + $channel = UserNotificationChannel::find($userNotificationChannelId); + + if ($channel->type == UserNotificationChannel::TYPE_EMAIL) { + (new SendTestEmail())->execute($data); + } + + if ($channel->type == UserNotificationChannel::TYPE_TELEGRAM) { + (new SendTestTelegramNotification())->execute($data); + } return response()->json([ 'data' => true, diff --git a/domains/Settings/ManageNotificationChannels/Web/Controllers/NotificationsToggleController.php b/domains/Settings/ManageNotificationChannels/Web/Controllers/NotificationsToggleController.php index d0f62ea3f..b6fa0a2d9 100644 --- a/domains/Settings/ManageNotificationChannels/Web/Controllers/NotificationsToggleController.php +++ b/domains/Settings/ManageNotificationChannels/Web/Controllers/NotificationsToggleController.php @@ -21,7 +21,7 @@ class NotificationsToggleController extends Controller $channel = (new ToggleUserNotificationChannel())->execute($data); return response()->json([ - 'data' => NotificationsIndexViewHelper::dtoEmail($channel, Auth::user()), + 'data' => NotificationsIndexViewHelper::dtoEmail($channel), ], 200); } } diff --git a/domains/Settings/ManageNotificationChannels/Web/Controllers/TelegramNotificationsController.php b/domains/Settings/ManageNotificationChannels/Web/Controllers/TelegramNotificationsController.php new file mode 100644 index 000000000..d32a7ceb7 --- /dev/null +++ b/domains/Settings/ManageNotificationChannels/Web/Controllers/TelegramNotificationsController.php @@ -0,0 +1,34 @@ +input('hours').':'.$request->input('minutes'); + + $data = [ + 'account_id' => Auth::user()->account_id, + 'author_id' => Auth::user()->id, + 'label' => 'Telegram', + 'type' => UserNotificationChannel::TYPE_TELEGRAM, + 'content' => 'tbd', + 'verify_email' => false, + 'preferred_time' => $time, + ]; + + $channel = (new CreateUserNotificationChannel())->execute($data); + + return response()->json([ + 'data' => NotificationsIndexViewHelper::dtoTelegram($channel), + ], 200); + } +} diff --git a/domains/Settings/ManageNotificationChannels/Web/Controllers/TelegramWebhookController.php b/domains/Settings/ManageNotificationChannels/Web/Controllers/TelegramWebhookController.php new file mode 100644 index 000000000..151d8f7eb --- /dev/null +++ b/domains/Settings/ManageNotificationChannels/Web/Controllers/TelegramWebhookController.php @@ -0,0 +1,53 @@ +message['text']; + } catch (Exception $e) { + return response()->json([ + 'code' => $e->getCode(), + 'message' => 'Accepted with error: \'' . $e->getMessage() . '\'', + ], 202); + } + + // check if the message matches the expected pattern. + // if the message does not match the pattern, then we return a 202 response + // so telegram will stop trying to send the message. + if (! Str::of($messageText)->test('/^\/start\s[A-Za-z0-9-]{36}$/')) { + return response('Accepted', 202); + } + + // Cleanup the string + $verificationKey = Str::of($messageText)->remove('/start ')->rtrim(); + + // Get Telegram ID from the request. + $chatId = $request->message['chat']['id']; + + // Get the User ID from the cache using the temp code as key. + $channel = UserNotificationChannel::where('verification_token', $verificationKey)->first(); + + // Update user with the Telegram Chat ID + $channel->content = $chatId; + $channel->active = true; + $channel->save(); + + return response('Success', 200); + } +} diff --git a/domains/Settings/ManageNotificationChannels/Web/ViewHelpers/NotificationsIndexViewHelper.php b/domains/Settings/ManageNotificationChannels/Web/ViewHelpers/NotificationsIndexViewHelper.php index 72f3c667c..b6feb76c7 100644 --- a/domains/Settings/ManageNotificationChannels/Web/ViewHelpers/NotificationsIndexViewHelper.php +++ b/domains/Settings/ManageNotificationChannels/Web/ViewHelpers/NotificationsIndexViewHelper.php @@ -19,17 +19,27 @@ class NotificationsIndexViewHelper return self::dtoEmail($channel, $user); }); + // telegram + $telegram = $channels->filter(function ($channel) { + return $channel->type === 'telegram'; + })->first(); + return [ 'emails' => $emailsCollection, + 'telegram' => [ + 'data' => $telegram ? self::dtoTelegram($telegram) : null, + 'telegram_env_variable_set' => config('services.telegram-bot-api.token'), + ], 'url' => [ 'settings' => route('settings.index'), 'back' => route('settings.index'), 'store' => route('settings.notifications.store'), + 'store_telegram' => route('settings.notifications.telegram.store'), ], ]; } - public static function dtoEmail(UserNotificationChannel $channel, User $user): array + public static function dtoEmail(UserNotificationChannel $channel): array { return [ 'id' => $channel->id, @@ -56,4 +66,30 @@ class NotificationsIndexViewHelper ], ]; } + + public static function dtoTelegram(UserNotificationChannel $channel): array + { + return [ + 'id' => $channel->id, + 'type' => $channel->type, + 'active' => $channel->active, + 'verified_at' => $channel->verified_at ? $channel->verified_at->format('Y-m-d H:i:s') : null, + 'preferred_time' => $channel->preferred_time->format('H:i'), + 'url' => [ + 'open' => config('services.telegram-bot-api.bot_url').'?start='.$channel->verification_token, + 'send_test' => route('settings.notifications.test.store', [ + 'notification' => $channel->id, + ]), + 'toggle' => route('settings.notifications.toggle.update', [ + 'notification' => $channel->id, + ]), + 'logs' => route('settings.notifications.log.index', [ + 'notification' => $channel->id, + ]), + 'destroy' => route('settings.notifications.destroy', [ + 'notification' => $channel->id, + ]), + ], + ]; + } } diff --git a/domains/Settings/ManageNotificationChannels/Web/ViewHelpers/NotificationsLogIndexViewHelper.php b/domains/Settings/ManageNotificationChannels/Web/ViewHelpers/NotificationsLogIndexViewHelper.php index 348176b44..d2dd6ea54 100644 --- a/domains/Settings/ManageNotificationChannels/Web/ViewHelpers/NotificationsLogIndexViewHelper.php +++ b/domains/Settings/ManageNotificationChannels/Web/ViewHelpers/NotificationsLogIndexViewHelper.php @@ -23,7 +23,7 @@ class NotificationsLogIndexViewHelper return [ 'channel' => [ 'id' => $channel->id, - 'type' => trans('app.notification_channel_type_'.$channel->type), + 'type' => trans('settings.notification_channel_type_'.$channel->type), 'label' => $channel->label, ], 'notifications' => $notificationsCollection, diff --git a/lang/en/app.php b/lang/en/app.php index 52b6b8d89..2e62e9950 100644 --- a/lang/en/app.php +++ b/lang/en/app.php @@ -93,5 +93,4 @@ return [ 'emotion_negative' => '😡 Negative', 'notification_channel_email' => 'My email', - 'notification_channel_type_email' => 'Email', ]; diff --git a/lang/en/email.php b/lang/en/email.php index b1061e657..66abe63d3 100644 --- a/lang/en/email.php +++ b/lang/en/email.php @@ -3,4 +3,9 @@ return [ 'notification_test_email' => 'Test email for Monica', 'notification_reminder_email' => 'Reminder for :name', + + // reminder triggered + 'reminder_triggered_intro' => 'You wanted to be reminded of the following:', + 'reminder_triggered_for' => 'for', + 'reminder_triggered_signature' => 'Have a great day', ]; diff --git a/lang/en/settings.php b/lang/en/settings.php index 79b19034e..ad847de83 100644 --- a/lang/en/settings.php +++ b/lang/en/settings.php @@ -50,6 +50,8 @@ return [ * NOTIFICATION CHANNELS **************************************************************/ + 'notification_channel_type_email' => 'Email', + 'notification_channel_type_telegram' => 'Telegram', 'notification_channels_title' => 'Configure how we should notify you', 'notification_channels_description' => 'You can be notified through different channels: emails, a Telegram message, on Facebook. You decide.', 'notification_channels_email_title' => 'Via email', @@ -77,6 +79,17 @@ return [ 'notification_channels_log_label' => 'Label:', 'notification_channels_log_help' => 'This page shows all the notifications that have been sent in this channel in the past. It primeraly serves as a way to debug in case you don’t receive the notification you’ve set up.', 'notification_channels_log_blank' => 'You haven’t received a notification in this channel yet.', + 'notification_channels_telegram_title' => 'Via Telegram', + 'notification_channels_telegram_cta' => 'Setup Telegram', + 'notification_channels_telegram_blank' => 'You haven’t setup Telegram yet.', + 'notification_channels_telegram_delete_confirm' => 'Are you sure? You can always add Telegram back later on if you want.', + 'notification_channels_telegram_not_set' => 'You have not setup Telegram in your environment variables yet.', + 'notification_channels_telegram_test_notification' => 'This is a test notification for :name', + 'notification_channels_telegram_test_notification_sent' => 'Notification sent', + 'notification_channels_telegram_destroy_success' => 'The Telegram channel has been deleted', + 'notification_channels_telegram_added' => 'The Telegram channel has been added', + 'notification_channels_telegram_linked' => 'Your account is linked', + 'notification_channels_test_success_telegram' => 'The notification has been sent', /*************************************************************** * USER MANAGEMENT diff --git a/lang/fr/app.php b/lang/fr/app.php index 43ccbfb88..8d72f2b15 100644 --- a/lang/fr/app.php +++ b/lang/fr/app.php @@ -93,5 +93,4 @@ return [ 'emotion_negative' => '😡 NĂ©gatif', 'notification_channel_email' => 'Mon courriel', - 'notification_channel_type_email' => 'Courriel', ]; diff --git a/lang/fr/settings.php b/lang/fr/settings.php index a20379b32..b980cd737 100644 --- a/lang/fr/settings.php +++ b/lang/fr/settings.php @@ -50,6 +50,8 @@ return [ * NOTIFICATION CHANNELS **************************************************************/ + 'notification_channel_type_email' => 'Courriel', + 'notification_channel_type_telegram' => 'Telegram', 'notification_channels_title' => 'Configurer comment nous devons vous notifier', 'notification_channels_description' => 'Vous pouvez ĂȘtre notifiĂ© Ă  travers plusieurs canaux : courriels, Telegram, Facebook. Vous dĂ©cidez.', 'notification_channels_email_title' => 'Par courriel', @@ -77,6 +79,17 @@ return [ 'notification_channels_log_label' => 'LibellĂ© :', 'notification_channels_log_help' => 'Cette page montre toutes les notifications qui ont Ă©tĂ© envoyĂ©s via ce canal par le passĂ©. Cela sert principalement comme une façon de dĂ©boguer dans le cas oĂč vous ne recevez pas les notifications que vous avez programmĂ©es.', 'notification_channels_log_blank' => 'Vous n’avez pas encore reçu de notifications dans ce canal.', + 'notification_channels_telegram_title' => 'Par Telegram', + 'notification_channels_telegram_cta' => 'Configurer Telegram', + 'notification_channels_telegram_blank' => 'Vous n’avez pas encore configurĂ© Telegram.', + 'notification_channels_telegram_delete_confirm' => 'Êtes-vous sĂ»r ? Vous pourrez toujours rajouter Telegram plus tard si vous le voulez.', + 'notification_channels_telegram_not_set' => 'Vous n’avez pas encore configurĂ© Telegram dans vos variables d’environnement.', + 'notification_channels_telegram_test_notification' => 'Ceci est une notification de test pour :name', + 'notification_channels_telegram_test_notification_sent' => 'Notification envoyĂ©e', + 'notification_channels_telegram_destroy_success' => 'Le canal Telegram a Ă©tĂ© supprimĂ©', + 'notification_channels_telegram_added' => 'Le canal Telegram a Ă©tĂ© ajoutĂ©', + 'notification_channels_telegram_linked' => 'Votre compte est liĂ©', + 'notification_channels_test_success_telegram' => 'La notification a Ă©tĂ© envoyĂ©e', /*************************************************************** * USER MANAGEMENT diff --git a/resources/js/Pages/Settings/Notifications/Index.vue b/resources/js/Pages/Settings/Notifications/Index.vue index b06e61c85..59702f24e 100644 --- a/resources/js/Pages/Settings/Notifications/Index.vue +++ b/resources/js/Pages/Settings/Notifications/Index.vue @@ -58,6 +58,9 @@ + + + @@ -70,6 +73,7 @@ import PrettySpan from '@/Shared/Form/PrettySpan'; import TextInput from '@/Shared/Form/TextInput'; import Errors from '@/Shared/Form/Errors'; import Emails from '@/Pages/Settings/Notifications/Partials/Emails'; +import Telegram from '@/Pages/Settings/Notifications/Partials/Telegram'; export default { components: { @@ -79,6 +83,7 @@ export default { TextInput, Errors, Emails, + Telegram, }, props: { diff --git a/resources/js/Pages/Settings/Notifications/Logs/Index.vue b/resources/js/Pages/Settings/Notifications/Logs/Index.vue index e074ebb61..324fc0850 100644 --- a/resources/js/Pages/Settings/Notifications/Logs/Index.vue +++ b/resources/js/Pages/Settings/Notifications/Logs/Index.vue @@ -54,7 +54,7 @@ -
  • {{ $t('settings.breadcrumb_settings_notification_channels_log_details') }}
  • +
  • {{ $t('app.breadcrumb_settings_notification_channels_log_details') }}
  • diff --git a/resources/js/Pages/Settings/Notifications/Partials/Emails.vue b/resources/js/Pages/Settings/Notifications/Partials/Emails.vue index 87a80f2cf..436214d6e 100644 --- a/resources/js/Pages/Settings/Notifications/Partials/Emails.vue +++ b/resources/js/Pages/Settings/Notifications/Partials/Emails.vue @@ -23,9 +23,9 @@ select {