From de7c49b63a018e06cfadd409491d3435d480c9e4 Mon Sep 17 00:00:00 2001
From: Robert Goldmann <deadlocker@gmx.de>
Date: Tue, 1 Oct 2024 23:22:49 +0200
Subject: [PATCH] #764 - warn about upcoming end date on logins

---
 .../accounts/AccountController.java           | 12 +++++++-
 .../services/AccountEndDateReminderData.java  |  7 +++++
 .../budgetmaster/services/HelpersService.java | 30 ++++++++++++++++---
 .../resources/languages/base_de.properties    |  4 +++
 .../resources/languages/base_en.properties    |  4 +++
 .../src/main/resources/static/js/main.js      |  5 ++++
 .../resources/templates/helpers/navbar.ftl    | 22 ++++++++++++++
 7 files changed, 79 insertions(+), 5 deletions(-)
 create mode 100644 BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/services/AccountEndDateReminderData.java

diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountController.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountController.java
index 2467ddf87..54b0bd55b 100644
--- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountController.java
+++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountController.java
@@ -2,6 +2,7 @@ package de.deadlocker8.budgetmaster.accounts;
 
 import de.deadlocker8.budgetmaster.controller.BaseController;
 import de.deadlocker8.budgetmaster.icon.IconService;
+import de.deadlocker8.budgetmaster.settings.SettingsService;
 import de.deadlocker8.budgetmaster.utils.FontAwesomeIcons;
 import de.deadlocker8.budgetmaster.utils.Mappings;
 import de.deadlocker8.budgetmaster.utils.ResourceNotFoundException;
@@ -58,12 +59,14 @@ public class AccountController extends BaseController
 
 	private final AccountService accountService;
 	private final IconService iconService;
+	private final SettingsService settingsService;
 
 	@Autowired
-	public AccountController(AccountService accountService, IconService iconService)
+	public AccountController(AccountService accountService, IconService iconService, SettingsService settingsService)
 	{
 		this.accountService = accountService;
 		this.iconService = iconService;
+		this.settingsService = settingsService;
 	}
 
 	@GetMapping(value = "/{ID}/select")
@@ -262,4 +265,11 @@ public class AccountController extends BaseController
 
 		return ReturnValues.GLOBAL_ACCOUNT_SELECT_MODAL;
 	}
+
+	@GetMapping("/cancelReminder")
+	public String cancelReminder(HttpServletRequest request)
+	{
+		settingsService.updateLastAccountEndDateReminderDate();
+		return "redirect:" + request.getHeader("Referer");
+	}
 }
\ No newline at end of file
diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/services/AccountEndDateReminderData.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/services/AccountEndDateReminderData.java
new file mode 100644
index 000000000..eb0b4bb4f
--- /dev/null
+++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/services/AccountEndDateReminderData.java
@@ -0,0 +1,7 @@
+package de.deadlocker8.budgetmaster.services;
+
+import java.util.List;
+
+public record AccountEndDateReminderData(boolean show, List<String> accountsWithEndDateSoon)
+{
+}
diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java
index 36314c618..329ee67a3 100644
--- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java
+++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java
@@ -30,10 +30,8 @@ import org.springframework.stereotype.Service;
 import java.text.DecimalFormatSymbols;
 import java.text.MessageFormat;
 import java.time.LocalDate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
 import java.util.stream.Collectors;
 
 
@@ -248,4 +246,28 @@ public class HelpersService
 	{
 		return new DecimalFormatSymbols(settingsService.getSettings().getLanguage().getLocale()).getGroupingSeparator();
 	}
+
+	public AccountEndDateReminderData getAccountEndDateReminderData()
+	{
+		final Settings settings = settingsService.getSettings();
+		if(!settings.getAccountEndDateReminderActivated())
+		{
+			return new AccountEndDateReminderData(false, List.of());
+		}
+
+		if(!Objects.equals(settings.getLastAccountEndDateReminderDate(), DateHelper.getCurrentDate()))
+		{
+			final List<String> accountsWithEndDateSoon = accountRepository.findAll().stream()
+					.filter(account -> account.getEndDate() != null)
+					.filter(account -> account.getRemainingDays() > 0)
+					.filter(account -> account.getRemainingDays() <= 30)
+					.map(account -> MessageFormat.format("{0} ({1})", account.getName(), account.getEndDate().format(DateTimeFormatter.ofPattern("dd.MM.yy"))))
+					.sorted()
+					.toList();
+
+			return new AccountEndDateReminderData(true, accountsWithEndDateSoon);
+		}
+
+		return new AccountEndDateReminderData(false, List.of());
+	}
 }
\ No newline at end of file
diff --git a/BudgetMasterServer/src/main/resources/languages/base_de.properties b/BudgetMasterServer/src/main/resources/languages/base_de.properties
index 96e8a77e2..63d8c0e4d 100644
--- a/BudgetMasterServer/src/main/resources/languages/base_de.properties
+++ b/BudgetMasterServer/src/main/resources/languages/base_de.properties
@@ -170,6 +170,10 @@ info.text.update=Es ist ein Update für BudgetMaster verfügbar<br><br>Installie
 info.title.backup.reminder=Zeit für ein Backup
 info.text.backup.reminder=Schon mal über ein Backup nachgedacht?<br>Du solltest deine BudgetMaster Datenbank regelmäßig sichern.<br>Dies geht besonders einfach in den Einstellungen.<br>Du kannst auch ein automatisches Backup konfigurieren.<br><br>(Du wilst diese Erinnerung nicht jeden Monat sehen? Dann deaktiviere die Backuperinnerung in den Einstellungen.)
 info.button.backup.reminder=Zu den Einstellungen
