diff --git a/app/Http/Controllers/Admin/HomeController.php b/app/Http/Controllers/Admin/HomeController.php index 722dc2b575..bbea3d0f15 100644 --- a/app/Http/Controllers/Admin/HomeController.php +++ b/app/Http/Controllers/Admin/HomeController.php @@ -75,8 +75,9 @@ class HomeController extends Controller foreach (config('firefly.admin_notifications') as $item) { $notifications[$item] = FireflyConfig::get(sprintf('notification_%s', $item), true)->data; } + $slackUrl = FireflyConfig::get('slack_webhook_url', '')->data; - return view('admin.index', compact('title', 'mainTitleIcon', 'email', 'notifications')); + return view('admin.index', compact('title', 'mainTitleIcon', 'email', 'notifications', 'slackUrl')); } public function notifications(Request $request): RedirectResponse @@ -86,7 +87,14 @@ class HomeController extends Controller if ($request->has(sprintf('notification_%s', $item))) { $value = true; } - FireflyConfig::set(sprintf('notification_%s',$item), $value); + FireflyConfig::set(sprintf('notification_%s', $item), $value); + } + $url = (string) $request->get('slackUrl'); + if ('' === $url) { + FireflyConfig::delete('slack_webhook_url'); + } + if (str_starts_with($url, 'https://hooks.slack.com/services/')) { + FireflyConfig::set('slack_webhook_url', $url); } session()->flash('success', (string) trans('firefly.notification_settings_saved')); diff --git a/app/Http/Controllers/PreferencesController.php b/app/Http/Controllers/PreferencesController.php index b99dd19535..18e0a6d45b 100644 --- a/app/Http/Controllers/PreferencesController.php +++ b/app/Http/Controllers/PreferencesController.php @@ -101,6 +101,7 @@ class PreferencesController extends Controller $languages = config('firefly.languages'); $locale = app('preferences')->get('locale', config('firefly.default_locale', 'equal'))->data; $listPageSize = app('preferences')->get('listPageSize', 50)->data; + $slackUrl = app('preferences')->get('slack_webhook_url', '')->data; $customFiscalYear = app('preferences')->get('customFiscalYear', 0)->data; $fiscalYearStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data; $fiscalYearStart = date('Y') . '-' . $fiscalYearStartStr; @@ -139,6 +140,7 @@ class PreferencesController extends Controller 'frontPageAccounts', 'languages', 'notifications', + 'slackUrl', 'locales', 'locale', 'tjOptionalFields', @@ -173,12 +175,12 @@ class PreferencesController extends Controller // extract notifications: $all = $request->all(); - foreach(config('firefly.available_notifications') as $option) { + foreach (config('firefly.available_notifications') as $option) { $key = sprintf('notification_%s', $option); - if(array_key_exists($key, $all)) { + if (array_key_exists($key, $all)) { app('preferences')->set($key, true); } - if(!array_key_exists($key, $all)) { + if (!array_key_exists($key, $all)) { app('preferences')->set($key, false); } } @@ -190,6 +192,16 @@ class PreferencesController extends Controller session()->forget('end'); session()->forget('range'); + + // slack URL: + $url = (string) $request->get('slackUrl'); + if(str_starts_with($url, 'https://hooks.slack.com/services/')){ + app('preferences')->set('slack_webhook_url', $url); + } + if('' === $url) { + app('preferences')->delete('slack_webhook_url'); + } + // custom fiscal year $customFiscalYear = 1 === (int) $request->get('customFiscalYear'); $string = strtotime((string) $request->get('fiscalYearStart')); diff --git a/app/Notifications/Admin/TestNotification.php b/app/Notifications/Admin/TestNotification.php index 16d001b6a0..f0e1948a70 100644 --- a/app/Notifications/Admin/TestNotification.php +++ b/app/Notifications/Admin/TestNotification.php @@ -25,6 +25,7 @@ namespace FireflyIII\Notifications\Admin; use FireflyIII\Mail\AdminTestMail; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\MailMessage; +use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; /** @@ -54,7 +55,7 @@ class TestNotification extends Notification */ public function via($notifiable) { - return ['mail']; + return ['mail', 'slack']; } /** @@ -69,6 +70,16 @@ class TestNotification extends Notification ->markdown('emails.admin-test', ['email' => $this->address]) ->subject((string) trans('email.admin_test_subject')); } + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * @return SlackMessage + */ + public function toSlack($notifiable) + { + return (new SlackMessage)->content((string)trans('email.admin_test_subject')); + } /** * Get the array representation of the notification. diff --git a/app/Notifications/Admin/UserRegistration.php b/app/Notifications/Admin/UserRegistration.php index edfe77a3a1..96978277c2 100644 --- a/app/Notifications/Admin/UserRegistration.php +++ b/app/Notifications/Admin/UserRegistration.php @@ -25,8 +25,12 @@ namespace FireflyIII\Notifications\Admin; use FireflyIII\User; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\MailMessage; +use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; +/** + * Class UserRegistration + */ class UserRegistration extends Notification { use Queueable; @@ -46,18 +50,18 @@ class UserRegistration extends Notification /** * Get the notification's delivery channels. * - * @param mixed $notifiable + * @param mixed $notifiable * @return array */ public function via($notifiable) { - return ['mail']; + return ['mail', 'slack']; } /** * Get the mail representation of the notification. * - * @param mixed $notifiable + * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) @@ -67,10 +71,21 @@ class UserRegistration extends Notification ->subject((string) trans('email.registered_subject_admin')); } + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * @return SlackMessage + */ + public function toSlack($notifiable) + { + return (new SlackMessage)->content((string) trans('email.admin_new_user_registered', ['email' => $this->user->email, 'id' => $this->user->id])); + } + /** * Get the array representation of the notification. * - * @param mixed $notifiable + * @param mixed $notifiable * @return array */ public function toArray($notifiable) diff --git a/app/Notifications/Admin/VersionCheckResult.php b/app/Notifications/Admin/VersionCheckResult.php index edf1998d09..2dd5f01ee5 100644 --- a/app/Notifications/Admin/VersionCheckResult.php +++ b/app/Notifications/Admin/VersionCheckResult.php @@ -22,9 +22,9 @@ declare(strict_types=1); namespace FireflyIII\Notifications\Admin; -use FireflyIII\Models\Bill; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\MailMessage; +use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; /** @@ -35,7 +35,7 @@ class VersionCheckResult extends Notification { use Queueable; - private string $message; + private string $message; /** * Create a new notification instance. @@ -55,7 +55,7 @@ class VersionCheckResult extends Notification */ public function via($notifiable) { - return ['mail']; + return ['mail', 'slack']; } /** @@ -69,7 +69,21 @@ class VersionCheckResult extends Notification return (new MailMessage) ->markdown('emails.new-version', ['message' => $this->message]) - ->subject((string)trans('email.new_version_email_subject')); + ->subject((string) trans('email.new_version_email_subject')); + } + + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * @return SlackMessage + */ + public function toSlack($notifiable) + { + return (new SlackMessage)->content($this->message) + ->attachment(function ($attachment) { + $attachment->title('Firefly III @ GitHub', 'https://github.com/firefly-iii/firefly-iii/releases'); + }); } /** diff --git a/app/Notifications/User/BillReminder.php b/app/Notifications/User/BillReminder.php index 0e72655c5f..38129abfa0 100644 --- a/app/Notifications/User/BillReminder.php +++ b/app/Notifications/User/BillReminder.php @@ -25,6 +25,7 @@ namespace FireflyIII\Notifications\User; use FireflyIII\Models\Bill; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\MailMessage; +use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; /** @@ -58,7 +59,7 @@ class BillReminder extends Notification */ public function via($notifiable) { - return ['mail']; + return ['mail', 'slack']; } /** @@ -79,6 +80,28 @@ class BillReminder extends Notification ->subject($subject); } + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * @return SlackMessage + */ + public function toSlack($notifiable) + { + $message = (string) trans(sprintf('email.bill_warning_subject_%s', $this->field), ['diff' => $this->diff, 'name' => $this->bill->name]); + if (0 === $this->diff) { + $message = (string) trans(sprintf('email.bill_warning_subject_now_%s', $this->field), ['diff' => $this->diff, 'name' => $this->bill->name]); + } + $bill = $this->bill; + $url = route('bills.show', [$bill->id]); + return (new SlackMessage) + ->warning() + ->attachment(function ($attachment) use ($bill, $url) { + $attachment->title((string) trans('firefly.visit_bill', ['name' => $bill->name]), $url); + }) + ->content($message); + } + /** * Get the array representation of the notification. * diff --git a/app/User.php b/app/User.php index bc8d2034be..67e4801820 100644 --- a/app/User.php +++ b/app/User.php @@ -48,6 +48,9 @@ use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\UserGroup; use FireflyIII\Models\Webhook; +use FireflyIII\Notifications\Admin\TestNotification; +use FireflyIII\Notifications\Admin\UserRegistration; +use FireflyIII\Notifications\Admin\VersionCheckResult; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; @@ -578,4 +581,25 @@ class User extends Authenticatable }; } + /** + * Route notifications for the Slack channel. + * + * @param Notification $notification + * @return string + */ + public function routeNotificationForSlack(Notification $notification): string + { + // this check does not validate if the user is owner, Should be done by notification itself. + if ($notification instanceof TestNotification) { + return app('fireflyconfig')->get('slack_webhook_url', '')->data; + } + if ($notification instanceof UserRegistration) { + return app('fireflyconfig')->get('slack_webhook_url', '')->data; + } + if ($notification instanceof VersionCheckResult) { + return app('fireflyconfig')->get('slack_webhook_url', '')->data; + } + return app('preferences')->getForUser($this, 'slack_webhook_url', '')->data; + } + } diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index e18b4bb09f..97d39d4b18 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -1051,6 +1051,10 @@ return [ 'pref_notification_user_login' => 'Alert when you login from a new location', 'pref_notifications' => 'Notifications', 'pref_notifications_help' => 'Indicate if these are notifications you would like to get. Some notifications may contain sensitive financial information.', + 'slack_webhook_url' => 'Slack Webhook URL', + 'slack_webhook_url_help' => 'If you want Firefly III to notify you using Slack, enter the webhook URL here. Otherwise leave the field blank. If you are an admin, you need to set this URL in the administration as well.', + 'slack_url_label' => 'Slack "incoming webhook" URL', + // profile: 'delete_stuff_header' => 'Delete data', 'permanent_delete_stuff' => 'Be careful with these buttons. Deleting stuff is permanent.', @@ -1349,6 +1353,7 @@ return [ // bills: 'not_expected_period' => 'Not expected this period', 'not_or_not_yet' => 'Not (yet)', + 'visit_bill' => 'Visit bill ":name" at Firefly III', 'match_between_amounts' => 'Bill matches transactions between :low and :high.', 'running_again_loss' => 'Previously linked transactions to this bill may lose their connection, if they (no longer) match the rule(s).', 'bill_related_rules' => 'Rules related to this bill', @@ -1978,7 +1983,7 @@ return [ 'delete_user' => 'Delete user :email', 'user_deleted' => 'The user has been deleted', 'send_test_email' => 'Send test email message', - 'send_test_email_text' => 'To see if your installation is capable of sending email, please press this button. You will not see an error here (if any), the log files will reflect any errors. You can press this button as many times as you like. There is no spam control. The message will be sent to :email and should arrive shortly.', + 'send_test_email_text' => 'To see if your installation is capable of sending email or posting Slack messages, please press this button. You will not see an error here (if any), the log files will reflect any errors. You can press this button as many times as you like. There is no spam control. The message will be sent to :email and should arrive shortly.', 'send_message' => 'Send message', 'send_test_triggered' => 'Test was triggered. Check your inbox and the log files.', 'give_admin_careful' => 'Users who are given admin rights can take away yours. Be careful.', @@ -1986,9 +1991,10 @@ return [ 'admin_maintanance_expl' => 'Some nifty buttons for Firefly III maintenance', 'admin_maintenance_clear_cache' => 'Clear cache', 'admin_notifications' => 'Admin notifications', - 'admin_notifications_expl' => 'The following notifications can be enabled or disabled by the administrator.', + 'admin_notifications_expl' => 'The following notifications can be enabled or disabled by the administrator. If you want to get these messages over Slack as well, set the "incoming webhook" URL.', 'admin_notification_check_user_new_reg' => 'User gets post-registration welcome message', 'admin_notification_check_admin_new_reg' => 'Administrator(s) get new user registration notification', + 'admin_notification_check_new_version' => 'A new version is available', 'save_notification_settings' => 'Save settings', 'notification_settings_saved' => 'The notification settings have been saved', diff --git a/resources/views/admin/index.twig b/resources/views/admin/index.twig index f045d1bf33..2d5b3e44b1 100644 --- a/resources/views/admin/index.twig +++ b/resources/views/admin/index.twig @@ -47,6 +47,7 @@ {% endfor %} + {{ ExpandedForm.text('slackUrl', slackUrl, {'label' : 'slack_url_label'|_}) }} +
+
+

{{ 'slack_webhook_url'|_ }}

+

{{ 'slack_webhook_url_help'|_ }}

+ {{ ExpandedForm.text('slackUrl',slackUrl,{'label' : 'slack_url_label'|_}) }} +
+