From d4718d15c3f717bd20e4211199e2dedcb263b2c9 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Schaetzen Date: Sun, 8 Jun 2025 06:47:34 +0200 Subject: [PATCH] Can show an asset --- .../pcinv/controllers/WebController.java | 18 +++++++ .../pcinv/meta/AssetDescriptor.java | 2 +- .../seeseepuff/pcinv/meta/AssetProperty.java | 52 ++++++++++++++++++- .../seeseepuff/pcinv/models/GenericAsset.java | 5 ++ .../pcinv/repositories/AssetRepository.java | 3 ++ .../repositories/GenericAssetRepository.java | 1 + .../pcinv/services/AssetService.java | 24 +++++++-- src/main/resources/templates/fragments.html | 7 ++- src/main/resources/templates/index.html | 1 - src/main/resources/templates/view.html | 14 +++++ 10 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/templates/view.html diff --git a/src/main/java/be/seeseepuff/pcinv/controllers/WebController.java b/src/main/java/be/seeseepuff/pcinv/controllers/WebController.java index 14842ea..616cfd6 100644 --- a/src/main/java/be/seeseepuff/pcinv/controllers/WebController.java +++ b/src/main/java/be/seeseepuff/pcinv/controllers/WebController.java @@ -24,6 +24,7 @@ public class WebController { private static final String DESCRIPTORS = "descriptors"; /// The name of the model attribute that holds the asset descriptor for the current view. private static final String DESCRIPTOR = "descriptor"; + private static final String GENERIC_DESCRIPTOR = "generic"; private final AssetService assetService; @@ -37,6 +38,23 @@ public class WebController { return "index"; } + /** + * Handles the view of an asset by its QR code. + * If the asset does not exist, it redirects to the index page. + * + * @param qr The QR code of the asset to view. + */ + @GetMapping("/view/{qr}") + public String view(Model model, @PathVariable long qr) { + var asset = assetService.getAssetByQr(qr); + if (asset == null) { + return "redirect:/"; + } + model.addAttribute("asset", asset); + model.addAttribute(DESCRIPTORS, assetService.getAssetDescriptorTree(asset.getAsset().getType())); + return "view"; + } + /** * Shows a view where the user can create the type of asset to create. */ diff --git a/src/main/java/be/seeseepuff/pcinv/meta/AssetDescriptor.java b/src/main/java/be/seeseepuff/pcinv/meta/AssetDescriptor.java index 517be6a..e352970 100644 --- a/src/main/java/be/seeseepuff/pcinv/meta/AssetDescriptor.java +++ b/src/main/java/be/seeseepuff/pcinv/meta/AssetDescriptor.java @@ -46,7 +46,7 @@ public class AssetDescriptor { .displayName(assetInfo.displayName()) .visible(assetInfo.isVisible()) .properties(Arrays.stream(assetType.getDeclaredFields()) - .map(AssetProperty::loadFrom) + .map(field -> AssetProperty.loadFrom(field, assetInfo.type())) .filter(Objects::nonNull) .toList()); if (Asset.class.isAssignableFrom(assetType)) { diff --git a/src/main/java/be/seeseepuff/pcinv/meta/AssetProperty.java b/src/main/java/be/seeseepuff/pcinv/meta/AssetProperty.java index 78fe0e6..7defda0 100644 --- a/src/main/java/be/seeseepuff/pcinv/meta/AssetProperty.java +++ b/src/main/java/be/seeseepuff/pcinv/meta/AssetProperty.java @@ -1,6 +1,9 @@ package be.seeseepuff.pcinv.meta; +import be.seeseepuff.pcinv.models.Asset; import be.seeseepuff.pcinv.models.AssetCondition; +import be.seeseepuff.pcinv.models.GenericAsset; +import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import lombok.AllArgsConstructor; import lombok.Builder; @@ -10,6 +13,7 @@ import lombok.Singular; import java.lang.reflect.Field; import java.util.List; import java.util.function.BiConsumer; +import java.util.function.Function; /** * Represents a property of an asset, such as its name or type. @@ -35,6 +39,8 @@ public class AssetProperty { private final boolean capacityAsIEC; /// A setter function that can be used to set the value of the property on an asset. private final BiConsumer setter; + /// A getter function that can be used to get the value of the property from an asset. + private final Function getter; /** * Enum representing the possible types of asset properties. @@ -66,7 +72,7 @@ public class AssetProperty { * @return An AssetProperty instance with the name, display name, and type determined from the field. */ @Nullable - public static AssetProperty loadFrom(Field property) { + public static AssetProperty loadFrom(Field property, @Nonnull String assetType) { var annotation = property.getAnnotation(Property.class); if (annotation == null) { return null; @@ -85,6 +91,17 @@ public class AssetProperty { } catch (IllegalAccessException e) { throw new RuntimeException(e); } + }) + .getter(obj -> { + try { + if (assetType.equals(GenericAsset.TYPE) && obj instanceof Asset asset) { + obj = asset.getAsset(); + } + property.setAccessible(true); + return property.get(obj); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } }); if (type.isEnum) { @@ -144,6 +161,39 @@ public class AssetProperty { setter.accept(asset, value); } + /** + * Gets the value of the property from the given asset. + * + * @param asset The asset to get the property value from. + * @return The value of the property. + */ + public Object getValue(Object asset) { + return getter.apply(asset); + } + + /** + * Renders the value of the property as a string. + * + * @return The rendered value as a string. + */ + public String renderValue(Object asset) { + var value = getValue(asset); + if (value == null) { + return "Unknown"; + } else if (type == Type.INTEGER || type == Type.STRING) { + return value.toString(); + } else if (type == Type.CAPACITY) { + return String.format("%s bytes", value); + } else if (type.isEnum) { + if (value instanceof AssetEnum assetEnum) { + return assetEnum.getDisplayName(); + } + throw new IllegalArgumentException("Expected value to be an instance of AssetEnum, but got: " + value.getClass().getName()); + } else { + return value.toString(); + } + } + @Override public String toString() { var enumOptions = ""; diff --git a/src/main/java/be/seeseepuff/pcinv/models/GenericAsset.java b/src/main/java/be/seeseepuff/pcinv/models/GenericAsset.java index bf66381..fe3e1cc 100644 --- a/src/main/java/be/seeseepuff/pcinv/models/GenericAsset.java +++ b/src/main/java/be/seeseepuff/pcinv/models/GenericAsset.java @@ -23,6 +23,8 @@ import lombok.Setter; @Table(name = "assets") public class GenericAsset { + public static final String TYPE = "asset"; + @Id @GeneratedValue private long id; @@ -30,6 +32,9 @@ public class GenericAsset @Property(value = "QR", required = true) private long qr; + /// The type of asset + private String type; + /// The brand of the asset. @Property("Brand") private String brand; diff --git a/src/main/java/be/seeseepuff/pcinv/repositories/AssetRepository.java b/src/main/java/be/seeseepuff/pcinv/repositories/AssetRepository.java index 36b837c..ac3ce64 100644 --- a/src/main/java/be/seeseepuff/pcinv/repositories/AssetRepository.java +++ b/src/main/java/be/seeseepuff/pcinv/repositories/AssetRepository.java @@ -1,6 +1,7 @@ package be.seeseepuff.pcinv.repositories; import be.seeseepuff.pcinv.models.Asset; +import be.seeseepuff.pcinv.models.GenericAsset; import org.springframework.stereotype.Repository; @Repository @@ -16,6 +17,8 @@ public interface AssetRepository { } } + T findByAsset(GenericAsset asset); + Class getAssetType(); long count(); diff --git a/src/main/java/be/seeseepuff/pcinv/repositories/GenericAssetRepository.java b/src/main/java/be/seeseepuff/pcinv/repositories/GenericAssetRepository.java index a989809..e672dcc 100644 --- a/src/main/java/be/seeseepuff/pcinv/repositories/GenericAssetRepository.java +++ b/src/main/java/be/seeseepuff/pcinv/repositories/GenericAssetRepository.java @@ -5,4 +5,5 @@ import org.springframework.data.jpa.repository.JpaRepository; @SuppressWarnings("unused") public interface GenericAssetRepository extends JpaRepository { + GenericAsset findByQr(long qr); } diff --git a/src/main/java/be/seeseepuff/pcinv/services/AssetService.java b/src/main/java/be/seeseepuff/pcinv/services/AssetService.java index 8d494db..62e7108 100644 --- a/src/main/java/be/seeseepuff/pcinv/services/AssetService.java +++ b/src/main/java/be/seeseepuff/pcinv/services/AssetService.java @@ -35,6 +35,21 @@ public class AssetService { return genericRepository.count(); } + /** + * Retrieves an asset by its QR code. + * + * @param qr the QR code of the asset to retrieve + * @return the Asset associated with the given QR code + * @throws IllegalArgumentException if no asset is found with the given QR code + */ + public Asset getAssetByQr(long qr) { + var genericAsset = genericRepository.findByQr(qr); + if (genericAsset == null) { + throw new IllegalArgumentException("No asset found with QR code: " + qr); + } + return getRepositoryFor(genericAsset.getType()).findByAsset(genericAsset); + } + /** * Retrieves the global asset descriptors for all asset types. * @@ -69,10 +84,10 @@ public class AssetService { * @return a list of AssetDescriptors for the specified type */ public List getAssetDescriptorTree(String type) { - if (type.equals("asset")) { - return List.of(getAssetDescriptor("asset")); + if (type.equals(GenericAsset.TYPE)) { + return List.of(getAssetDescriptor(GenericAsset.TYPE)); } - return List.of(getAssetDescriptor("asset"), getAssetDescriptor(type)); + return List.of(getAssetDescriptor(GenericAsset.TYPE), getAssetDescriptor(type)); } /** @@ -84,10 +99,11 @@ public class AssetService { */ @Transactional public Asset createAsset(String type, Map formData) { - var genericDescriptor = getAssetDescriptor("asset"); + var genericDescriptor = getAssetDescriptor(GenericAsset.TYPE); var assetDescriptor = getAssetDescriptor(type); var genericAsset = new GenericAsset(); + genericAsset.setType(type); fillIn(genericAsset, genericDescriptor, formData); var asset = assetDescriptor.newInstance(); diff --git a/src/main/resources/templates/fragments.html b/src/main/resources/templates/fragments.html index 9200871..86928ef 100644 --- a/src/main/resources/templates/fragments.html +++ b/src/main/resources/templates/fragments.html @@ -4,7 +4,12 @@ PC Inventory -

PC Inventory -

+

PC Inventory - +

+
+ Home + Browse + Create
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 5a58521..f528dd7 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -1,6 +1,5 @@
- Create a new device

This system holds 5 assets.

diff --git a/src/main/resources/templates/view.html b/src/main/resources/templates/view.html new file mode 100644 index 0000000..cba2a27 --- /dev/null +++ b/src/main/resources/templates/view.html @@ -0,0 +1,14 @@ + +
+ View device details +
+

+ + + + + +
+
+
+