diff --git a/build.gradle b/build.gradle index 8015e02..47bce9f 100644 --- a/build.gradle +++ b/build.gradle @@ -60,6 +60,7 @@ dependencies { implementation 'org.commonmark:commonmark:0.22.0' implementation 'org.jsoup:jsoup:1.17.2' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.17.2' implementation 'io.minio:minio:8.5.11' diff --git a/dev-data/images/Obazda.jpg b/dev-data/images/Obazda.jpg new file mode 100644 index 0000000..92369d7 Binary files /dev/null and b/dev-data/images/Obazda.jpg differ diff --git a/dev-data/recipes/Obazda.md b/dev-data/recipes/Obazda.md new file mode 100644 index 0000000..6403383 --- /dev/null +++ b/dev-data/recipes/Obazda.md @@ -0,0 +1,21 @@ +--- +title: German (Bavarian) Obazda +slug: obazda +isPublic: true +mainImage: + src: images/Obazda.jpg + title: Obazda + alt: Obazda. + caption: German Obazda. + isPublic: true +--- +## Ingredients +- Butter +- Camembert +- Scallions +- A few slices of red onion +- Salt and pepper + +## Instructions +Mix all together until coarsely blended. +Serve cold with pretzels or other lye-type bread! \ No newline at end of file diff --git a/src/main/java/app/mealsmadeeasy/api/DevConfiguration.java b/src/main/java/app/mealsmadeeasy/api/DevConfiguration.java index d605f94..d4a31ac 100644 --- a/src/main/java/app/mealsmadeeasy/api/DevConfiguration.java +++ b/src/main/java/app/mealsmadeeasy/api/DevConfiguration.java @@ -1,7 +1,6 @@ package app.mealsmadeeasy.api; import app.mealsmadeeasy.api.image.Image; -import app.mealsmadeeasy.api.image.ImageException; import app.mealsmadeeasy.api.image.ImageService; import app.mealsmadeeasy.api.image.spec.ImageCreateInfoSpec; import app.mealsmadeeasy.api.recipe.Recipe; @@ -9,6 +8,8 @@ import app.mealsmadeeasy.api.recipe.RecipeService; import app.mealsmadeeasy.api.recipe.spec.RecipeCreateSpec; import app.mealsmadeeasy.api.user.User; import app.mealsmadeeasy.api.user.UserService; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.CommandLineRunner; @@ -16,9 +17,12 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; -import java.io.IOException; +import java.io.FileInputStream; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Set; +import java.util.stream.Stream; @Configuration @Profile("dev") @@ -30,58 +34,82 @@ public class DevConfiguration { private final RecipeService recipeService; private final ImageService imageService; + private final ObjectMapper yamlObjectMapper = new ObjectMapper(new YAMLFactory()); + public DevConfiguration(UserService userService, RecipeService recipeService, ImageService imageService) { this.userService = userService; this.recipeService = recipeService; this.imageService = imageService; } + private static final class ImageInfo { + public String src; + public String title; + public String alt; + public String caption; + public boolean isPublic; + } + + private static final class RecipeFrontMatter { + public String title; + public String slug; + public boolean isPublic; + public ImageInfo mainImage; + } + @Bean public CommandLineRunner addTestData() { return args -> { final User testUser = this.userService.createUser( - "test", "test@test.com", "test", Set.of() + "test-user", "test-user@test.com", "test", Set.of() ); - logger.info("Created {}", testUser); + logger.info("Created testUser: {}", testUser); - final ImageCreateInfoSpec obazdaCreateSpec = new ImageCreateInfoSpec(); - obazdaCreateSpec.setAlt("Obazda"); - obazdaCreateSpec.setCaption("German Obazda."); - obazdaCreateSpec.setPublic(true); - final Image obazdaImage; - try (final InputStream obazdaStream = DevConfiguration.class.getResourceAsStream("Obazda.jpg")) { - obazdaImage = this.imageService.create( - testUser, - "Obazda.jpg", - obazdaStream, - 48654L, - obazdaCreateSpec - ); - } - logger.info("Created {}", obazdaImage); + try (final Stream recipePaths = Files.walk(Path.of("dev-data/recipes"))) { + for (final Path recipePath : recipePaths.toList()) { + if (Files.isDirectory(recipePath)) { + continue; + } - final RecipeCreateSpec recipeCreateSpec = new RecipeCreateSpec(); - recipeCreateSpec.setSlug("test-recipe"); - recipeCreateSpec.setTitle("Test Recipe"); - recipeCreateSpec.setRawText("Hello, World!"); - recipeCreateSpec.setPublic(true); - recipeCreateSpec.setMainImage(obazdaImage); - final Recipe recipe = this.recipeService.create(testUser, recipeCreateSpec); - logger.info("Created {}", recipe); + final String fullText = Files.readString(recipePath); + final String[] parts = fullText.split("---"); + if (parts.length != 3) { + throw new IllegalArgumentException("Invalid recipe file: " + recipePath); + } + final String rawFrontMatter = parts[1]; + final String rawRecipeText = parts[2]; + final RecipeFrontMatter frontMatter = this.yamlObjectMapper.readValue( + rawFrontMatter, RecipeFrontMatter.class + ); - try (final InputStream inputStream = DevConfiguration.class.getResourceAsStream("HAL9000.svg")) { - final ImageCreateInfoSpec imageCreateSpec = new ImageCreateInfoSpec(); - imageCreateSpec.setPublic(true); - final Image image = this.imageService.create( - testUser, - "HAL9000.svg", - inputStream, - 27881L, - imageCreateSpec - ); - logger.info("Created {}", image); - } catch (IOException | ImageException e) { - logger.error("Failed to load and/or create HAL9000.svg", e); + final ImageCreateInfoSpec imageCreateSpec = new ImageCreateInfoSpec(); + imageCreateSpec.setAlt(frontMatter.mainImage.alt); + imageCreateSpec.setCaption(frontMatter.mainImage.caption); + imageCreateSpec.setPublic(frontMatter.mainImage.isPublic); + final Path givenPath = Path.of(frontMatter.mainImage.src); + final Path resolvedPath = Path.of("dev-data").resolve(givenPath); + final Image mainImage; + try (final InputStream inputStream = new FileInputStream(resolvedPath.toFile())) { + final long size = Files.size(resolvedPath); + mainImage = this.imageService.create( + testUser, + givenPath.getName(givenPath.getNameCount() - 1).toString(), + inputStream, + size, + imageCreateSpec + ); + logger.info("Created mainImage {} for {}", mainImage, recipePath); + } + + final RecipeCreateSpec recipeCreateSpec = new RecipeCreateSpec(); + recipeCreateSpec.setSlug(frontMatter.slug); + recipeCreateSpec.setTitle(frontMatter.title); + recipeCreateSpec.setRawText(rawRecipeText); + recipeCreateSpec.setPublic(frontMatter.isPublic); + recipeCreateSpec.setMainImage(mainImage); + final Recipe recipe = this.recipeService.create(testUser, recipeCreateSpec); + logger.info("Created recipe {}", recipe); + } } }; } diff --git a/src/main/java/app/mealsmadeeasy/api/recipe/RecipeEntity.java b/src/main/java/app/mealsmadeeasy/api/recipe/RecipeEntity.java index 490515b..10c8cb5 100644 --- a/src/main/java/app/mealsmadeeasy/api/recipe/RecipeEntity.java +++ b/src/main/java/app/mealsmadeeasy/api/recipe/RecipeEntity.java @@ -33,12 +33,13 @@ public final class RecipeEntity implements Recipe { @Column(nullable = false) private String title; - @Column(nullable = false) @Lob + @Column(name = "raw_text", columnDefinition = "TEXT", nullable = false) @Basic(fetch = FetchType.LAZY) private String rawText; @Lob + @Column(name = "cached_rendered_text", columnDefinition = "TEXT") @Basic(fetch = FetchType.LAZY) private String cachedRenderedText;