summaryrefslogtreecommitdiff
path: root/clams-server/src/main/java/no
diff options
context:
space:
mode:
Diffstat (limited to 'clams-server/src/main/java/no')
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/config/AppContext.java24
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/config/AppRoutes.java14
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ArticleController.java31
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ArticlesController.java132
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/BlogController.java132
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/MediaController.java2
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/PostController.java31
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Article.java12
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/ArticleDTO.java4
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/ArticleMetaData.java6
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Post.java12
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/PostDTO.java4
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/PostMetaData.java6
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ArticlesRepo.java17
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ArticlesRepoSqlite.java (renamed from clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/BlogPostRepoSqlite.java)93
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/BlogPostRepo.java17
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/SqliteManager.java6
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/ArticlesSearchService.java44
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/BlogSearchService.java44
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/SlugService.java10
20 files changed, 321 insertions, 320 deletions
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/config/AppContext.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/config/AppContext.java
index 9f88053..c3c987e 100644
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/config/AppContext.java
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/config/AppContext.java
@@ -1,11 +1,11 @@
package no.eliashaugsbakk.clams.server.config;
import java.nio.file.Path;
-import no.eliashaugsbakk.clams.server.controller.BlogController;
+import no.eliashaugsbakk.clams.server.controller.ArticlesController;
import no.eliashaugsbakk.clams.server.controller.MediaController;
-import no.eliashaugsbakk.clams.server.controller.PostController;
-import no.eliashaugsbakk.clams.server.repository.BlogPostRepo;
-import no.eliashaugsbakk.clams.server.repository.BlogPostRepoSqlite;
+import no.eliashaugsbakk.clams.server.controller.ArticleController;
+import no.eliashaugsbakk.clams.server.repository.ArticlesRepo;
+import no.eliashaugsbakk.clams.server.repository.ArticlesRepoSqlite;
import no.eliashaugsbakk.clams.server.repository.MediaRepo;
import no.eliashaugsbakk.clams.server.repository.MediaRepoSqlite;
import no.eliashaugsbakk.clams.server.repository.SqliteManager;
@@ -14,9 +14,9 @@ import no.eliashaugsbakk.clams.server.service.SlugService;
public class AppContext implements AutoCloseable {
private final SqliteManager dbManager;
- private final BlogController blogController;
+ private final ArticlesController articlesController;
private final MediaController mediaController;
- private final PostController postController;
+ private final ArticleController articleController;
private final AuthService authService;
public AppContext() {
@@ -27,19 +27,19 @@ public class AppContext implements AutoCloseable {
this.dbManager = new SqliteManager(dbUrl);
this.dbManager.init();
- BlogPostRepo blogPostRepo = new BlogPostRepoSqlite(dbManager);
+ ArticlesRepo articlesRepo = new ArticlesRepoSqlite(dbManager);
MediaRepo mediaRepo = new MediaRepoSqlite(dbManager);
- SlugService slugService = new SlugService(blogPostRepo);
+ SlugService slugService = new SlugService(articlesRepo);
- this.blogController = new BlogController(dbManager);
+ this.articlesController = new ArticlesController(dbManager);
this.mediaController = new MediaController(mediaRepo, appConfig);
- this.postController = new PostController(blogPostRepo, slugService);
+ this.articleController = new ArticleController(articlesRepo, slugService);
this.authService = new AuthService(appConfig);
}
- public BlogController getBlogController() { return blogController; }
+ public ArticlesController getArticlesController() { return articlesController; }
public MediaController getMediaController() { return mediaController; }
- public PostController getPostController() { return postController; }
+ public ArticleController getArticleController() { return articleController; }
public AuthService getAuthService() { return authService; }
@Override
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/config/AppRoutes.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/config/AppRoutes.java
index fb5c936..3df4d6d 100644
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/config/AppRoutes.java
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/config/AppRoutes.java
@@ -25,9 +25,9 @@ public class AppRoutes implements EndpointGroup {
get("/projects", ctx -> ctx.render("templates/projects.html",
Map.of("page_title", "Projects - Elias Haugsbakk", "page_css", "projects")));
- path("blog", () -> {
- get(appContext.getBlogController()::handleBlogRequest);
- get("{slug}", appContext.getBlogController()::handleGetPost);
+ path("articles", () -> {
+ get(appContext.getArticlesController()::handleArticlesRequest);
+ get("{slug}", appContext.getArticlesController()::handleGetArticle);
});
path("api", () -> {
@@ -50,13 +50,13 @@ public class AppRoutes implements EndpointGroup {
}
});
- post("posts", appContext.getPostController()::handlePostPost);
- put("posts/{slug}", appContext.getPostController()::handlePutPost);
- delete("posts/{slug}", appContext.getPostController()::handleDeletePost);
+ post("articles", appContext.getArticleController()::handleArticleArticle);
+ put("articles/{slug}", appContext.getArticleController()::handlePutArticle);
+ delete("articles/{slug}", appContext.getArticleController()::handleDeleteArticle);
get("media", appContext.getMediaController()::handleGetMediaIndex);
get("media/{uuid}", appContext.getMediaController()::handleGetMedia);
- post("media", appContext.getMediaController()::handlePostMedia);
+ post("media", appContext.getMediaController()::handleArticleMedia);
delete("media/{uuid}", appContext.getMediaController()::handleDeleteMedia);
});
}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ArticleController.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ArticleController.java
new file mode 100644
index 0000000..a57414f
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ArticleController.java
@@ -0,0 +1,31 @@
+package no.eliashaugsbakk.clams.server.controller;
+
+import io.javalin.http.Context;
+import no.eliashaugsbakk.clams.server.model.Article;
+import no.eliashaugsbakk.clams.server.model.ArticleDTO;
+import no.eliashaugsbakk.clams.server.repository.ArticlesRepo;
+import no.eliashaugsbakk.clams.server.service.SlugService;
+
+public class ArticleController {
+ private final ArticlesRepo articlesRepo;
+ private final SlugService slugService;
+
+ public ArticleController(ArticlesRepo articlesRepo, SlugService slugService) {
+ this.articlesRepo = articlesRepo;
+ this.slugService = slugService;
+ }
+
+ public void handleArticleArticle(Context ctx) {
+ ArticleDTO newArticle = ctx.bodyAsClass(ArticleDTO.class);
+ articlesRepo.addArticle(new Article(newArticle, slugService.toSlug(newArticle.title())));
+ }
+
+ public void handlePutArticle(Context ctx) {
+ ArticleDTO updatedArticle = ctx.bodyAsClass(ArticleDTO.class);
+ articlesRepo.updateArticle(new Article(updatedArticle, ctx.pathParam("slug")));
+ }
+
+ public void handleDeleteArticle(Context ctx) {
+ articlesRepo.deleteArticle(ctx.pathParam("slug"));
+ }
+}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ArticlesController.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ArticlesController.java
new file mode 100644
index 0000000..fb53d86
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ArticlesController.java
@@ -0,0 +1,132 @@
+package no.eliashaugsbakk.clams.server.controller;
+
+import io.javalin.http.Context;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+import no.eliashaugsbakk.clams.server.model.Article;
+import no.eliashaugsbakk.clams.server.model.ArticleMetaData;
+import no.eliashaugsbakk.clams.server.repository.ArticlesRepo;
+import no.eliashaugsbakk.clams.server.repository.ArticlesRepoSqlite;
+import no.eliashaugsbakk.clams.server.repository.SqliteManager;
+import no.eliashaugsbakk.clams.server.service.ArticlesSearchService;
+import no.eliashaugsbakk.clams.server.utils.MarkdownConverter;
+
+public class ArticlesController {
+ private static final ZoneId OSLO_ZONE = ZoneId.of("Europe/Oslo");
+ private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("MMM dd, yyyy");
+
+ private final ArticlesRepo articlesRepo;
+ private final ArticlesSearchService articlesSearchService;
+
+ public record SearchResultItem(String title, String slug, String summary, String formattedDate) {}
+
+ public ArticlesController(SqliteManager sqliteManager) {
+ this.articlesRepo = new ArticlesRepoSqlite(sqliteManager);
+ this.articlesSearchService = new ArticlesSearchService(articlesRepo);
+ }
+
+ public void handleGetArticle(Context ctx) {
+ var articleOpt = articlesRepo.getArticle(ctx.pathParam("slug"));
+
+ if (articleOpt.isEmpty()) {
+ ctx.status(404);
+ return;
+ }
+
+ Article article = articleOpt.get();
+
+ if (!article.isPublished()) {
+ ctx.status(404);
+ return;
+ }
+
+ String formattedDate = article.timePublished().atZone(OSLO_ZONE).format(DATE_FORMATTER);
+
+ ctx.render("templates/article.html", Map.of(
+ "page_title", article.title() + " -- Elias Haugsbakk",
+ "page_css", "article",
+ "title", article.title(),
+ "published_date", formattedDate,
+ "author", "by Elias Haugsbakk",
+ "content", MarkdownConverter.convertToHtml(article.content()),
+ "back_to_index", "<a href=\"/articles/\">back to all articles</a>"
+ ));
+ }
+
+ public void handleArticlesRequest(Context ctx) {
+ String searchTerm = ctx.queryParam("search");
+ if (searchTerm != null) {
+ handleSearch(ctx, searchTerm);
+ } else {
+ handleArticlesIndex(ctx);
+ }
+ }
+
+ private void handleArticlesIndex(Context ctx) {
+ List<ArticleMetaData> allArticles = articlesRepo.listArticlesMetaData().stream()
+ .filter(ArticleMetaData::isPublished)
+ .toList();
+ Map<Integer, List<ArticleMetaData>> articlesByYear = groupArticlesByYear(allArticles);
+
+ var featuredSlugs = List.of(
+ ""
+ );
+
+ List<Article> featuredArticles = new ArrayList<>();
+ for (String slug : featuredSlugs) {
+ articlesRepo.getArticle(slug).ifPresent(featuredArticles::add);
+ }
+
+ ctx.render("templates/articles.html",
+ Map.of(
+ "page_title", "My articles",
+ "page_css", "articles",
+ "articles_by_year", articlesByYear,
+ "featured_articles", featuredArticles,
+ "search_value", ""
+ ));
+ }
+
+ private void handleSearch(Context ctx, String searchTerm) {
+ String query = searchTerm.trim();
+ List<ArticleMetaData> results = query.isEmpty() ? List.of() : articlesSearchService.searchArticles(query);
+
+ List<SearchResultItem> resultItems = results.stream()
+ .filter(ArticleMetaData::isPublished)
+ .map(article -> new SearchResultItem(
+ article.title(),
+ article.slug(),
+ article.summary() != null ? article.summary() : "",
+ article.timePublished().atZone(OSLO_ZONE).format(DATE_FORMATTER)
+ ))
+ .toList();
+
+ ctx.render("templates/articles-search.html",
+ Map.of(
+ "page_title", "Search Results -- Elias Haugsbakk",
+ "page_css", "articles",
+ "search_term", query,
+ "results", resultItems,
+ "results_count", resultItems.size()
+ ));
+ }
+
+ private Map<Integer, List<ArticleMetaData>> groupArticlesByYear(List<ArticleMetaData> articles) {
+ Map<Integer, List<ArticleMetaData>> unsortedGroups = articles.stream()
+ .collect(Collectors.groupingBy(
+ article -> article.timePublished().atZone(OSLO_ZONE).getYear(),
+ Collectors.toList()
+ ));
+
+ Map<Integer, List<ArticleMetaData>> sortedGroups = new TreeMap<>(Comparator.reverseOrder());
+ sortedGroups.putAll(unsortedGroups);
+
+ return sortedGroups;
+ }
+}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/BlogController.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/BlogController.java
deleted file mode 100644
index 33a6ac6..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/BlogController.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package no.eliashaugsbakk.clams.server.controller;
-
-import io.javalin.http.Context;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.stream.Collectors;
-import no.eliashaugsbakk.clams.server.model.Post;
-import no.eliashaugsbakk.clams.server.model.PostMetaData;
-import no.eliashaugsbakk.clams.server.repository.BlogPostRepo;
-import no.eliashaugsbakk.clams.server.repository.BlogPostRepoSqlite;
-import no.eliashaugsbakk.clams.server.repository.SqliteManager;
-import no.eliashaugsbakk.clams.server.service.BlogSearchService;
-import no.eliashaugsbakk.clams.server.utils.MarkdownConverter;
-
-public class BlogController {
- private static final ZoneId OSLO_ZONE = ZoneId.of("Europe/Oslo");
- private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("MMM dd, yyyy");
-
- private final BlogPostRepo blogPostRepo;
- private final BlogSearchService blogSearchService;
-
- public record SearchResultItem(String title, String slug, String summary, String formattedDate) {}
-
- public BlogController(SqliteManager sqliteManager) {
- this.blogPostRepo = new BlogPostRepoSqlite(sqliteManager);
- this.blogSearchService = new BlogSearchService(blogPostRepo);
- }
-
- public void handleGetPost(Context ctx) {
- var postOpt = blogPostRepo.getPost(ctx.pathParam("slug"));
-
- if (postOpt.isEmpty()) {
- ctx.status(404);
- return;
- }
-
- Post post = postOpt.get();
-
- if (!post.isPublished()) {
- ctx.status(404);
- return;
- }
-
- String formattedDate = post.timePublished().atZone(OSLO_ZONE).format(DATE_FORMATTER);
-
- ctx.render("templates/post.html", Map.of(
- "page_title", post.title() + " -- Elias Haugsbakk",
- "page_css", "post",
- "title", post.title(),
- "published_date", formattedDate,
- "author", "by Elias Haugsbakk",
- "content", MarkdownConverter.convertToHtml(post.content()),
- "back_to_index", "<a href=\"/blog/\">back to all posts</a>"
- ));
- }
-
- public void handleBlogRequest(Context ctx) {
- String searchTerm = ctx.queryParam("search");
- if (searchTerm != null) {
- handleSearch(ctx, searchTerm);
- } else {
- handleBlogIndex(ctx);
- }
- }
-
- private void handleBlogIndex(Context ctx) {
- List<PostMetaData> allPosts = blogPostRepo.listPostsMetaData().stream()
- .filter(PostMetaData::isPublished)
- .toList();
- Map<Integer, List<PostMetaData>> postsByYear = groupPostsByYear(allPosts);
-
- var featuredSlugs = List.of(
- ""
- );
-
- List<Post> featuredPosts = new ArrayList<>();
- for (String slug : featuredSlugs) {
- blogPostRepo.getPost(slug).ifPresent(featuredPosts::add);
- }
-
- ctx.render("templates/blog.html",
- Map.of(
- "page_title", "Elias Haugsbakk's Blog",
- "page_css", "blog",
- "posts_by_year", postsByYear,
- "featured_posts", featuredPosts,
- "search_value", ""
- ));
- }
-
- private void handleSearch(Context ctx, String searchTerm) {
- String query = searchTerm.trim();
- List<PostMetaData> results = query.isEmpty() ? List.of() : blogSearchService.searchPosts(query);
-
- List<SearchResultItem> resultItems = results.stream()
- .filter(PostMetaData::isPublished)
- .map(post -> new SearchResultItem(
- post.title(),
- post.slug(),
- post.summary() != null ? post.summary() : "",
- post.timePublished().atZone(OSLO_ZONE).format(DATE_FORMATTER)
- ))
- .toList();
-
- ctx.render("templates/blog-search.html",
- Map.of(
- "page_title", "Search Results -- Elias Haugsbakk",
- "page_css", "blog",
- "search_term", query,
- "results", resultItems,
- "results_count", resultItems.size()
- ));
- }
-
- private Map<Integer, List<PostMetaData>> groupPostsByYear(List<PostMetaData> posts) {
- Map<Integer, List<PostMetaData>> unsortedGroups = posts.stream()
- .collect(Collectors.groupingBy(
- post -> post.timePublished().atZone(OSLO_ZONE).getYear(),
- Collectors.toList()
- ));
-
- Map<Integer, List<PostMetaData>> sortedGroups = new TreeMap<>(Comparator.reverseOrder());
- sortedGroups.putAll(unsortedGroups);
-
- return sortedGroups;
- }
-}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/MediaController.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/MediaController.java
index 8855b7b..d4e40b9 100644
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/MediaController.java
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/MediaController.java
@@ -28,7 +28,7 @@ public class MediaController {
this.appConfig = appConfig;
}
- public void handlePostMedia(Context ctx) {
+ public void handleArticleMedia(Context ctx) {
UploadedFile file = ctx.uploadedFile("image");
if (file == null) {
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/PostController.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/PostController.java
deleted file mode 100644
index 93976fd..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/PostController.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package no.eliashaugsbakk.clams.server.controller;
-
-import io.javalin.http.Context;
-import no.eliashaugsbakk.clams.server.model.Post;
-import no.eliashaugsbakk.clams.server.model.PostDTO;
-import no.eliashaugsbakk.clams.server.repository.BlogPostRepo;
-import no.eliashaugsbakk.clams.server.service.SlugService;
-
-public class PostController {
- private final BlogPostRepo blogPostRepo;
- private final SlugService slugService;
-
- public PostController(BlogPostRepo blogPostRepo, SlugService slugService) {
- this.blogPostRepo = blogPostRepo;
- this.slugService = slugService;
- }
-
- public void handlePostPost(Context ctx) {
- PostDTO newPost = ctx.bodyAsClass(PostDTO.class);
- blogPostRepo.addBlogPost(new Post(newPost, slugService.toSlug(newPost.title())));
- }
-
- public void handlePutPost(Context ctx) {
- PostDTO updatedPost = ctx.bodyAsClass(PostDTO.class);
- blogPostRepo.updateBlogPost(new Post(updatedPost, ctx.pathParam("slug")));
- }
-
- public void handleDeletePost(Context ctx) {
- blogPostRepo.deleteBlogPost(ctx.pathParam("slug"));
- }
-}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Article.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Article.java
new file mode 100644
index 0000000..b74a79b
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Article.java
@@ -0,0 +1,12 @@
+package no.eliashaugsbakk.clams.server.model;
+
+import java.time.Instant;
+
+public record Article(String title, String slug, String summary, Instant timePublished, Instant lastEdited, String content,
+ boolean isPublished) {
+ public Article(ArticleDTO articleDTO, String slug) {
+
+ this(articleDTO.title(), slug, articleDTO.summary(), Instant.now(), Instant.now(), articleDTO.content(),
+ articleDTO.isPublished());
+ }
+}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/ArticleDTO.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/ArticleDTO.java
new file mode 100644
index 0000000..27207d7
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/ArticleDTO.java
@@ -0,0 +1,4 @@
+package no.eliashaugsbakk.clams.server.model;
+
+public record ArticleDTO(String title, String summary, String content, boolean isPublished) {
+}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/ArticleMetaData.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/ArticleMetaData.java
new file mode 100644
index 0000000..8e71d78
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/ArticleMetaData.java
@@ -0,0 +1,6 @@
+package no.eliashaugsbakk.clams.server.model;
+
+import java.time.Instant;
+
+public record ArticleMetaData(String title, String slug, String summary, Instant timePublished, Instant lastEdit, Boolean isPublished) {
+}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Post.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Post.java
deleted file mode 100644
index 4a7fcf6..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Post.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package no.eliashaugsbakk.clams.server.model;
-
-import java.time.Instant;
-
-public record Post(String title, String slug, String summary, Instant timePublished, String content,
- boolean isPublished) {
- public Post(PostDTO postDTO, String slug) {
-
- this(postDTO.title(), slug, postDTO.summary(), Instant.now(), postDTO.content(),
- postDTO.isPublished());
- }
-}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/PostDTO.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/PostDTO.java
deleted file mode 100644
index 12254da..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/PostDTO.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package no.eliashaugsbakk.clams.server.model;
-
-public record PostDTO(String title, String summary, String content, boolean isPublished) {
-}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/PostMetaData.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/PostMetaData.java
deleted file mode 100644
index 175fc55..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/PostMetaData.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package no.eliashaugsbakk.clams.server.model;
-
-import java.time.Instant;
-
-public record PostMetaData(String title, String slug, String summary, Instant timePublished, Instant lastEdit, Boolean isPublished) {
-}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ArticlesRepo.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ArticlesRepo.java
new file mode 100644
index 0000000..221be74
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ArticlesRepo.java
@@ -0,0 +1,17 @@
+package no.eliashaugsbakk.clams.server.repository;
+
+import java.util.List;
+import java.util.Optional;
+import no.eliashaugsbakk.clams.server.model.Article;
+import no.eliashaugsbakk.clams.server.model.ArticleMetaData;
+
+public interface ArticlesRepo {
+ List<ArticleMetaData> listArticlesMetaData();
+ Optional<Article> getArticle(String slug);
+ List<ArticleMetaData> searchArticlesBody(String query);
+
+ void addArticle(Article article);
+ void updateArticle(Article article);
+ void deleteArticle(String slug);
+ boolean existsArticleBySlug(String slug);
+}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/BlogPostRepoSqlite.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ArticlesRepoSqlite.java
index 754c915..86a615b 100644
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/BlogPostRepoSqlite.java
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ArticlesRepoSqlite.java
@@ -8,25 +8,25 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
-import no.eliashaugsbakk.clams.server.model.Post;
-import no.eliashaugsbakk.clams.server.model.PostMetaData;
+import no.eliashaugsbakk.clams.server.model.Article;
+import no.eliashaugsbakk.clams.server.model.ArticleMetaData;
-public class BlogPostRepoSqlite implements BlogPostRepo {
+public class ArticlesRepoSqlite implements ArticlesRepo {
private final SqliteManager manager;
- public BlogPostRepoSqlite(SqliteManager manager) {
+ public ArticlesRepoSqlite(SqliteManager manager) {
this.manager = manager;
}
@Override
- public List<PostMetaData> listPostsMetaData() {
+ public List<ArticleMetaData> listArticlesMetaData() {
String sql = """
SELECT title, slug, summary, published, last_edited, is_published
- FROM posts
+ FROM articles
ORDER BY published DESC
""";
- List<PostMetaData> posts = new ArrayList<>();
+ List<ArticleMetaData> articles = new ArrayList<>();
try (Connection conn = manager.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
@@ -41,21 +41,21 @@ public class BlogPostRepoSqlite implements BlogPostRepo {
Instant lastEdit = (lastEditRaw != null) ? Instant.parse(lastEditRaw) : null;
boolean isPublished = resultSet.getBoolean("is_published");
- posts.add(new PostMetaData(title, slug, summary, published, lastEdit, isPublished));
+ articles.add(new ArticleMetaData(title, slug, summary, published, lastEdit, isPublished));
}
- return posts;
+ return articles;
} catch (SQLException e) {
- throw new RepoException("Error fetching all post metadata sorted by time", e);
+ throw new RepoException("Error fetching all article metadata sorted by time", e);
}
}
@Override
- public Optional<Post> getPost(String slug) {
+ public Optional<Article> getArticle(String slug) {
String sql = """
- SELECT title, slug, summary, content, published, is_published
- FROM posts
+ SELECT title, slug, summary, content, published, last_edited, is_published
+ FROM articles
WHERE slug = ?
""";
@@ -67,32 +67,33 @@ public class BlogPostRepoSqlite implements BlogPostRepo {
try (ResultSet resultSet = stmt.executeQuery()) {
if (resultSet.next()) {
String title = resultSet.getString("title");
- String postSlug = resultSet.getString("slug");
+ String articleSlug = resultSet.getString("slug");
String summary = resultSet.getString("summary");
String content = resultSet.getString("content");
Instant published = Instant.parse(resultSet.getString("published"));
+ Instant lastEdited = Instant.parse(resultSet.getString("last_edited"));
boolean isPublished = resultSet.getBoolean("is_published");
- return Optional.of(new Post(title, postSlug, summary, published, content, isPublished));
+ return Optional.of(new Article(title, articleSlug, summary, published, lastEdited, content, isPublished));
}
return Optional.empty();
}
} catch (SQLException e) {
- throw new RepoException("Error fetching full post by slug: " + slug, e);
+ throw new RepoException("Error fetching full article by slug: " + slug, e);
}
}
@Override
- public List<PostMetaData> searchPostsBody(String query) {
+ public List<ArticleMetaData> searchArticlesBody(String query) {
String sql = """
SELECT title, slug, summary, published, last_edited, is_published
- FROM posts
+ FROM articles
WHERE content LIKE ?
ORDER BY published DESC
""";
- List<PostMetaData> posts = new ArrayList<>();
+ List<ArticleMetaData> articles = new ArrayList<>();
try (Connection conn = manager.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
@@ -109,45 +110,45 @@ public class BlogPostRepoSqlite implements BlogPostRepo {
Instant lastEdit = Instant.parse(resultSet.getString("last_edited"));
boolean isPublished = resultSet.getBoolean("is_published");
- posts.add(new PostMetaData(title, slug, summary, published, lastEdit, isPublished));
+ articles.add(new ArticleMetaData(title, slug, summary, published, lastEdit, isPublished));
}
}
- return posts;
+ return articles;
} catch (SQLException e) {
- throw new RepoException("Error searching posts for query: " + query, e);
+ throw new RepoException("Error searching articles for query: " + query, e);
}
}
@Override
- public void addBlogPost(Post post) {
+ public void addArticle(Article article) {
String sql = """
- INSERT INTO posts (slug, title, content, summary, published, is_published)
+ INSERT INTO articles (slug, title, content, summary, published, is_published)
VALUES (?, ?, ?, ?, ?, ?)
""";
try (Connection conn = manager.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
- stmt.setString(1, post.slug());
- stmt.setString(2, post.title());
- stmt.setString(3, post.content());
- stmt.setString(4, post.summary());
- stmt.setString(5, post.timePublished().toString());
- stmt.setBoolean(6, post.isPublished());
+ stmt.setString(1, article.slug());
+ stmt.setString(2, article.title());
+ stmt.setString(3, article.content());
+ stmt.setString(4, article.summary());
+ stmt.setString(5, article.timePublished().toString());
+ stmt.setBoolean(6, article.isPublished());
stmt.executeUpdate();
} catch (SQLException e) {
- throw new RepoException("Error adding blog post: " + post.slug(), e);
+ throw new RepoException("Error adding articles article: " + article.slug(), e);
}
}
@Override
- public void updateBlogPost(Post post) {
+ public void updateArticle(Article article) {
String sql = """
- UPDATE posts
+ UPDATE articles
SET title = ?, content = ?, summary = ?, published = ?, last_edited = ?, is_published = ?
WHERE slug = ?
""";
@@ -155,25 +156,25 @@ public class BlogPostRepoSqlite implements BlogPostRepo {
try (Connection conn = manager.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
- stmt.setString(1, post.title());
- stmt.setString(2, post.content());
- stmt.setString(3, post.summary());
- stmt.setString(4, post.timePublished().toString());
+ stmt.setString(1, article.title());
+ stmt.setString(2, article.content());
+ stmt.setString(3, article.summary());
+ stmt.setString(4, article.timePublished().toString());
stmt.setString(5, Instant.now().toString());
- stmt.setBoolean(6, post.isPublished());
- stmt.setString(7, post.slug());
+ stmt.setBoolean(6, article.isPublished());
+ stmt.setString(7, article.slug());
stmt.executeUpdate();
} catch (SQLException e) {
- throw new RepoException("Error updating blog post: " + post.slug(), e);
+ throw new RepoException("Error updating articles article: " + article.slug(), e);
}
}
@Override
- public void deleteBlogPost(String slug) {
+ public void deleteArticle(String slug) {
String sql = """
- DELETE FROM posts
+ DELETE FROM articles
WHERE slug = ?
""";
@@ -185,15 +186,15 @@ public class BlogPostRepoSqlite implements BlogPostRepo {
stmt.executeUpdate();
} catch (SQLException e) {
- throw new RepoException("Error deleting blog post: " + slug, e);
+ throw new RepoException("Error deleting articles article: " + slug, e);
}
}
@Override
- public boolean existsPostBySlug(String slug) {
+ public boolean existsArticleBySlug(String slug) {
String sql = """
SELECT 1
- FROM posts
+ FROM articles
WHERE slug = ?
LIMIT 1
""";
@@ -208,7 +209,7 @@ public class BlogPostRepoSqlite implements BlogPostRepo {
}
} catch (SQLException e) {
- throw new RepoException("Error checking existence of post by slug: " + slug, e);
+ throw new RepoException("Error checking existence of article by slug: " + slug, e);
}
}
}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/BlogPostRepo.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/BlogPostRepo.java
deleted file mode 100644
index 6455f7d..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/BlogPostRepo.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package no.eliashaugsbakk.clams.server.repository;
-
-import java.util.List;
-import java.util.Optional;
-import no.eliashaugsbakk.clams.server.model.Post;
-import no.eliashaugsbakk.clams.server.model.PostMetaData;
-
-public interface BlogPostRepo {
- List<PostMetaData> listPostsMetaData();
- Optional<Post> getPost(String slug);
- List<PostMetaData> searchPostsBody(String query);
-
- void addBlogPost(Post post);
- void updateBlogPost(Post post);
- void deleteBlogPost(String slug);
- boolean existsPostBySlug(String slug);
-}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/SqliteManager.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/SqliteManager.java
index 06a4ee2..4054ae4 100644
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/SqliteManager.java
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/SqliteManager.java
@@ -25,8 +25,8 @@ public class SqliteManager implements AutoCloseable {
}
public void init() {
- String posts = """
- CREATE TABLE IF NOT EXISTS posts (
+ String articles = """
+ CREATE TABLE IF NOT EXISTS articles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT NOT NULL UNIQUE,
title TEXT NOT NULL,
@@ -49,7 +49,7 @@ public class SqliteManager implements AutoCloseable {
try (Connection conn = dataSource.getConnection(); Statement stmt = conn.createStatement()) {
- stmt.execute(posts);
+ stmt.execute(articles);
stmt.execute(images);
} catch (SQLException e) {
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/ArticlesSearchService.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/ArticlesSearchService.java
new file mode 100644
index 0000000..db68063
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/ArticlesSearchService.java
@@ -0,0 +1,44 @@
+package no.eliashaugsbakk.clams.server.service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import no.eliashaugsbakk.clams.server.model.ArticleMetaData;
+import no.eliashaugsbakk.clams.server.repository.ArticlesRepo;
+
+public class ArticlesSearchService {
+ private final ArticlesRepo articlesRepo;
+
+ public ArticlesSearchService(ArticlesRepo articlesRepo) {
+ this.articlesRepo = articlesRepo;
+ }
+
+ public List<ArticleMetaData> searchArticles(String query) {
+ if (query == null || query.isBlank()) return List.of();
+
+ int titleValue = 10;
+ int summaryValue = 5;
+ int bodyValue = 1;
+
+ Map<ArticleMetaData, Integer> searchRanking = new HashMap<>();
+ String lowerQuery = query.toLowerCase();
+
+ List<ArticleMetaData> articlesMetaData = articlesRepo.listArticlesMetaData();
+ List<ArticleMetaData> bodyResults = articlesRepo.searchArticlesBody(query);
+
+ articlesMetaData.stream()
+ .filter(article -> article.title().toLowerCase().contains(lowerQuery))
+ .forEach(article -> searchRanking.merge(article, titleValue, Integer::sum));
+
+ articlesMetaData.stream()
+ .filter(article -> article.summary() != null && article.summary().toLowerCase().contains(lowerQuery))
+ .forEach(article -> searchRanking.merge(article, summaryValue, Integer::sum));
+
+ bodyResults.forEach(article -> searchRanking.merge(article, bodyValue, Integer::sum));
+
+ return searchRanking.entrySet().stream()
+ .sorted((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue()))
+ .map(Map.Entry::getKey)
+ .toList();
+ }
+}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/BlogSearchService.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/BlogSearchService.java
deleted file mode 100644
index afc47f5..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/BlogSearchService.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package no.eliashaugsbakk.clams.server.service;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import no.eliashaugsbakk.clams.server.model.PostMetaData;
-import no.eliashaugsbakk.clams.server.repository.BlogPostRepo;
-
-public class BlogSearchService {
- private final BlogPostRepo blogPostRepo;
-
- public BlogSearchService(BlogPostRepo blogPostRepo) {
- this.blogPostRepo = blogPostRepo;
- }
-
- public List<PostMetaData> searchPosts(String query) {
- if (query == null || query.isBlank()) return List.of();
-
- int titleValue = 10;
- int summaryValue = 5;
- int bodyValue = 1;
-
- Map<PostMetaData, Integer> searchRanking = new HashMap<>();
- String lowerQuery = query.toLowerCase();
-
- List<PostMetaData> postsMetaData = blogPostRepo.listPostsMetaData();
- List<PostMetaData> bodyResults = blogPostRepo.searchPostsBody(query);
-
- postsMetaData.stream()
- .filter(post -> post.title().toLowerCase().contains(lowerQuery))
- .forEach(post -> searchRanking.merge(post, titleValue, Integer::sum));
-
- postsMetaData.stream()
- .filter(post -> post.summary() != null && post.summary().toLowerCase().contains(lowerQuery))
- .forEach(post -> searchRanking.merge(post, summaryValue, Integer::sum));
-
- bodyResults.forEach(post -> searchRanking.merge(post, bodyValue, Integer::sum));
-
- return searchRanking.entrySet().stream()
- .sorted((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue()))
- .map(Map.Entry::getKey)
- .toList();
- }
-}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/SlugService.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/SlugService.java
index 19af1da..7d356ce 100644
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/SlugService.java
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/SlugService.java
@@ -3,15 +3,15 @@ package no.eliashaugsbakk.clams.server.service;
import java.text.Normalizer;
import java.util.Locale;
import java.util.regex.Pattern;
-import no.eliashaugsbakk.clams.server.repository.BlogPostRepo;
+import no.eliashaugsbakk.clams.server.repository.ArticlesRepo;
public class SlugService {
- private final BlogPostRepo blogPostRepo;
+ private final ArticlesRepo articlesRepo;
private static final Pattern NON_LATIN = Pattern.compile("[^\\w-]");
private static final Pattern WHITESPACE = Pattern.compile("[\\s]");
- public SlugService(BlogPostRepo blogPostRepo) {
- this.blogPostRepo = blogPostRepo;
+ public SlugService(ArticlesRepo articlesRepo) {
+ this.articlesRepo = articlesRepo;
}
public String toSlug(String input) {
@@ -31,7 +31,7 @@ public class SlugService {
String finalSlug = slug;
int counter = 2;
while (true) {
- if (blogPostRepo.existsPostBySlug(finalSlug)) {
+ if (articlesRepo.existsArticleBySlug(finalSlug)) {
finalSlug = slug + "-" + counter;
counter++;
} else {