Expand UI for notifications.

This commit is contained in:
James Cole
2024-12-07 08:05:51 +01:00
parent 1220564f30
commit 26948a058a
13 changed files with 2834 additions and 2622 deletions

View File

@@ -67,22 +67,24 @@ class HomeController extends Controller
// admin notification settings:
$notifications = [];
foreach (config('firefly.admin_notifications') as $item) {
$notifications[$item] = app('fireflyconfig')->get(sprintf('notification_%s', $item), true)->data;
foreach (config('notifications.notifications.owner') as $key => $info) {
if($info['enabled']) {
$notifications[$key] = app('fireflyconfig')->get(sprintf('notification_%s', $key), true)->data;
}
$slackUrl = app('fireflyconfig')->get('slack_webhook_url', '')->data;
}
//
return view('admin.index', compact('title', 'mainTitleIcon', 'email', 'notifications', 'slackUrl'));
return view('admin.index', compact('title', 'mainTitleIcon', 'email', 'notifications'));
}
public function notifications(Request $request): RedirectResponse
{
foreach (config('firefly.admin_notifications') as $item) {
foreach (config('notifications.notifications.owner') as $key => $info) {
$value = false;
if ($request->has(sprintf('notification_%s', $item))) {
if ($request->has(sprintf('notification_%s', $key))) {
$value = true;
}
app('fireflyconfig')->set(sprintf('notification_%s', $item), $value);
app('fireflyconfig')->set(sprintf('notification_%s', $key), $value);
}
$url = (string)$request->get('slackUrl');
if ('' === $url) {

View File

@@ -0,0 +1,44 @@
<?php
/*
* NotificationController.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Admin;
use FireflyIII\Http\Controllers\Controller;
use Illuminate\Support\Facades\Log;
class NotificationController extends Controller
{
public function index()
{
Log::channel('audit')->info('User visits notifications index.');
$title = (string) trans('firefly.administration');
$mainTitleIcon = 'fa-hand-spock-o';
$subTitle = (string) trans('firefly.title_owner_notifications');
$subTitleIcon = 'envelope-o';
$slackUrl = app('fireflyconfig')->get('slack_webhook_url', '')->data;
$discordUrl = app('fireflyconfig')->get('discord_webhook_url', '')->data;
$channels = config('notifications.channels');
return view('admin.notifications.index', compact('title', 'subTitle', 'mainTitleIcon', 'subTitleIcon', 'channels', 'slackUrl','discordUrl'));
}
}

View File

@@ -111,6 +111,7 @@ class PreferencesController extends Controller
// notification preferences (single value for each):
$notifications = [];
die('fix the reference to the available notifications.');
foreach (config('firefly.available_notifications') as $notification) {
$notifications[$notification] = app('preferences')->get(sprintf('notification_%s', $notification), true)->data;
}
@@ -165,6 +166,7 @@ class PreferencesController extends Controller
// extract notifications:
$all = $request->all();
die('fix the reference to the available notifications.');
foreach (config('firefly.available_notifications') as $option) {
$key = sprintf('notification_%s', $option);
if (array_key_exists($key, $all)) {

View File

@@ -147,9 +147,7 @@ return [
'update_endpoint' => 'https://version.firefly-iii.org/index.json',
'update_minimum_age' => 7,
// notifications
'available_notifications' => ['bill_reminder', 'new_access_token', 'transaction_creation', 'user_login', 'rule_action_failures'],
'admin_notifications' => ['admin_new_reg', 'user_new_reg', 'new_version', 'invite_created', 'invite_redeemed'],
// enabled languages
'languages' => [

54
config/notifications.php Normal file
View File

@@ -0,0 +1,54 @@
<?php
/*
* notifications.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
return [
'channels' => [
'email' => ['enabled' => true, 'ui_configurable' => 0,],
'slack' => ['enabled' => true, 'ui_configurable' => 1,],
'discord' => ['enabled' => true, 'ui_configurable' => 1,],
'nfty' => ['enabled' => false, 'ui_configurable' => 0,],
'pushover' => ['enabled' => false, 'ui_configurable' => 0,],
'gotify' => ['enabled' => false, 'ui_configurable' => 0,],
'pushbullet' => ['enabled' => false, 'ui_configurable' => 0,],
],
'notifications' => [
'user' => [
'some_notification' => [
'enabled' => true,
'email' => '',
'slack' => '',
],
],
'owner' => [
//'invitation_created' => ['enabled' => true],
// 'some_notification' => ['enabled' => true],
'admin_new_reg' => ['enabled' => true],
'user_new_reg' => ['enabled' => true],
'new_version' => ['enabled' => true],
'invite_created' => ['enabled' => true],
'invite_redeemed' => ['enabled' => true],
],
],
// // notifications
// 'available_notifications' => ['bill_reminder', 'new_access_token', 'transaction_creation', 'user_login', 'rule_action_failures'],
// 'admin_notifications' => ['admin_new_reg', 'user_new_reg', 'new_version', 'invite_created', 'invite_redeemed'],
];

View File

@@ -86,4 +86,7 @@ return [
'mfa_enableMFA' => 'Enable multi-factor authentication',
'mfa_backup_codes' => 'Backup codes',
'mfa_disableMFA' => 'Disable multi-factor authentication',
// notifications
'notification_index' => 'Owner notifications',
];

View File

@@ -1382,6 +1382,7 @@ return [
'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',
'discord_url_label' => 'Discord webhook URL',
// Financial administrations
'administration_index' => 'Financial administration',
@@ -1909,6 +1910,8 @@ return [
'select_at_least_one_tag' => 'Please select at least one tag',
'select_at_least_one_expense' => 'Please select at least one combination of expense/revenue accounts. If you have none (the list is empty) this report is not available.',
'account_default_currency' => 'This will be the default currency associated with this account.',
'piggy_default_currency' => 'Piggy banks can only save money in a single currency.',
'piggy_account_currency_match' => 'Only accounts that use the previously selected currency will be accepted.',
'reconcile_has_more' => 'Your Firefly III ledger has more money in it than your bank claims you should have. There are several options. Please choose what to do. Then, press "Confirm reconciliation".',
'reconcile_has_less' => 'Your Firefly III ledger has less money in it than your bank claims you should have. There are several options. Please choose what to do. Then, press "Confirm reconciliation".',
'reconcile_is_equal' => 'Your Firefly III ledger and your bank statements match. There is nothing to do. Please press "Confirm reconciliation" to confirm your input.',
@@ -2477,16 +2480,33 @@ return [
'admin_maintanance_title' => 'Maintenance',
'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. 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',
'admin_notification_check_invite_created' => 'A user is invited to Firefly III',
'admin_notification_check_invite_redeemed' => 'A user invitation is redeemed',
'owner_notifications' => 'Admin notifications',
'owner_notifications_expl' => 'The following notifications can be enabled or disabled by the administrator. It will be sent over ALL configured channels. Some channels are configured in your environment variables, others can be set in your <a href="#">notifications settings</a>.',
'settings_notifications' => 'Settings for notifications',
'title_owner_notifications' => 'Owner notifications',
'owner_notification_check_user_new_reg' => 'User gets post-registration welcome message',
'owner_notification_check_admin_new_reg' => 'Administrator(s) get new user registration notification',
'owner_notification_check_new_version' => 'A new version is available',
'owner_notification_check_invite_created' => 'A user is invited to Firefly III',
'owner_notification_check_invite_redeemed' => 'A user invitation is redeemed',
'all_invited_users' => 'All invited users',
'save_notification_settings' => 'Save settings',
'notification_settings' => 'Settings for notifications',
'notification_settings_saved' => 'The notification settings have been saved',
'available_channels_title' => 'Available channels',
'available_channels_expl' => 'These channels are available to send notifications over. To test your confiuration, use the buttons below. Please note that the buttons have no spam control.',
'notification_channel_name_email' => 'Email',
'notification_channel_name_slack' => 'Slack',
'notification_channel_name_discord' => 'Discord',
'notification_channel_name_nfty' => 'Nfty',
'notification_channel_name_pushover' => 'Pushover',
'notification_channel_name_gotify' => 'Gotify',
'notification_channel_name_pushbullet' => 'Pushbullet',
'channel_not_available' => 'not available yet',
'configure_channel_in_env' => 'needs environment variables',
'test_notification_channel_name_email' => 'Test email',
'test_notification_channel_name_slack' => 'Test Slack',
'test_notification_channel_name_discord' => 'Test Discord',
'split_transaction_title' => 'Description of the split transaction',
'split_transaction_title_help' => 'If you create a split transaction, there must be a global description for all splits of the transaction.',

View File

@@ -17,6 +17,7 @@
</li>
<li><a href="{{ route('admin.links.index') }}">{{ 'journal_link_configuration'|_ }}</a></li>
<li><a href="{{ route('admin.update-check') }}">{{ 'update_check_title'|_ }}</a></li>
<li><a href="{{ route('admin.notifications') }}">{{ 'settings_notifications'|_ }}</a></li>
</ul>
</div>
</div>
@@ -34,20 +35,20 @@
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title">{{ 'admin_notifications'|_ }}</h3>
<h3 class="box-title">{{ 'owner_notifications'|_ }}</h3>
</div>
<div class="box-body">
<p>
{{ 'admin_notifications_expl'|_ }}
{{ 'owner_notifications_expl'|_ }}
</p>
{% for notification, value in notifications %}
<div class="checkbox">
<label>
<input value="1" {% if true == value %}checked{% endif %} type="checkbox" name="notification_{{ notification }}"> {{ trans('firefly.admin_notification_check_'~notification) }}
<input value="1" {% if true == value %}checked{% endif %} type="checkbox" name="notification_{{ notification }}"> {{ trans('firefly.owner_notification_check_'~notification) }}
</label>
</div>
{% endfor %}
{{ ExpandedForm.text('slackUrl', slackUrl, {'label' : 'slack_url_label'|_}) }}
{# {{ ExpandedForm.text('slackUrl', slackUrl, {'label' : 'slack_url_label'|_}) }} #}
</div>
<div class="box-footer">
<button type="submit" class="btn btn-success">

View File

@@ -0,0 +1,68 @@
{% extends './layout/default' %}
{% block breadcrumbs %}
{{ Breadcrumbs.render }}
{% endblock %}
{% block content %}
<div class="row" xmlns="http://www.w3.org/1999/html">
<div class="col-lg-6 col-md-12 col-sm-12 col-xs-12">
<form action="{{ route('admin.notification.post') }}" method="post">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title">{{ 'notification_settings'|_ }}</h3>
</div>
<div class="box-body">
{{ ExpandedForm.text('slackUrl', slackUrl, {'label' : 'slack_url_label'|_}) }}
{{ ExpandedForm.text('discordUrl', discordUrl, {'label' : 'discord_url_label'|_}) }}
</div>
<div class="box-footer">
<button type="submit" class="btn btn-success">
<span class="fa fa-check-circle"></span> {{ ('save_notification_settings')|_ }}
</button>
</div>
</div>
</form>
</div>
<form action="{{ route('admin.notification.test') }}" method="post">
<div class="col-lg-6 col-md-12 col-sm-12 col-xs-12">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title">{{ 'available_channels_title'|_ }}</h3>
</div>
<div class="box-body">
<p>
{{ 'available_channels_expl'|_ }}
</p>
<ul>
{% for name,info in channels %}
<li>
{% if info.enabled %}
☑️ {{ trans('firefly.notification_channel_name_'~name) }}
{% if 0 == info.ui_configurable %}({{ 'configure_channel_in_env'|_ }}) {% endif %}
{% endif %}
{% if not info.enabled %}
⚠️ {{ trans('firefly.notification_channel_name_'~name) }} ({{ 'channel_not_available'|_ }})
{% endif %}
</li>
{% endfor %}
</ul>
</div>
<div class="box-footer">
<div class="btn-group">
{% for name,info in channels %}
{% if info.enabled %}
<button type="submit" name="test_submit" value="{{ name }}" class="btn btn-default">
{{ trans('firefly.test_notification_channel_name_'~name) }}
</button>
{% endif %}
{% endfor %}
</div>
</div>
</div>
</div>
</form>
</div>
{% endblock %}

View File

@@ -2,7 +2,7 @@
<label for="{{ options.id }}" class="col-sm-4 control-label">{{ label }}</label>
<div class="col-sm-8">
{{ Html.select(name~"[]", list, selected).id(options.id).class('form-control').attribute('multiple').attribute('autocomplete','off').attribute('spellcheck','false').attribute('placeholder', options.placeholder) }}
{{ Html.multiselect(name~"[]", list, selected).id(options.id).class('form-control').attribute('autocomplete','off').attribute('spellcheck','false').attribute('placeholder', options.placeholder) }}
{% include 'form.help' %}
{% include 'form.feedback' %}

View File

@@ -56,7 +56,13 @@
{% endif %}
{# SINGLE INFO MESSAGE #}
{% if session('info') is not iterable %}
{% if session_has('info_url') %}
<a href="{{ session('info_url') }}">
{% endif %}
<strong>{{ 'flash_info'|_ }}:</strong> {{ session('info')|raw }}
{% if session_has('info_url') %}
</a>
{% endif %}
{% endif %}
</div>

View File

@@ -179,6 +179,15 @@ Breadcrumbs::for(
}
);
Breadcrumbs::for(
'admin.notification.index',
static function (Generator $breadcrumbs): void {
$breadcrumbs->parent('home');
$breadcrumbs->push(trans('firefly.administration'), route('admin.index'));
$breadcrumbs->push(trans('breadcrumbs.notification_index'), route('admin.notification.index'));
}
);
Breadcrumbs::for(
'admin.users',
static function (Generator $breadcrumbs): void {

View File

@@ -1398,6 +1398,11 @@ Route::group(
// FF configuration:
Route::get('configuration', ['uses' => 'ConfigurationController@index', 'as' => 'configuration.index']);
Route::post('configuration', ['uses' => 'ConfigurationController@postIndex', 'as' => 'configuration.index.post']);
// routes for notifications settings.
Route::get('notifications', ['uses' => 'NotificationController@index', 'as' => 'notification.index']);
Route::post('notifications', ['uses' => 'NotificationController@postIndex', 'as' => 'notification.post']);
Route::post('notifications/test', ['uses' => 'NotificationController@testNotification', 'as' => 'notification.test']);
}
);