personalweb

Archived
git clone git://git.wimdupont.com/personalweb.git
Log | Files | Refs | README | LICENSE

commit 8bd36cfc8eb49c8bdd497504f2c05929a55b957a
parent 6b5991d1311de54f72fd604b49112c4b97ac0341
Author: Wim Dupont <wim@wimdupont.com>
Date:   Sat,  4 Feb 2023 15:08:52 +0100

cleanup


Former-commit-id: 426312c390e3c79e06c69fe919bc0cb994c1bd39
Diffstat:
Mpom.xml | 5-----
Msrc/main/java/com/wimdupont/personalweb/api/AffirmationApi.java | 13+++++--------
Msrc/main/java/com/wimdupont/personalweb/config/SecurityConfig.java | 1-
Msrc/main/java/com/wimdupont/personalweb/config/WebClientConfig.java | 1-
Msrc/main/java/com/wimdupont/personalweb/controller/BlogController.java | 40+++++++++-------------------------------
Msrc/main/java/com/wimdupont/personalweb/controller/BookController.java | 23+++++------------------
Msrc/main/java/com/wimdupont/personalweb/controller/ContactController.java | 9+++++----
Msrc/main/java/com/wimdupont/personalweb/controller/DonateController.java | 3---
Msrc/main/java/com/wimdupont/personalweb/controller/FeedController.java | 14++++++++------
Msrc/main/java/com/wimdupont/personalweb/controller/IndexController.java | 7++++---
Msrc/main/java/com/wimdupont/personalweb/controller/LinkController.java | 1-
Msrc/main/java/com/wimdupont/personalweb/converter/BookToBookDtoConverter.java | 2+-
Dsrc/main/java/com/wimdupont/personalweb/model/FeedModel.java | 15---------------
Msrc/main/java/com/wimdupont/personalweb/model/dao/Book.java | 66+++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/main/java/com/wimdupont/personalweb/model/dto/ArticleDto.java | 41+++++++++++++++++++++++++++++++++--------
Msrc/main/java/com/wimdupont/personalweb/model/dto/BookDto.java | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/main/java/com/wimdupont/personalweb/service/AdocConverter.java | 13+++----------
Asrc/main/java/com/wimdupont/personalweb/service/ArticleService.java | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main/java/com/wimdupont/personalweb/service/BlogArticleGenerator.java | 46+++++++++++++++++++++++++++++++++-------------
Msrc/main/java/com/wimdupont/personalweb/service/BookService.java | 24+++++++++++++++++++-----
Msrc/main/java/com/wimdupont/personalweb/service/RssFeedGenerator.java | 26++++++++++++++++----------
Msrc/main/java/com/wimdupont/personalweb/util/Constants.java | 20++++++++++++++------
Msrc/test/java/com/wimdupont/personalweb/converter/BookToBookDtoConverterTest.java | 17++++++++++-------
23 files changed, 355 insertions(+), 179 deletions(-)