+info.title.account.endDate=Account end dates
+info.text.account.endDate.soon=Die folgenden Konten erreichen demnächst ihr Enddatum:
+info.text.account.endDate.general=(Du wilst diese Erinnerung nicht mehr sehen? Dann deaktiviere die Enddatumserinnerung in den Einstellungen.)
+info.button.account.endDate=Zur Accountübersicht
 notification.settings.security.saved=Passwort gespeichert
 notification.settings.security.warning=Passwort entspricht bereits gespeicherten Passwort
 notification.settings.security.error=Fehler beim Speichern des Passworts
diff --git a/BudgetMasterServer/src/main/resources/languages/base_en.properties b/BudgetMasterServer/src/main/resources/languages/base_en.properties
index 1b94eb874..0b1766145 100644
--- a/BudgetMasterServer/src/main/resources/languages/base_en.properties
+++ b/BudgetMasterServer/src/main/resources/languages/base_en.properties
@@ -170,6 +170,10 @@ info.text.update=An update for BudgetMaster is available<br><br>Installed: v{0}<
 info.title.backup.reminder=Time for a backup
 info.text.backup.reminder=Have you ever thought about a backup?<br>You should back up your BudgetMaster database regularly.<br>This can be done on the settings page.<br>You can also enable an automatic backup.<br><br>(You don''t want to see this reminder every month? Disable the backup reminder in the settings.)
 info.button.backup.reminder=To the settings
+info.title.account.endDate=Account end dates
+info.text.account.endDate.soon=The following accounts will reach their end dates soon:
+info.text.account.endDate.general=(You don''t want to see this message anymore? Disable the account end date reminder in the settings.)
+info.button.account.endDate=Open account Overview
 notification.settings.security.saved=Password saved
 notification.settings.security.warning=Password equals already saved password
 notification.settings.security.error=Error saving password
diff --git a/BudgetMasterServer/src/main/resources/static/js/main.js b/BudgetMasterServer/src/main/resources/static/js/main.js
index 47c108fef..907bd21cd 100644
--- a/BudgetMasterServer/src/main/resources/static/js/main.js
+++ b/BudgetMasterServer/src/main/resources/static/js/main.js
@@ -20,6 +20,11 @@ $(document).ready(function()
         $('#modalBackupReminder').modal('open');
     }
 
+    if($("#modalAccountEndDateReminder").length)
+    {
+        $('#modalAccountEndDateReminder').modal('open');
+    }
+
     if($("#whatsNewModelContainer").length)
     {
         fetchAndShowModal(document.getElementById('whatsNewModelContainer'), 'whatsNewModelContainer', '#modalWhatsNew');
diff --git a/BudgetMasterServer/src/main/resources/templates/helpers/navbar.ftl b/BudgetMasterServer/src/main/resources/templates/helpers/navbar.ftl
index f3925e9f9..f1a1150da 100644
--- a/BudgetMasterServer/src/main/resources/templates/helpers/navbar.ftl
+++ b/BudgetMasterServer/src/main/resources/templates/helpers/navbar.ftl
@@ -53,6 +53,7 @@
     </form>
 
     <@backupReminder settings/>
+    <@accountEndDateReminder helpers.getAccountEndDateReminderData()/>
     <@whatsNewModal settings/>
 
     <div id="globalAccountSelectModalOnDemand"></div>
@@ -176,3 +177,24 @@
         <div id="whatsNewModelContainer" data-url="<@s.url '/about/whatsNewModal'/>"></div>
     </#if>
 </#macro>
+
+<#macro accountEndDateReminder acountEndDateReminderData>
+    <#if acountEndDateReminderData.show()>
+        <div id="modalAccountEndDateReminder" class="modal background-color">
+            <div class="modal-content">
+                <h4>${locale.getString("info.title.account.endDate")}</h4>
+
+                <p>${locale.getString("info.text.account.endDate.soon")}</p>
+                <#list acountEndDateReminderData.accountsWithEndDateSoon() as accountWithEndDateSoon>
+                  <div>&nbsp;• ${accountWithEndDateSoon}</div>
+                </#list>
+
+                <p>${locale.getString("info.text.account.endDate.general")}</p>
+            </div>
+            <div class="modal-footer background-color">
+                <@header.buttonLink url='/accounts/cancelReminder' icon='clear' localizationKey='cancel' color='red' id='buttonCloseReminder' classes='modal-action modal-close text-white'/>
+                <@header.buttonLink url='/accounts' icon='account_balance' localizationKey='info.button.account.endDate' color='green' id='buttonCloseReminder' classes='modal-action modal-close text-white'/>
+            </div>
+        </div>
+    </#if>
+</#macro>
\ No newline at end of file
-- 
GitLab