From 00a25e55bad18098aaa8aee52fa4cf87cbd670fe Mon Sep 17 00:00:00 2001 From: Robert Goldmann <deadlocker@gmx.de> Date: Sun, 14 Mar 2021 12:21:49 +0100 Subject: [PATCH] #419 - new database entity for images --- .../budgetmaster/accounts/Account.java | 22 ++--- .../accounts/AccountController.java | 13 +-- .../budgetmaster/images/Image.java | 85 +++++++++++++++++++ .../budgetmaster/images/ImageRepository.java | 8 ++ .../budgetmaster/images/ImageService.java | 51 +++++++++++ .../templates/accounts/accountFunctions.ftl | 6 +- .../resources/templates/accounts/accounts.ftl | 2 +- .../templates/accounts/newAccount.ftl | 7 +- .../unit/database/DatabaseParser_v5Test.java | 4 +- 9 files changed, 175 insertions(+), 23 deletions(-) create mode 100644 src/main/java/de/deadlocker8/budgetmaster/images/Image.java create mode 100644 src/main/java/de/deadlocker8/budgetmaster/images/ImageRepository.java create mode 100644 src/main/java/de/deadlocker8/budgetmaster/images/ImageService.java diff --git a/src/main/java/de/deadlocker8/budgetmaster/accounts/Account.java b/src/main/java/de/deadlocker8/budgetmaster/accounts/Account.java index 88352473f..92f09e6af 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/accounts/Account.java +++ b/src/main/java/de/deadlocker8/budgetmaster/accounts/Account.java @@ -1,6 +1,7 @@ package de.deadlocker8.budgetmaster.accounts; import com.google.gson.annotations.Expose; +import de.deadlocker8.budgetmaster.images.Image; import de.deadlocker8.budgetmaster.transactions.Transaction; import javax.persistence.*; @@ -30,20 +31,21 @@ public class Account private Boolean isDefault = false; private Boolean isReadOnly = false; + @ManyToOne @Expose - private String iconPath; + private Image icon; @Expose private AccountType type; - public Account(String name, AccountType type, String iconPath) + public Account(String name, AccountType type, Image icon) { this.name = name; this.type = type; this.isSelected = false; this.isDefault = false; this.isReadOnly = false; - this.iconPath = iconPath; + this.icon = icon; } public Account(String name, AccountType type) @@ -125,14 +127,14 @@ public class Account this.type = type; } - public String getIconPath() + public Image getIcon() { - return iconPath; + return icon; } - public void setIconPath(String iconPath) + public void setIcon(Image icon) { - this.iconPath = iconPath; + this.icon = icon; } @Override @@ -146,7 +148,7 @@ public class Account ", isDefault=" + isDefault + ", isReadOnly=" + isReadOnly + ", type=" + type + - ", iconPath=" + iconPath + + ", icon=" + icon + '}'; } @@ -162,12 +164,12 @@ public class Account Objects.equals(ID, account.ID) && Objects.equals(name, account.name) && type == account.type && - Objects.equals(iconPath, account.iconPath); + Objects.equals(icon, account.icon); } @Override public int hashCode() { - return Objects.hash(ID, name, isSelected, isDefault, isReadOnly, type, iconPath); + return Objects.hash(ID, name, isSelected, isDefault, isReadOnly, type, icon); } } \ No newline at end of file diff --git a/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountController.java b/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountController.java index 5651fd483..38b3e8dd1 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountController.java +++ b/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountController.java @@ -1,6 +1,7 @@ package de.deadlocker8.budgetmaster.accounts; import de.deadlocker8.budgetmaster.controller.BaseController; +import de.deadlocker8.budgetmaster.images.ImageService; import de.deadlocker8.budgetmaster.settings.SettingsService; import de.deadlocker8.budgetmaster.utils.Mappings; import de.deadlocker8.budgetmaster.utils.ResourceNotFoundException; @@ -27,12 +28,14 @@ public class AccountController extends BaseController { private final AccountService accountService; private final SettingsService settingsService; + private final ImageService imageService; @Autowired - public AccountController(AccountService accountService, SettingsService settingsService) + public AccountController(AccountService accountService, SettingsService settingsService, ImageService imageService) { this.accountService = accountService; this.settingsService = settingsService; + this.imageService = imageService; } @GetMapping(value = "/{ID}/select") @@ -129,7 +132,7 @@ public class AccountController extends BaseController Account emptyAccount = new Account(); model.addAttribute("account", emptyAccount); model.addAttribute("settings", settingsService.getSettings()); - model.addAttribute("iconImages", List.of("https://localhost:9000/touch_icon.png", "https://localhost:9000/touch_icon.png")); + model.addAttribute("availableImages", imageService.getRepository().findAll()); return "accounts/newAccount"; } @@ -144,7 +147,7 @@ public class AccountController extends BaseController model.addAttribute("account", accountOptional.get()); model.addAttribute("settings", settingsService.getSettings()); - model.addAttribute("iconImages", List.of("https://localhost:9000/touch_icon.png", "https://localhost:9000/touch_icon.png")); + model.addAttribute("availableImages", imageService.getRepository().findAll()); return "accounts/newAccount"; } @@ -168,7 +171,7 @@ public class AccountController extends BaseController model.addAttribute("error", bindingResult); model.addAttribute("account", account); model.addAttribute("settings", settingsService.getSettings()); - model.addAttribute("iconImages", List.of("https://localhost:9000/touch_icon.png", "https://localhost:9000/touch_icon.png")); + model.addAttribute("availableImages", imageService.getRepository().findAll()); return "accounts/newAccount"; } else @@ -187,7 +190,7 @@ public class AccountController extends BaseController { Account existingAccount = existingAccountOptional.get(); existingAccount.setName(account.getName()); - existingAccount.setIconPath(account.getIconPath()); + existingAccount.setIcon(account.getIcon()); accountService.getRepository().save(existingAccount); } } diff --git a/src/main/java/de/deadlocker8/budgetmaster/images/Image.java b/src/main/java/de/deadlocker8/budgetmaster/images/Image.java new file mode 100644 index 000000000..973a25107 --- /dev/null +++ b/src/main/java/de/deadlocker8/budgetmaster/images/Image.java @@ -0,0 +1,85 @@ +package de.deadlocker8.budgetmaster.images; + +import com.google.gson.annotations.Expose; +import de.deadlocker8.budgetmaster.accounts.Account; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; +import java.util.Objects; + +@Entity +public class Image +{ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Expose + private Integer ID; + + @NotNull + @Size(min = 1) + @Expose + private String imagePath; + + @OneToMany(mappedBy = "icon", fetch = FetchType.LAZY) + private List<Account> referringAccounts; + + public Image(String imagePath) + { + this.imagePath = imagePath; + } + + public Image() + { + } + + public Integer getID() + { + return ID; + } + + public void setID(Integer ID) + { + this.ID = ID; + } + + public String getImagePath() + { + return imagePath; + } + + public void setImagePath(String imagePath) + { + this.imagePath = imagePath; + } + + public List<Account> getReferringAccounts() + { + return referringAccounts; + } + + @Override + public String toString() + { + return "Image{" + + "ID=" + ID + + ", imagePath='" + imagePath + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) + { + if(this == o) return true; + if(o == null || getClass() != o.getClass()) return false; + Image image = (Image) o; + return Objects.equals(ID, image.ID) && Objects.equals(imagePath, image.imagePath); + } + + @Override + public int hashCode() + { + return Objects.hash(ID, imagePath); + } +} \ No newline at end of file diff --git a/src/main/java/de/deadlocker8/budgetmaster/images/ImageRepository.java b/src/main/java/de/deadlocker8/budgetmaster/images/ImageRepository.java new file mode 100644 index 000000000..db770d707 --- /dev/null +++ b/src/main/java/de/deadlocker8/budgetmaster/images/ImageRepository.java @@ -0,0 +1,8 @@ +package de.deadlocker8.budgetmaster.images; + +import org.springframework.data.jpa.repository.JpaRepository; + + +public interface ImageRepository extends JpaRepository<Image, Integer> +{ +} \ No newline at end of file diff --git a/src/main/java/de/deadlocker8/budgetmaster/images/ImageService.java b/src/main/java/de/deadlocker8/budgetmaster/images/ImageService.java new file mode 100644 index 000000000..cd364e3e6 --- /dev/null +++ b/src/main/java/de/deadlocker8/budgetmaster/images/ImageService.java @@ -0,0 +1,51 @@ +package de.deadlocker8.budgetmaster.images; + +import de.deadlocker8.budgetmaster.services.Resetable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ImageService implements Resetable +{ + private static final Logger LOGGER = LoggerFactory.getLogger(ImageService.class); + + private final ImageRepository imageRepository; + + @Autowired + public ImageService(ImageRepository imageRepository) + { + this.imageRepository = imageRepository; + } + + public ImageRepository getRepository() + { + return imageRepository; + } + + @Override + public void deleteAll() + { + // TODO: set placeholder image for all accounts + imageRepository.deleteAll(); + } + + @Override + public void createDefaults() + { + if(imageRepository.findAll().isEmpty()) + { + // TODO: insert placeholder image +// Account placeholder = new Account("Placeholder", AccountType.ALL); +// accountRepository.save(placeholder); +// LOGGER.debug("Created placeholder account"); +// +// Account account = accountRepository.save(new Account(Localization.getString(Strings.ACCOUNT_DEFAULT_NAME), AccountType.CUSTOM)); +// selectAccount(account.getID()); +// setAsDefaultAccount(account.getID()); +// LOGGER.debug("Created default account"); + } + + } +} diff --git a/src/main/resources/templates/accounts/accountFunctions.ftl b/src/main/resources/templates/accounts/accountFunctions.ftl index 407c3b353..ae5b1c054 100644 --- a/src/main/resources/templates/accounts/accountFunctions.ftl +++ b/src/main/resources/templates/accounts/accountFunctions.ftl @@ -4,7 +4,7 @@ <div id="modalAccountIconSelect" class="modal modal-fixed-footer background-color"> <div class="modal-content"> <div class="row"> - <#list iconImages as image> + <#list availableImages as image> <@accountIconOption image/> </#list> </div> @@ -16,10 +16,10 @@ </div> </#macro> -<#macro accountIconOption icon> +<#macro accountIconOption image> <div class="col s4 m2 l2 account-icon-option-column"> <div class="account-icon-option"> - <img src="${icon}" class="account-icon-preview" alt="${icon}" data-image-id="1"/> + <img src="${image.getImagePath()}" class="account-icon-preview" alt="${image.getImagePath()}" data-image-id="${image.getID()}"/> </div> </div> </#macro> \ No newline at end of file diff --git a/src/main/resources/templates/accounts/accounts.ftl b/src/main/resources/templates/accounts/accounts.ftl index 55b60dd8e..f8256aeff 100644 --- a/src/main/resources/templates/accounts/accounts.ftl +++ b/src/main/resources/templates/accounts/accounts.ftl @@ -41,7 +41,7 @@ <a href="<@s.url '/accounts/${account.getID()?c}/toggleReadOnly'/>" class="btn-flat no-padding text-default tooltipped" data-position="right" data-tooltip="${toolTipText}">${lockIcon}</a> </#if> </td> - <td><#if account.getIconPath()?has_content><img src="${account.getIconPath()}" class="account-icon"/></#if></td> + <td><#if account.getIcon()??><img src="${account.getIcon().getImagePath()}" class="account-icon"/></#if></td> <td>${account.getName()}</td> <td> <a href="<@s.url '/accounts/${account.getID()?c}/edit'/>" class="btn-flat no-padding text-default"><i class="material-icons left">edit</i></a> diff --git a/src/main/resources/templates/accounts/newAccount.ftl b/src/main/resources/templates/accounts/newAccount.ftl index d27d2205d..83b2aa607 100644 --- a/src/main/resources/templates/accounts/newAccount.ftl +++ b/src/main/resources/templates/accounts/newAccount.ftl @@ -54,11 +54,12 @@ <div id="account-icon" class="valign-wrapper"> <a href="#modalAccountIconSelect" id="account-icon-preview" class="modal-trigger"> - <img id="account-icon-preview-icon" src="<#if account.getIconPath()?has_content>${account.getIconPath()}</#if>" class="account-icon-preview <#if account.getIconPath()?has_content == false>hidden</#if>"/> - <div id="account-icon-placeholder" class="<#if account.getIconPath()?has_content>hidden</#if>">${locale.getString("account.new.icon.placeholder")}</div> + <img id="account-icon-preview-icon" src="<#if account.getIcon()??>${account.getIcon().getImagePath()}</#if>" class="account-icon-preview <#if account.getIcon()?? == false>hidden</#if>"/> + <div id="account-icon-placeholder" class="<#if account.getIcon()??>hidden</#if>">${locale.getString("account.new.icon.placeholder")}</div> </a> <@header.buttonFlat url='' icon='delete' id='button-remove-account-icon' localizationKey='' classes="no-padding text-default" noUrl=true/> - <input id="hidden-input-account-icon" type="hidden" name="iconPath" value="<#if account.getIconPath()??>${account.getIconPath()}</#if>"> + + <input id="hidden-input-account-icon" type="hidden" name="icon" value="<#if account.getIcon()??>${account.getIcon().getID()?c}</#if>"> </div> </div> </div> diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v5Test.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v5Test.java index e73826c26..d46effdbb 100644 --- a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v5Test.java +++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v5Test.java @@ -8,6 +8,7 @@ import de.deadlocker8.budgetmaster.charts.Chart; import de.deadlocker8.budgetmaster.charts.ChartType; import de.deadlocker8.budgetmaster.database.Database; import de.deadlocker8.budgetmaster.database.DatabaseParser_v5; +import de.deadlocker8.budgetmaster.images.Image; import de.thecodelabs.utils.util.Localization; import de.thecodelabs.utils.util.Localization.LocalizationDelegate; import org.junit.Before; @@ -95,7 +96,8 @@ public class DatabaseParser_v5Test DatabaseParser_v5 importer = new DatabaseParser_v5(json); Database database = importer.parseDatabaseFromJSON(); - final Account account = new Account("Second Account", AccountType.CUSTOM, "myPath/to/fancy/icon.png"); + // TODO + final Account account = new Account("Second Account", AccountType.CUSTOM, new Image()); account.setID(3); assertThat(database.getAccounts()).hasSize(3) -- GitLab