diff --git a/pom.xml b/pom.xml @@ -34,11 +34,6 @@ <artifactId>mariadb-java-client</artifactId> </dependency> <dependency> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - <optional>true</optional> - </dependency> - <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> diff --git a/src/main/java/com/wimdupont/personalweb/api/AffirmationApi.java b/src/main/java/com/wimdupont/personalweb/api/AffirmationApi.java @@ -1,7 +1,6 @@ package com.wimdupont.personalweb.api; import com.wimdupont.personalweb.api.dto.affirmation.Affirmation; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; @@ -9,20 +8,18 @@ import reactor.core.publisher.Mono; import java.time.Duration; @Component -@RequiredArgsConstructor public class AffirmationApi { private final WebClient webClient; + public AffirmationApi(WebClient webClient) { + this.webClient = webClient; + } + private static final String AFFIRMATION_URL = "https://www.affirmations.dev/"; public Mono<Affirmation> getAffirmation() { - return webClient.get() - .uri(AFFIRMATION_URL) - .retrieve() - .bodyToMono(Affirmation.class) - .timeout(Duration.ofSeconds(3)) - .onErrorReturn(new Affirmation("You're the best!")); + return webClient.get().uri(AFFIRMATION_URL).retrieve().bodyToMono(Affirmation.class).timeout(Duration.ofSeconds(3)).onErrorReturn(new Affirmation("You're the best!")); } } diff --git a/src/main/java/com/wimdupont/personalweb/config/SecurityConfig.java b/src/main/java/com/wimdupont/personalweb/config/SecurityConfig.java @@ -10,7 +10,6 @@ import org.springframework.security.web.server.SecurityWebFilterChain; @Configuration @EnableWebFluxSecurity @EnableReactiveMethodSecurity -@SuppressWarnings("unused") public class SecurityConfig { @Bean diff --git a/src/main/java/com/wimdupont/personalweb/config/WebClientConfig.java b/src/main/java/com/wimdupont/personalweb/config/WebClientConfig.java @@ -7,7 +7,6 @@ import org.springframework.http.MediaType; import org.springframework.web.reactive.function.client.WebClient; @Configuration -@SuppressWarnings("unused") public class WebClientConfig { @Bean diff --git a/src/main/java/com/wimdupont/personalweb/controller/BlogController.java b/src/main/java/com/wimdupont/personalweb/controller/BlogController.java @@ -1,48 +1,27 @@ package com.wimdupont.personalweb.controller; -import com.wimdupont.personalweb.model.dto.ArticleDto; -import com.wimdupont.personalweb.util.Constants; -import lombok.extern.slf4j.Slf4j; +import com.wimdupont.personalweb.service.ArticleService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; -import java.io.File; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.time.Instant; -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.TimeZone; -@Slf4j @Controller @RequestMapping("/blog") -@SuppressWarnings("unused") public class BlogController { + private final ArticleService articleService; + + public BlogController(ArticleService articleService) { + this.articleService = articleService; + } + @GetMapping public String getBlog(Model model) { - List<ArticleDto> articles = new ArrayList<>(); - File[] files = new File(String.format("%s/html", Constants.ARTICLES_DIRECTORY)).listFiles(); - if (files != null) { - Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed()); - for (File htmlArticle : files) { - articles.add(ArticleDto.builder() - .name(htmlArticle.getName().replaceFirst(".html", "")) - .date(LocalDate.ofInstant(Instant.ofEpochMilli(htmlArticle.lastModified()), TimeZone.getDefault().toZoneId())) - .build() - ); - } - model.addAttribute("articles", articles); - } - + model.addAttribute("articles", articleService.getArticles()); return "blog"; } @@ -50,10 +29,9 @@ public class BlogController { public String getBlogArticle(@PathVariable(value = "name") String name, Model model) { String article; try { - article = Files.readString(Paths.get(String.format("%s/html/%s%s", Constants.ARTICLES_DIRECTORY, name, ".html"))); + article = articleService.getHtmlArticle(name, true); } catch (IOException e) { article = String.format("Article with name \"%s\" not found.", name); - log.warn(article); } model.addAttribute("article", article); model.addAttribute("title", name); diff --git a/src/main/java/com/wimdupont/personalweb/controller/BookController.java b/src/main/java/com/wimdupont/personalweb/controller/BookController.java @@ -1,37 +1,24 @@ package com.wimdupont.personalweb.controller; -import com.wimdupont.personalweb.converter.BookToBookDtoConverter; -import com.wimdupont.personalweb.model.dto.BookDto; import com.wimdupont.personalweb.service.BookService; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - @Controller -@RequiredArgsConstructor @RequestMapping("/books") public class BookController { - private final BookToBookDtoConverter bookToBookDtoConverter; private final BookService bookService; + public BookController(BookService bookService) { + this.bookService = bookService; + } + @GetMapping - @SuppressWarnings("unused") public String getBooks(Model model) { - Map<String, List<BookDto>> books = bookService.findAllSorted().stream() - .map(bookToBookDtoConverter::convert) - .collect(Collectors.groupingBy(BookDto::getCategory, - LinkedHashMap::new, - Collectors.mapping(book -> book, Collectors.toList()))); - model.addAttribute("books", books); - + model.addAttribute("books", bookService.findAllSortedByCategory()); return "books"; } diff --git a/src/main/java/com/wimdupont/personalweb/controller/ContactController.java b/src/main/java/com/wimdupont/personalweb/controller/ContactController.java @@ -1,6 +1,7 @@ package com.wimdupont.personalweb.controller; -import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.Resource; import org.springframework.http.MediaType; @@ -16,12 +17,12 @@ import java.io.IOException; import static com.wimdupont.personalweb.util.Constants.GPG_PUBLIC_KEY; -@Slf4j @Controller @RequestMapping("/contact") -@SuppressWarnings("unused") public class ContactController { + private static final Logger LOG = LoggerFactory.getLogger(ContactController.class); + @GetMapping public String getContact(Model model) { return "contact"; @@ -37,7 +38,7 @@ public class ContactController { .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(resource); } catch (IOException e) { - log.error(e.getMessage(), e); + LOG.error(e.getMessage(), e); } return null; } diff --git a/src/main/java/com/wimdupont/personalweb/controller/DonateController.java b/src/main/java/com/wimdupont/personalweb/controller/DonateController.java @@ -1,15 +1,12 @@ package com.wimdupont.personalweb.controller; -import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; -@Slf4j @Controller @RequestMapping("/donate") -@SuppressWarnings("unused") public class DonateController { @GetMapping diff --git a/src/main/java/com/wimdupont/personalweb/controller/FeedController.java b/src/main/java/com/wimdupont/personalweb/controller/FeedController.java @@ -2,20 +2,22 @@ package com.wimdupont.personalweb.controller; import com.rometools.rome.feed.rss.Channel; import com.wimdupont.personalweb.service.RssFeedGenerator; -import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.ResponseBody; -@RequiredArgsConstructor -@RestController +@Controller public class FeedController { private final RssFeedGenerator rssFeed; + public FeedController(RssFeedGenerator rssFeed) { + this.rssFeed = rssFeed; + } + @GetMapping(path = "/rss.xml") - @SuppressWarnings("unused") - public Channel getRss(Model model) { + public @ResponseBody Channel getRss(Model model) { return rssFeed.getChannel(); } } diff --git a/src/main/java/com/wimdupont/personalweb/controller/IndexController.java b/src/main/java/com/wimdupont/personalweb/controller/IndexController.java @@ -1,19 +1,20 @@ package com.wimdupont.personalweb.controller; import com.wimdupont.personalweb.api.AffirmationApi; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @Controller -@RequiredArgsConstructor public class IndexController { private final AffirmationApi affirmationApi; + public IndexController(AffirmationApi affirmationApi) { + this.affirmationApi = affirmationApi; + } + @GetMapping("/") - @SuppressWarnings("unused") public String home(Model model) { model.addAttribute("affirmation", affirmationApi.getAffirmation()); return "home"; diff --git a/src/main/java/com/wimdupont/personalweb/controller/LinkController.java b/src/main/java/com/wimdupont/personalweb/controller/LinkController.java @@ -7,7 +7,6 @@ import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/links") -@SuppressWarnings("unused") public class LinkController { @GetMapping diff --git a/src/main/java/com/wimdupont/personalweb/converter/BookToBookDtoConverter.java b/src/main/java/com/wimdupont/personalweb/converter/BookToBookDtoConverter.java @@ -9,7 +9,7 @@ public class BookToBookDtoConverter implements Converter<Book, BookDto> { @Override public BookDto convert(Book entity) { - return BookDto.builder() + return BookDto.Builder.newBuilder() .id(entity.getId()) .title(entity.getTitle()) .author(entity.getAuthor()) diff --git a/src/main/java/com/wimdupont/personalweb/model/FeedModel.java b/src/main/java/com/wimdupont/personalweb/model/FeedModel.java @@ -1,15 +0,0 @@ -package com.wimdupont.personalweb.model; - -import lombok.Data; - -import java.util.Date; - -@Data -public class FeedModel { - - private String title; - private String url; - private String summary; - private Date createdDate; - -} diff --git a/src/main/java/com/wimdupont/personalweb/model/dao/Book.java b/src/main/java/com/wimdupont/personalweb/model/dao/Book.java @@ -3,23 +3,15 @@ package com.wimdupont.personalweb.model.dao; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; import org.hibernate.annotations.GenericGenerator; @Entity -@Builder -@Data -@NoArgsConstructor -@AllArgsConstructor public class Book { @Id @GeneratedValue(generator = "uuid") - @GenericGenerator(name="uuid", strategy = "uuid") + @GenericGenerator(name = "uuid", strategy = "uuid") private String id; private String title; @@ -28,4 +20,60 @@ public class Book { private String category; private String series; private Double seriesNumber; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getSeries() { + return series; + } + + public void setSeries(String series) { + this.series = series; + } + + public Double getSeriesNumber() { + return seriesNumber; + } + + public void setSeriesNumber(Double seriesNumber) { + this.seriesNumber = seriesNumber; + } } diff --git a/src/main/java/com/wimdupont/personalweb/model/dto/ArticleDto.java b/src/main/java/com/wimdupont/personalweb/model/dto/ArticleDto.java @@ -1,16 +1,41 @@ package com.wimdupont.personalweb.model.dto; -import lombok.Builder; -import lombok.Value; - import java.time.LocalDate; -@Value -@Builder -public class ArticleDto { +public record ArticleDto( + String name, + LocalDate date +) { + + + private ArticleDto(Builder builder) { + this(builder.name, builder.date); + } + + public static final class Builder { + private String name; + private LocalDate date; + + private Builder() { + } + + public static Builder newBuilder() { + return new Builder(); + } + + public Builder name(String val) { + name = val; + return this; + } - String name; - LocalDate date; + public Builder date(LocalDate val) { + date = val; + return this; + } + public ArticleDto build() { + return new ArticleDto(this); + } + } } diff --git a/src/main/java/com/wimdupont/personalweb/model/dto/BookDto.java b/src/main/java/com/wimdupont/personalweb/model/dto/BookDto.java @@ -1,17 +1,79 @@ package com.wimdupont.personalweb.model.dto; -import lombok.Builder; -import lombok.Value; - -@Value -@Builder -public class BookDto { - - String id; - String title; - String author; - String isbn; - String category; - String series; - Double seriesNumber; +public record BookDto( + + String id, + String title, + String author, + String isbn, + String category, + String series, + Double seriesNumber +) { + + private BookDto(Builder builder) { + this(builder.id, + builder.title, + builder.author, + builder.isbn, + builder.category, + builder.series, + builder.seriesNumber); + } + + public static final class Builder { + private String id; + private String title; + private String author; + private String isbn; + private String category; + private String series; + private Double seriesNumber; + + private Builder() { + } + + public static Builder newBuilder() { + return new Builder(); + } + + public Builder id(String val) { + id = val; + return this; + } + + public Builder title(String val) { + title = val; + return this; + } + + public Builder author(String val) { + author = val; + return this; + } + + public Builder isbn(String val) { + isbn = val; + return this; + } + + public Builder category(String val) { + category = val; + return this; + } + + public Builder series(String val) { + series = val; + return this; + } + + public Builder seriesNumber(Double val) { + seriesNumber = val; + return this; + } + + public BookDto build() { + return new BookDto(this); + } + } } diff --git a/src/main/java/com/wimdupont/personalweb/service/AdocConverter.java b/src/main/java/com/wimdupont/personalweb/service/AdocConverter.java @@ -1,7 +1,6 @@ package com.wimdupont.personalweb.service; import jakarta.transaction.Transactional; -import lombok.extern.slf4j.Slf4j; import org.asciidoctor.Asciidoctor; import org.asciidoctor.Options; import org.asciidoctor.SafeMode; @@ -14,7 +13,6 @@ import java.nio.file.Path; @Service @Transactional -@Slf4j public class AdocConverter { private static final Asciidoctor ASCIIDOCTOR = Asciidoctor.Factory.create(); @@ -22,13 +20,8 @@ public class AdocConverter { .safe(SafeMode.UNSAFE) .build(); - public String convert(File file) { - try { - String article = Files.readString(Path.of(file.getAbsolutePath())); - return ASCIIDOCTOR.convert(article, OPTIONS); - } catch (IOException e) { - log.error(e.getMessage(), e); - } - return null; + public String convert(File file) throws IOException { + String article = Files.readString(Path.of(file.getAbsolutePath())); + return ASCIIDOCTOR.convert(article, OPTIONS); } } diff --git a/src/main/java/com/wimdupont/personalweb/service/ArticleService.java b/src/main/java/com/wimdupont/personalweb/service/ArticleService.java @@ -0,0 +1,57 @@ +package com.wimdupont.personalweb.service; + +import com.wimdupont.personalweb.model.dto.ArticleDto; +import com.wimdupont.personalweb.util.Constants.Article; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.Instant; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.TimeZone; + +@Service +public class ArticleService { + + public File[] getAdocArticles() { + return new File(Article.ARTICLES_DIRECTORY).listFiles(); + } + + public File[] getHtmlArticles() { + return new File(Article.HTML_ARTICLES_DIRECTORY).listFiles(); + } + + public String getHtmlArticle(String name, boolean addSuffix) throws IOException { + return Files.readString(Paths.get(String.format("%s/%s%s", Article.HTML_ARTICLES_DIRECTORY, name, + addSuffix ? Article.HTML_SUFFIX : ""))); + } + + public String toHtmlPathName(File adocArticle) { + return String.format("%s/%s", + Article.HTML_ARTICLES_DIRECTORY, + adocArticle.getName().replaceFirst(Article.ADOC_SUFFIX, Article.HTML_SUFFIX)); + } + + public List<ArticleDto> getArticles() { + List<ArticleDto> articles = new ArrayList<>(); + File[] files = getHtmlArticles(); + if (files != null) { + Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed()); + for (File htmlArticle : files) { + articles.add(ArticleDto.Builder.newBuilder() + .name(htmlArticle.getName().replaceFirst(Article.HTML_SUFFIX, "")) + .date(LocalDate.ofInstant(Instant.ofEpochMilli(htmlArticle.lastModified()), TimeZone.getDefault().toZoneId())) + .build() + ); + } + } + return articles; + } + +} diff --git a/src/main/java/com/wimdupont/personalweb/service/BlogArticleGenerator.java b/src/main/java/com/wimdupont/personalweb/service/BlogArticleGenerator.java @@ -1,9 +1,9 @@ package com.wimdupont.personalweb.service; -import com.wimdupont.personalweb.util.Constants; +import com.wimdupont.personalweb.util.Constants.Article; import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -12,34 +12,54 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; -@Slf4j @Service @Transactional -@RequiredArgsConstructor public class BlogArticleGenerator { + private static final Logger LOG = LoggerFactory.getLogger(BlogArticleGenerator.class); private final AdocConverter adocConverter; private final RssFeedGenerator rssFeedGenerator; + private final ArticleService articleService; + + public BlogArticleGenerator(AdocConverter adocConverter, + RssFeedGenerator rssFeedGenerator, + ArticleService articleService) { + this.adocConverter = adocConverter; + this.rssFeedGenerator = rssFeedGenerator; + this.articleService = articleService; + } @Scheduled(cron = "0 0 0 * * *") public void generate() { - log.info("Blog article generator started."); - File[] files = new File(Constants.ARTICLES_DIRECTORY).listFiles(); + LOG.info("Blog article generator started."); + File[] files = articleService.getAdocArticles(); if (files != null) { + createHtmlArticleDir(); for (File article : files) { - if (article.isFile() && article.getName().endsWith(".adoc") && !new File(String.format("%s/html/%s", Constants.ARTICLES_DIRECTORY, article.getName().replace(".adoc", ".html"))).exists()) { + String articlePathName = articleService.toHtmlPathName(article); + if (article.isFile() && article.getName().endsWith(Article.ADOC_SUFFIX) && !new File(articlePathName).exists()) { try { String htmlArticle = adocConverter.convert(article); - new File(String.format("%s/html/", Constants.ARTICLES_DIRECTORY)).mkdir(); - new File(String.format("%s/html/%s", Constants.ARTICLES_DIRECTORY, article.getName().replaceFirst(".adoc", ".html"))).createNewFile(); - Files.writeString(Paths.get(String.format("%s/html/%s", Constants.ARTICLES_DIRECTORY, article.getName().replaceFirst(".adoc", ".html"))), htmlArticle); - log.info("Article [{}] has been generated.", article.getName()); + if (new File(articlePathName).createNewFile()) { + LOG.debug("Article is created: {}", articlePathName); + } + Files.writeString(Paths.get(articlePathName), htmlArticle); + LOG.info("Article [{}] has been generated.", article.getName()); } catch (IOException e) { - log.error(e.getMessage(), e); + LOG.error(e.getMessage(), e); } } } } rssFeedGenerator.generate(); } + + private void createHtmlArticleDir() { + File htmlArticlesDir = new File(Article.HTML_ARTICLES_DIRECTORY); + if (!htmlArticlesDir.exists()) { + if (htmlArticlesDir.mkdir()) { + LOG.debug("Directory is created: {}", Article.HTML_ARTICLES_DIRECTORY); + } + } + } } diff --git a/src/main/java/com/wimdupont/personalweb/service/BookService.java b/src/main/java/com/wimdupont/personalweb/service/BookService.java @@ -1,22 +1,36 @@ package com.wimdupont.personalweb.service; -import com.wimdupont.personalweb.model.dao.Book; +import com.wimdupont.personalweb.converter.BookToBookDtoConverter; +import com.wimdupont.personalweb.model.dto.BookDto; import com.wimdupont.personalweb.repository.BookRepository; import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Service @Transactional -@RequiredArgsConstructor public class BookService { private final BookRepository bookRepository; + private final BookToBookDtoConverter bookToBookDtoConverter; - public List<Book> findAllSorted() { - return bookRepository.findAll(Sort.by("category", "author", "series", "seriesNumber", "title").ascending()); + public BookService(BookRepository bookRepository, + BookToBookDtoConverter bookToBookDtoConverter) { + this.bookRepository = bookRepository; + this.bookToBookDtoConverter = bookToBookDtoConverter; + } + + public Map<String, List<BookDto>> findAllSortedByCategory() { + return bookRepository.findAll(Sort.by("category", "author", "series", "seriesNumber", "title").ascending()) + .stream() + .map(bookToBookDtoConverter::convert) + .collect(Collectors.groupingBy(BookDto::category, + LinkedHashMap::new, + Collectors.mapping(book -> book, Collectors.toList()))); } } diff --git a/src/main/java/com/wimdupont/personalweb/service/RssFeedGenerator.java b/src/main/java/com/wimdupont/personalweb/service/RssFeedGenerator.java @@ -5,27 +5,33 @@ import com.rometools.rome.feed.rss.Content; import com.rometools.rome.feed.rss.Guid; import com.rometools.rome.feed.rss.Item; import com.wimdupont.personalweb.util.Constants; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import java.io.File; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Date; import java.util.List; -@Slf4j @Service public class RssFeedGenerator { - @Getter + private static final Logger LOG = LoggerFactory.getLogger(RssFeedGenerator.class); + private final ArticleService articleService; private Channel channel; + public RssFeedGenerator(ArticleService articleService) { + this.articleService = articleService; + } + + public Channel getChannel() { + return channel; + } + public void generate() { Channel channel = new Channel(); @@ -44,18 +50,18 @@ public class RssFeedGenerator { private List<Item> getItems() { List<Item> items = new ArrayList<>(); - File[] files = new File(String.format("%s/html", Constants.ARTICLES_DIRECTORY)).listFiles(); + File[] files = articleService.getHtmlArticles(); if (files != null) { Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed()); for (File article : files) { String articleString = null; try { - articleString = Files.readString(Paths.get(String.format("%s/html/%s", Constants.ARTICLES_DIRECTORY, article.getName()))); + articleString = articleService.getHtmlArticle(article.getName(), false); } catch (IOException e) { - log.error(e.getMessage(), e); + LOG.error(e.getMessage(), e); } - String title = article.getName().replace(".html", ""); + String title = article.getName().replace(Constants.Article.HTML_SUFFIX, ""); Item item = genericItem(new Date(article.lastModified()), title); item.setTitle(title); Content content = new Content(); diff --git a/src/main/java/com/wimdupont/personalweb/util/Constants.java b/src/main/java/com/wimdupont/personalweb/util/Constants.java @@ -1,11 +1,19 @@ package com.wimdupont.personalweb.util; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) public class Constants { - public static final String ARTICLES_DIRECTORY = System.getProperty("user.home") + "/personalweb/articles"; - public static final String GPG_PUBLIC_KEY = System.getProperty("user.home") + "/personalweb/gpg/pub.asc"; + private Constants() { + } + + public static class Article { + private Article() { + } + + public static final String ARTICLES_DIRECTORY = System.getProperty("user.home") + "/personalweb/articles"; + public static final String HTML_ARTICLES_DIRECTORY = ARTICLES_DIRECTORY + "/html"; + public static final String HTML_SUFFIX = ".html"; + public static final String ADOC_SUFFIX = ".adoc"; + } + + public static final String GPG_PUBLIC_KEY = System.getProperty("user.home") + "/personalweb/gpg/pub.asc"; } diff --git a/src/test/java/com/wimdupont/personalweb/converter/BookToBookDtoConverterTest.java b/src/test/java/com/wimdupont/personalweb/converter/BookToBookDtoConverterTest.java @@ -13,6 +13,8 @@ class BookToBookDtoConverterTest { private static final String AUTHOR = "author"; private static final String ISBN = "isbn"; private static final String CATEGORY = "category"; + private static final String SERIES = "series"; + private static final Double SERIES_NUMBER = 2.5; private BookToBookDtoConverter converter; private Book book; @@ -20,13 +22,14 @@ class BookToBookDtoConverterTest { @BeforeEach void setup() { converter = new BookToBookDtoConverter(); - book = Book.builder() - .id(ID) - .title(TITLE) - .author(AUTHOR) - .isbn(ISBN) - .category(CATEGORY) - .build(); + book = new Book(); + book.setId(ID); + book.setTitle(TITLE); + book.setAuthor(AUTHOR); + book.setIsbn(ISBN); + book.setCategory(CATEGORY); + book.setSeries(SERIES); + book.setSeriesNumber(SERIES_NUMBER); } @Test