mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-15 16:57:09 +00:00
Fix spam whoopsie.
This commit is contained in:
@@ -6,12 +6,13 @@ namespace FireflyIII\Events\Model\Bill;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class WarnUserAboutOverdueSubscription extends Event
|
||||
class WarnUserAboutOverdueSubscriptions extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(public Bill $bill, public array $dates) {}
|
||||
public function __construct(public User $user, public array $overdue) {}
|
||||
|
||||
}
|
@@ -26,9 +26,10 @@ namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutBill;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutOverdueSubscription;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutOverdueSubscriptions;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Notifications\User\BillReminder;
|
||||
use FireflyIII\Notifications\User\SubscriptionOverdueReminder;
|
||||
use FireflyIII\Notifications\User\SubscriptionsOverdueReminder;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
@@ -38,47 +39,65 @@ use Illuminate\Support\Facades\Notification;
|
||||
*/
|
||||
class BillEventHandler
|
||||
{
|
||||
public function warnAboutOverdueSubscription(WarnUserAboutOverdueSubscription $event): void
|
||||
public function warnAboutOverdueSubscriptions(WarnUserAboutOverdueSubscriptions $event): void
|
||||
{
|
||||
$bill = $event->bill;
|
||||
$dates = $event->dates;
|
||||
|
||||
$key = sprintf('bill_overdue_%s_%s', $bill->id, substr(hash('sha256', json_encode($dates['pay_dates'], JSON_THROW_ON_ERROR)), 0, 10));
|
||||
$pref = Preferences::getForUser($bill->user, $key, false);
|
||||
if (true === $pref->data) {
|
||||
Log::debug(sprintf('User %s has already been warned about overdue subscription %s.', $bill->user->id, $bill->id));
|
||||
|
||||
return;
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
// make sure user does not get the warning twice.
|
||||
$overdue = $event->overdue;
|
||||
$user = $event->user;
|
||||
$toBeWarned = [];
|
||||
Log::debug(sprintf('%d bills to warn about.', count($overdue)));
|
||||
foreach ($overdue as $item) {
|
||||
/** @var Bill $bill */
|
||||
$bill = $item['bill'];
|
||||
$key = sprintf('bill_overdue_%s_%s', $bill->id, substr(hash('sha256', json_encode($item['dates']['pay_dates'], JSON_THROW_ON_ERROR)), 0, 10));
|
||||
$pref = Preferences::getForUser($bill->user, $key, false);
|
||||
if (true === $pref->data) {
|
||||
Log::debug(sprintf('User #%d has already been warned about overdue subscription #%d.', $bill->user->id, $bill->id));
|
||||
continue;
|
||||
}
|
||||
$toBeWarned[] = $item;
|
||||
}
|
||||
unset($bill);
|
||||
Log::debug(sprintf('Now %d bills to warn about.', count($toBeWarned)));
|
||||
|
||||
/** @var bool $sendNotification */
|
||||
$sendNotification = Preferences::getForUser($bill->user, 'notification_bill_reminder', true)->data;
|
||||
|
||||
if (true === $sendNotification) {
|
||||
Log::debug('Will warning about overdue subscription.');
|
||||
Preferences::setForUser($bill->user, $key, true);
|
||||
|
||||
try {
|
||||
Notification::send($bill->user, new SubscriptionOverdueReminder($bill, $dates));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
|
||||
$sendNotification = Preferences::getForUser($user, 'notification_bill_reminder', true)->data;
|
||||
if (false === $sendNotification) {
|
||||
Log::debug('User has disabled bill reminders.');
|
||||
return;
|
||||
}
|
||||
Log::debug('User has disabled bill reminders.');
|
||||
Log::debug(sprintf('Will warning about %d overdue subscription(s).', count($toBeWarned)));
|
||||
if (0 === count($toBeWarned)) {
|
||||
Log::debug('No overdue subscriptions to warn about.');
|
||||
return;
|
||||
}
|
||||
foreach ($toBeWarned as $item) {
|
||||
/** @var Bill $bill */
|
||||
$bill = $item['bill'];
|
||||
$key = sprintf('bill_overdue_%s_%s', $bill->id, substr(hash('sha256', json_encode($item['dates']['pay_dates'], JSON_THROW_ON_ERROR)), 0, 10));
|
||||
Preferences::setForUser($bill->user, $key, true);
|
||||
}
|
||||
Log::warning('should hit this ONCE');
|
||||
try {
|
||||
Notification::send($user, new SubscriptionsOverdueReminder($overdue));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function warnAboutBill(WarnUserAboutBill $event): void
|
||||
|
@@ -26,10 +26,11 @@ namespace FireflyIII\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutBill;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutOverdueSubscription;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutOverdueSubscriptions;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Support\Facades\Navigation;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\SubscriptionEnrichment;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
@@ -55,12 +56,12 @@ class WarnAboutBills implements ShouldQueue
|
||||
*/
|
||||
public function __construct(?Carbon $date)
|
||||
{
|
||||
$newDate = new Carbon();
|
||||
$newDate = new Carbon();
|
||||
$newDate->startOfDay();
|
||||
$this->date = $newDate;
|
||||
$this->date = $newDate;
|
||||
|
||||
if ($date instanceof Carbon) {
|
||||
$newDate = clone $date;
|
||||
$newDate = clone $date;
|
||||
$newDate->startOfDay();
|
||||
$this->date = $newDate;
|
||||
}
|
||||
@@ -76,28 +77,29 @@ class WarnAboutBills implements ShouldQueue
|
||||
public function handle(): void
|
||||
{
|
||||
Log::debug(sprintf('Now at start of WarnAboutBills() job for %s.', $this->date->format('D d M Y')));
|
||||
$bills = Bill::all();
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
Log::debug(sprintf('Now checking bill #%d ("%s")', $bill->id, $bill->name));
|
||||
$dates = $this->getDates($bill);
|
||||
if ($this->needsOverdueAlert($dates)) {
|
||||
$this->sendOverdueAlert($bill, $dates);
|
||||
}
|
||||
if ($this->hasDateFields($bill)) {
|
||||
if ($this->needsWarning($bill, 'end_date')) {
|
||||
$this->sendWarning($bill, 'end_date');
|
||||
foreach (User::all() as $user) {
|
||||
$bills = $user->bills()->where('active', true)->get();
|
||||
$overdue = [];
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
Log::debug(sprintf('Now checking bill #%d ("%s")', $bill->id, $bill->name));
|
||||
$dates = $this->getDates($bill);
|
||||
if ($this->needsOverdueAlert($dates)) {
|
||||
$overdue[] = ['bill' => $bill, 'dates' => $dates];
|
||||
}
|
||||
if ($this->needsWarning($bill, 'extension_date')) {
|
||||
$this->sendWarning($bill, 'extension_date');
|
||||
if ($this->hasDateFields($bill)) {
|
||||
if ($this->needsWarning($bill, 'end_date')) {
|
||||
$this->sendWarning($bill, 'end_date');
|
||||
}
|
||||
if ($this->needsWarning($bill, 'extension_date')) {
|
||||
$this->sendWarning($bill, 'extension_date');
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->sendOverdueAlerts($user, $overdue);
|
||||
}
|
||||
Log::debug('Done with handle()');
|
||||
|
||||
// clear cache:
|
||||
app('preferences')->mark();
|
||||
}
|
||||
|
||||
private function hasDateFields(Bill $bill): bool
|
||||
@@ -148,7 +150,7 @@ class WarnAboutBills implements ShouldQueue
|
||||
|
||||
public function setDate(Carbon $date): void
|
||||
{
|
||||
$newDate = clone $date;
|
||||
$newDate = clone $date;
|
||||
$newDate->startOfDay();
|
||||
$this->date = $newDate;
|
||||
}
|
||||
@@ -168,7 +170,7 @@ class WarnAboutBills implements ShouldQueue
|
||||
$enrichment->setUser($bill->user);
|
||||
$enrichment->setStart($start);
|
||||
$enrichment->setEnd($end);
|
||||
$single = $enrichment->enrichSingle($bill);
|
||||
$single = $enrichment->enrichSingle($bill);
|
||||
|
||||
return [
|
||||
'pay_dates' => $single->meta['pay_dates'] ?? [],
|
||||
@@ -178,7 +180,7 @@ class WarnAboutBills implements ShouldQueue
|
||||
|
||||
private function needsOverdueAlert(array $dates): bool
|
||||
{
|
||||
$count = count($dates['pay_dates']) - count($dates['paid_dates']);
|
||||
$count = count($dates['pay_dates']) - count($dates['paid_dates']);
|
||||
if (0 === $count || 0 === count($dates['pay_dates'])) {
|
||||
return false;
|
||||
}
|
||||
@@ -186,7 +188,7 @@ class WarnAboutBills implements ShouldQueue
|
||||
$earliest = new Carbon($dates['pay_dates'][0]);
|
||||
$earliest->startOfDay();
|
||||
Log::debug(sprintf('Earliest expected pay date is %s', $earliest->toAtomString()));
|
||||
$diff = $earliest->diffInDays($this->date);
|
||||
$diff = $earliest->diffInDays($this->date);
|
||||
Log::debug(sprintf('Difference in days is %s', $diff));
|
||||
if ($diff < 2) {
|
||||
return false;
|
||||
@@ -195,9 +197,11 @@ class WarnAboutBills implements ShouldQueue
|
||||
return true;
|
||||
}
|
||||
|
||||
private function sendOverdueAlert(Bill $bill, array $dates): void
|
||||
private function sendOverdueAlerts(User $user, array $overdue): void
|
||||
{
|
||||
Log::debug('Will now send warning about overdue bill.');
|
||||
event(new WarnUserAboutOverdueSubscription($bill, $dates));
|
||||
if (count($overdue) > 0) {
|
||||
Log::debug(sprintf('Will now send warning about overdue bill for user #%d.', $user->id));
|
||||
event(new WarnUserAboutOverdueSubscriptions($user, $overdue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Notifications\User;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Notifications\ReturnsAvailableChannels;
|
||||
use FireflyIII\Notifications\ReturnsSettings;
|
||||
use FireflyIII\User;
|
||||
@@ -15,11 +14,13 @@ use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use NotificationChannels\Pushover\PushoverMessage;
|
||||
|
||||
class SubscriptionOverdueReminder extends Notification
|
||||
class SubscriptionsOverdueReminder extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public function __construct(private Bill $bill, private array $dates) {}
|
||||
public function __construct(private array $overdue)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
|
||||
@@ -35,23 +36,31 @@ class SubscriptionOverdueReminder extends Notification
|
||||
*/
|
||||
public function toMail(User $notifiable): MailMessage
|
||||
{
|
||||
// format the dates in a human-readable way
|
||||
$this->dates['pay_dates'] = array_map(
|
||||
static function (string $date): string {
|
||||
return new Carbon($date)->isoFormat((string) trans('config.month_and_day_moment_js'));
|
||||
},
|
||||
$this->dates['pay_dates']
|
||||
);
|
||||
|
||||
// format the data
|
||||
$info = [];
|
||||
$count = 0;
|
||||
foreach ($this->overdue as $item) {
|
||||
$current = [
|
||||
'bill' => $item['bill'],
|
||||
];
|
||||
$current['pay_dates'] = array_map(
|
||||
static function (string $date): string {
|
||||
return new Carbon($date)->isoFormat((string)trans('config.month_and_day_moment_js'));
|
||||
}, $item['dates']['pay_dates']);
|
||||
$info[] = $current;
|
||||
$count++;
|
||||
}
|
||||
return new MailMessage()
|
||||
->markdown('emails.subscription-overdue-warning', ['bill' => $this->bill, 'dates' => $this->dates])
|
||||
->subject($this->getSubject())
|
||||
;
|
||||
->markdown('emails.subscriptions-overdue-warning', ['info' => $info,'count' => $count])
|
||||
->subject($this->getSubject());
|
||||
}
|
||||
|
||||
private function getSubject(): string
|
||||
{
|
||||
return (string) trans('email.subscription_overdue_subject', ['name' => $this->bill->name]);
|
||||
if (count($this->overdue) > 1) {
|
||||
return (string)trans('email.subscriptions_overdue_subject_multi', ['count' => count($this->overdue)]);
|
||||
}
|
||||
return (string)trans('email.subscriptions_overdue_subject_single');
|
||||
}
|
||||
|
||||
public function toNtfy(User $notifiable): Message
|
||||
@@ -60,7 +69,7 @@ class SubscriptionOverdueReminder extends Notification
|
||||
$message = new Message();
|
||||
$message->topic($settings['ntfy_topic']);
|
||||
$message->title($this->getSubject());
|
||||
$message->body((string) trans('email.bill_warning_please_action'));
|
||||
$message->body((string)trans('email.bill_warning_please_action'));
|
||||
|
||||
return $message;
|
||||
}
|
||||
@@ -70,9 +79,8 @@ class SubscriptionOverdueReminder extends Notification
|
||||
*/
|
||||
public function toPushover(User $notifiable): PushoverMessage
|
||||
{
|
||||
return PushoverMessage::create((string) trans('email.bill_warning_please_action'))
|
||||
->title($this->getSubject())
|
||||
;
|
||||
return PushoverMessage::create((string)trans('email.bill_warning_please_action'))
|
||||
->title($this->getSubject());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,10 +94,9 @@ class SubscriptionOverdueReminder extends Notification
|
||||
return new SlackMessage()
|
||||
->warning()
|
||||
->attachment(static function ($attachment) use ($bill, $url): void {
|
||||
$attachment->title((string) trans('firefly.visit_bill', ['name' => $bill->name]), $url);
|
||||
$attachment->title((string)trans('firefly.visit_bill', ['name' => $bill->name]), $url);
|
||||
})
|
||||
->content($this->getSubject())
|
||||
;
|
||||
->content($this->getSubject());
|
||||
}
|
||||
|
||||
/**
|
@@ -28,7 +28,7 @@ use FireflyIII\Events\Admin\InvitationCreated;
|
||||
use FireflyIII\Events\DestroyedTransactionGroup;
|
||||
use FireflyIII\Events\DetectedNewIPAddress;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutBill;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutOverdueSubscription;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutOverdueSubscriptions;
|
||||
use FireflyIII\Events\Model\BudgetLimit\Created;
|
||||
use FireflyIII\Events\Model\BudgetLimit\Deleted;
|
||||
use FireflyIII\Events\Model\BudgetLimit\Updated;
|
||||
@@ -203,8 +203,8 @@ class EventServiceProvider extends ServiceProvider
|
||||
WarnUserAboutBill::class => [
|
||||
'FireflyIII\Handlers\Events\BillEventHandler@warnAboutBill',
|
||||
],
|
||||
WarnUserAboutOverdueSubscription::class => [
|
||||
'FireflyIII\Handlers\Events\BillEventHandler@warnAboutOverdueSubscription',
|
||||
WarnUserAboutOverdueSubscriptions::class => [
|
||||
'FireflyIII\Handlers\Events\BillEventHandler@warnAboutOverdueSubscriptions',
|
||||
],
|
||||
|
||||
// audit log events:
|
||||
|
@@ -139,10 +139,11 @@ return [
|
||||
'new_journals_header' => 'Firefly III has created a transaction for you. You can find it in your Firefly III installation:|Firefly III has created :count transactions for you. You can find them in your Firefly III installation:',
|
||||
|
||||
// subscription is overdue.
|
||||
'subscription_overdue_subject' => 'Your subscription ":name" is overdue to be paid',
|
||||
'subscription_overdue_warning_intro' => 'Your subscription ":name" is overdue to be paid. At the following date(s) a payment was expected, but it has not yet arrived.',
|
||||
'subscription_overdue_please_action' => 'Perhaps you have simply not linked the transaction to subscription ":name". In that case, please do so. You will NOT get another warning about this overdue bill.',
|
||||
'subscription_overdue_outro' => 'If you believe this message is wrong, please contact the Firefly III developer.',
|
||||
'subscriptions_overdue_subject_multi' => 'You have :count subscriptions that are overdue to be paid',
|
||||
'subscriptions_overdue_subject_single' => 'You have a subscription that is overdue to be paid',
|
||||
'subscriptions_overdue_warning_intro' => 'You have :count subscription(s) that are overdue to be paid. At the following date(s) a payment was expected, but it has not yet arrived.',
|
||||
'subscriptions_overdue_please_action' => 'Perhaps you have simply not linked a transaction to these subscription(s). In that case, please do so. You will NOT get another warning about these overdue bill(s).',
|
||||
'subscriptions_overdue_outro' => 'If you believe this message is wrong, please contact the Firefly III developer.',
|
||||
// bill warning
|
||||
'bill_warning_subject_end_date' => 'Your subscription ":name" is due to end in :diff days',
|
||||
'bill_warning_subject_now_end_date' => 'Your subscription ":name" is due to end TODAY',
|
||||
|
@@ -1,10 +0,0 @@
|
||||
@component('mail::message')
|
||||
{{ trans('email.subscription_overdue_warning_intro', ['name' => $bill->name]) }}
|
||||
|
||||
@foreach($dates['pay_dates'] as $date)
|
||||
- {{ $date }}
|
||||
@endforeach
|
||||
|
||||
{{ trans('email.subscription_overdue_please_action', ['name' => $bill->name]) }}
|
||||
|
||||
@endcomponent
|
@@ -0,0 +1,17 @@
|
||||
@component('mail::message')
|
||||
{{ trans('email.subscriptions_overdue_warning_intro', ['count' => $count]) }}
|
||||
|
||||
@foreach($info as $row)
|
||||
- {{ $row['bill']->name }}:
|
||||
@foreach($row['pay_dates'] as $date)
|
||||
- {{ $date }}
|
||||
@endforeach
|
||||
@endforeach
|
||||
|
||||
{{ trans('email.subscriptions_overdue_please_action') }}
|
||||
|
||||
{{ trans('email.subscriptions_overdue_outro') }}
|
||||
|
||||
|
||||
|
||||
@endcomponent
|
Reference in New Issue
Block a user