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.java12
-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.java137
-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/controller/PostsController.java136
-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/PostsRepo.java17
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/PostsRepoSqlite.java (renamed from clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ArticlesRepoSqlite.java)92
-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/PostsSearchService.java44
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/SlugService.java10
19 files changed, 322 insertions, 323 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 c3c987e..30c22e1 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.ArticlesController;
+import no.eliashaugsbakk.clams.server.controller.PostsController;
import no.eliashaugsbakk.clams.server.controller.MediaController;
-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.controller.PostController;
+import no.eliashaugsbakk.clams.server.repository.PostsRepo;
+import no.eliashaugsbakk.clams.server.repository.PostsRepoSqlite;
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 ArticlesController articlesController;
+ private final PostsController postsController;
private final MediaController mediaController;
- private final ArticleController articleController;
+ private final PostController postController;
private final AuthService authService;
public AppContext() {
@@ -27,19 +27,19 @@ public class AppContext implements AutoCloseable {
this.dbManager = new SqliteManager(dbUrl);
this.dbManager.init();
- ArticlesRepo articlesRepo = new ArticlesRepoSqlite(dbManager);
+ PostsRepo postsRepo = new PostsRepoSqlite(dbManager);
MediaRepo mediaRepo = new MediaRepoSqlite(dbManager);
- SlugService slugService = new SlugService(articlesRepo);
+ SlugService slugService = new SlugService(postsRepo);
- this.articlesController = new ArticlesController(dbManager);
+ this.postsController = new PostsController(dbManager);
this.mediaController = new MediaController(mediaRepo, appConfig);
- this.articleController = new ArticleController(articlesRepo, slugService);
+ this.postController = new PostController(postsRepo, slugService);
this.authService = new AuthService(appConfig);
}
- public ArticlesController getArticlesController() { return articlesController; }
+ public PostsController getPostsController() { return postsController; }
public MediaController getMediaController() { return mediaController; }
- public ArticleController getArticleController() { return articleController; }
+ public PostController getPostController() { return postController; }
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 9deef6b..0157496 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("articles", () -> {
- get(appContext.getArticlesController()::handleGetArticles);
- get("{slug}", appContext.getArticlesController()::handleGetArticle);
+ path("posts", () -> {
+ get(appContext.getPostsController()::handleGetPosts);
+ get("{slug}", appContext.getPostsController()::handleGetPost);
});
path("api", () -> {
@@ -50,9 +50,9 @@ public class AppRoutes implements EndpointGroup {
}
});
- post("articles", appContext.getArticleController()::handlePostArticle);
- put("articles/{slug}", appContext.getArticleController()::handlePutArticle);
- delete("articles/{slug}", appContext.getArticleController()::handleDeleteArticle);
+ post("posts", appContext.getPostController()::handlePostPost);
+ put("posts/{slug}", appContext.getPostController()::handlePutPost);
+ delete("posts/{slug}", appContext.getPostController()::handleDeletePost);
get("media", appContext.getMediaController()::handleGetMediaIndex);
get("media/{uuid}", appContext.getMediaController()::handleGetMedia);
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
deleted file mode 100644
index 8759b1a..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ArticleController.java
+++ /dev/null
@@ -1,31 +0,0 @@
-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 handlePostArticle(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
deleted file mode 100644
index 80a1cb5..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ArticlesController.java
+++ /dev/null
@@ -1,137 +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.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 ArticleItem(String title, String slug, String summary, String formattedDate, int year) {}
-
- 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",
- "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 handleGetArticles(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);
-
- Map<Integer, List<ArticleItem>> articleItemsByYear = articlesByYear.entrySet().stream()
- .collect(Collectors.toMap(
- Map.Entry::getKey,
- entry -> entry.getValue().stream()
- .map(article -> new ArticleItem(
- article.title(),
- article.slug(),
- article.summary() != null ? article.summary() : "",
- article.timePublished().atZone(OSLO_ZONE).format(DATE_FORMATTER),
- article.timePublished().atZone(OSLO_ZONE).getYear()
- ))
- .toList()
- ));
-
- ctx.render("templates/articles.html",
- Map.of(
- "page_title", "My articles",
- "page_css", "articles",
- "articles_by_year", articleItemsByYear,
- "search_value", ""
- ));
- }
-
- private void handleSearch(Context ctx, String searchTerm) {
- String query = searchTerm.trim();
- List<ArticleMetaData> results = query.isEmpty() ? List.of() : articlesSearchService.searchArticles(query);
-
- List<ArticleItem> resultItems = results.stream()
- .filter(ArticleMetaData::isPublished)
- .map(article -> new ArticleItem(
- article.title(),
- article.slug(),
- article.summary() != null ? article.summary() : "",
- article.timePublished().atZone(OSLO_ZONE).format(DATE_FORMATTER),
- article.timePublished().atZone(OSLO_ZONE).getYear()
- ))
- .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/PostController.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/PostController.java
new file mode 100644
index 0000000..f3aa406
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/PostController.java
@@ -0,0 +1,31 @@
+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.PostsRepo;
+import no.eliashaugsbakk.clams.server.service.SlugService;
+
+public class PostController {
+ private final PostsRepo postsRepo;
+ private final SlugService slugService;
+
+ public PostController(PostsRepo postsRepo, SlugService slugService) {
+ this.postsRepo = postsRepo;
+ this.slugService = slugService;
+ }
+
+ public void handlePostPost(Context ctx) {
+ PostDTO newPost = ctx.bodyAsClass(PostDTO.class);
+ postsRepo.addPost(new Post(newPost, slugService.toSlug(newPost.title())));
+ }
+
+ public void handlePutPost(Context ctx) {
+ PostDTO updatedPost = ctx.bodyAsClass(PostDTO.class);
+ postsRepo.updatePost(new Post(updatedPost, ctx.pathParam("slug")));
+ }
+
+ public void handleDeletePost(Context ctx) {
+ postsRepo.deletePost(ctx.pathParam("slug"));
+ }
+}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/PostsController.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/PostsController.java
new file mode 100644
index 0000000..f490b2c
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/PostsController.java
@@ -0,0 +1,136 @@
+package no.eliashaugsbakk.clams.server.controller;
+
+import io.javalin.http.Context;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+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.PostsRepo;
+import no.eliashaugsbakk.clams.server.repository.PostsRepoSqlite;
+import no.eliashaugsbakk.clams.server.repository.SqliteManager;
+import no.eliashaugsbakk.clams.server.service.PostsSearchService;
+import no.eliashaugsbakk.clams.server.utils.MarkdownConverter;
+
+public class PostsController {
+ private static final ZoneId OSLO_ZONE = ZoneId.of("Europe/Oslo");
+ private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("MMM dd, yyyy");
+
+ private final PostsRepo postsRepo;
+ private final PostsSearchService postsSearchService;
+
+ public record PostItem(String title, String slug, String summary, String formattedDate, int year) {}
+
+ public PostsController(SqliteManager sqliteManager) {
+ this.postsRepo = new PostsRepoSqlite(sqliteManager);
+ this.postsSearchService = new PostsSearchService(postsRepo);
+ }
+
+ public void handleGetPost(Context ctx) {
+ var postOpt = postsRepo.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",
+ "published_date", formattedDate,
+ "author", "by Elias Haugsbakk",
+ "content", MarkdownConverter.convertToHtml(post.content()),
+ "back_to_index", "<a href=\"/posts/\">back to all posts</a>"
+ ));
+ }
+
+ public void handleGetPosts(Context ctx) {
+ String searchTerm = ctx.queryParam("search");
+ if (searchTerm != null) {
+ handleSearch(ctx, searchTerm);
+ } else {
+ handlePostsIndex(ctx);
+ }
+ }
+
+ private void handlePostsIndex(Context ctx) {
+ List<PostMetaData> allPosts = postsRepo.listPostsMetaData().stream()
+ .filter(PostMetaData::isPublished)
+ .toList();
+
+ Map<Integer, List<PostMetaData>> postsByYear = groupPostsByYear(allPosts);
+
+ Map<Integer, List<PostItem>> postItemsByYear = postsByYear.entrySet().stream()
+ .collect(Collectors.toMap(
+ Map.Entry::getKey,
+ entry -> entry.getValue().stream()
+ .map(post -> new PostItem(
+ post.title(),
+ post.slug(),
+ post.summary() != null ? post.summary() : "",
+ post.timePublished().atZone(OSLO_ZONE).format(DATE_FORMATTER),
+ post.timePublished().atZone(OSLO_ZONE).getYear()
+ ))
+ .toList()
+ ));
+
+ ctx.render("templates/posts.html",
+ Map.of(
+ "page_title", "My posts",
+ "page_css", "posts",
+ "posts_by_year", postItemsByYear,
+ "search_value", ""
+ ));
+ }
+
+ private void handleSearch(Context ctx, String searchTerm) {
+ String query = searchTerm.trim();
+ List<PostMetaData> results = query.isEmpty() ? List.of() : postsSearchService.searchPosts(query);
+
+ List<PostItem> resultItems = results.stream()
+ .filter(PostMetaData::isPublished)
+ .map(post -> new PostItem(
+ post.title(),
+ post.slug(),
+ post.summary() != null ? post.summary() : "",
+ post.timePublished().atZone(OSLO_ZONE).format(DATE_FORMATTER),
+ post.timePublished().atZone(OSLO_ZONE).getYear()
+ ))
+ .toList();
+
+ ctx.render("templates/posts-search.html",
+ Map.of(
+ "page_title", "Search Results -- Elias Haugsbakk",
+ "page_css", "posts",
+ "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/model/Article.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Article.java
deleted file mode 100644
index b74a79b..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Article.java
+++ /dev/null
@@ -1,12 +0,0 @@
-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
deleted file mode 100644
index 27207d7..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/ArticleDTO.java
+++ /dev/null
@@ -1,4 +0,0 @@
-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
deleted file mode 100644
index 8e71d78..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/ArticleMetaData.java
+++ /dev/null
@@ -1,6 +0,0 @@
-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
new file mode 100644
index 0000000..dcf0e54
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Post.java
@@ -0,0 +1,12 @@
+package no.eliashaugsbakk.clams.server.model;
+
+import java.time.Instant;
+
+public record Post(String title, String slug, String summary, Instant timePublished, Instant lastEdited, String content,
+ boolean isPublished) {
+ public Post(PostDTO postDTO, String slug) {
+
+ this(postDTO.title(), slug, postDTO.summary(), Instant.now(), 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
new file mode 100644
index 0000000..12254da
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/PostDTO.java
@@ -0,0 +1,4 @@
+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
new file mode 100644
index 0000000..175fc55
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/PostMetaData.java
@@ -0,0 +1,6 @@
+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
deleted file mode 100644
index 221be74..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ArticlesRepo.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.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/PostsRepo.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/PostsRepo.java
new file mode 100644
index 0000000..b5553b5
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/PostsRepo.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.Post;
+import no.eliashaugsbakk.clams.server.model.PostMetaData;
+
+public interface PostsRepo {
+ List<PostMetaData> listPostsMetaData();
+ Optional<Post> getPost(String slug);
+ List<PostMetaData> searchPostsBody(String query);
+
+ void addPost(Post post);
+ void updatePost(Post post);
+ void deletePost(String slug);
+ boolean existsPostBySlug(String slug);
+}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ArticlesRepoSqlite.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/PostsRepoSqlite.java
index 60f0f9d..8ed15af 100644
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ArticlesRepoSqlite.java
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/PostsRepoSqlite.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.Article;
-import no.eliashaugsbakk.clams.server.model.ArticleMetaData;
+import no.eliashaugsbakk.clams.server.model.Post;
+import no.eliashaugsbakk.clams.server.model.PostMetaData;
-public class ArticlesRepoSqlite implements ArticlesRepo {
+public class PostsRepoSqlite implements PostsRepo {
private final SqliteManager manager;
- public ArticlesRepoSqlite(SqliteManager manager) {
+ public PostsRepoSqlite(SqliteManager manager) {
this.manager = manager;
}
@Override
- public List<ArticleMetaData> listArticlesMetaData() {
+ public List<PostMetaData> listPostsMetaData() {
String sql = """
SELECT title, slug, summary, published, last_edited, is_published
- FROM articles
+ FROM posts
ORDER BY published DESC
""";
- List<ArticleMetaData> articles = new ArrayList<>();
+ List<PostMetaData> posts = new ArrayList<>();
try (Connection conn = manager.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
@@ -41,21 +41,21 @@ public class ArticlesRepoSqlite implements ArticlesRepo {
Instant lastEdit = (lastEditRaw != null) ? Instant.parse(lastEditRaw) : null;
boolean isPublished = resultSet.getBoolean("is_published");
- articles.add(new ArticleMetaData(title, slug, summary, published, lastEdit, isPublished));
+ posts.add(new PostMetaData(title, slug, summary, published, lastEdit, isPublished));
}
- return articles;
+ return posts;
} catch (SQLException e) {
- throw new RepoException("Error fetching all article metadata sorted by time", e);
+ throw new RepoException("Error fetching all post metadata sorted by time", e);
}
}
@Override
- public Optional<Article> getArticle(String slug) {
+ public Optional<Post> getPost(String slug) {
String sql = """
SELECT title, slug, summary, content, published, last_edited, is_published
- FROM articles
+ FROM posts
WHERE slug = ?
""";
@@ -67,33 +67,33 @@ public class ArticlesRepoSqlite implements ArticlesRepo {
try (ResultSet resultSet = stmt.executeQuery()) {
if (resultSet.next()) {
String title = resultSet.getString("title");
- String articleSlug = resultSet.getString("slug");
+ String postSlug = 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 Article(title, articleSlug, summary, published, lastEdited, content, isPublished));
+ return Optional.of(new Post(title, postSlug, summary, published, lastEdited, content, isPublished));
}
return Optional.empty();
}
} catch (SQLException e) {
- throw new RepoException("Error fetching full article by slug: " + slug, e);
+ throw new RepoException("Error fetching full post by slug: " + slug, e);
}
}
@Override
- public List<ArticleMetaData> searchArticlesBody(String query) {
+ public List<PostMetaData> searchPostsBody(String query) {
String sql = """
SELECT title, slug, summary, published, last_edited, is_published
- FROM articles
+ FROM posts
WHERE content LIKE ?
ORDER BY published DESC
""";
- List<ArticleMetaData> articles = new ArrayList<>();
+ List<PostMetaData> posts = new ArrayList<>();
try (Connection conn = manager.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
@@ -110,46 +110,46 @@ public class ArticlesRepoSqlite implements ArticlesRepo {
Instant lastEdit = Instant.parse(resultSet.getString("last_edited"));
boolean isPublished = resultSet.getBoolean("is_published");
- articles.add(new ArticleMetaData(title, slug, summary, published, lastEdit, isPublished));
+ posts.add(new PostMetaData(title, slug, summary, published, lastEdit, isPublished));
}
}
- return articles;
+ return posts;
} catch (SQLException e) {
- throw new RepoException("Error searching articles for query: " + query, e);
+ throw new RepoException("Error searching posts for query: " + query, e);
}
}
@Override
- public void addArticle(Article article) {
+ public void addPost(Post post) {
String sql = """
- INSERT INTO articles (slug, title, content, summary, published, last_edited, is_published)
+ INSERT INTO posts (slug, title, content, summary, published, last_edited, is_published)
VALUES (?, ?, ?, ?, ?, ?, ?)
""";
try (Connection conn = manager.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
- 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.setString(6, article.timePublished().toString());
- stmt.setBoolean(7, article.isPublished());
+ 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.setString(6, post.timePublished().toString());
+ stmt.setBoolean(7, post.isPublished());
stmt.executeUpdate();
} catch (SQLException e) {
- throw new RepoException("Error adding articles article: " + article.slug(), e);
+ throw new RepoException("Error adding posts post: " + post.slug(), e);
}
}
@Override
- public void updateArticle(Article article) {
+ public void updatePost(Post post) {
String sql = """
- UPDATE articles
+ UPDATE posts
SET title = ?, content = ?, summary = ?, published = ?, last_edited = ?, is_published = ?
WHERE slug = ?
""";
@@ -157,25 +157,25 @@ public class ArticlesRepoSqlite implements ArticlesRepo {
try (Connection conn = manager.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
- stmt.setString(1, article.title());
- stmt.setString(2, article.content());
- stmt.setString(3, article.summary());
- stmt.setString(4, article.timePublished().toString());
+ stmt.setString(1, post.title());
+ stmt.setString(2, post.content());
+ stmt.setString(3, post.summary());
+ stmt.setString(4, post.timePublished().toString());
stmt.setString(5, Instant.now().toString());
- stmt.setBoolean(6, article.isPublished());
- stmt.setString(7, article.slug());
+ stmt.setBoolean(6, post.isPublished());
+ stmt.setString(7, post.slug());
stmt.executeUpdate();
} catch (SQLException e) {
- throw new RepoException("Error updating articles article: " + article.slug(), e);
+ throw new RepoException("Error updating posts post: " + post.slug(), e);
}
}
@Override
- public void deleteArticle(String slug) {
+ public void deletePost(String slug) {
String sql = """
- DELETE FROM articles
+ DELETE FROM posts
WHERE slug = ?
""";
@@ -187,15 +187,15 @@ public class ArticlesRepoSqlite implements ArticlesRepo {
stmt.executeUpdate();
} catch (SQLException e) {
- throw new RepoException("Error deleting articles article: " + slug, e);
+ throw new RepoException("Error deleting posts post: " + slug, e);
}
}
@Override
- public boolean existsArticleBySlug(String slug) {
+ public boolean existsPostBySlug(String slug) {
String sql = """
SELECT 1
- FROM articles
+ FROM posts
WHERE slug = ?
LIMIT 1
""";
@@ -210,7 +210,7 @@ public class ArticlesRepoSqlite implements ArticlesRepo {
}
} catch (SQLException e) {
- throw new RepoException("Error checking existence of article by slug: " + slug, e);
+ throw new RepoException("Error checking existence of post by slug: " + slug, e);
}
}
}
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 4832818..898729a 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 articles = """
- CREATE TABLE IF NOT EXISTS articles (
+ String posts = """
+ CREATE TABLE IF NOT EXISTS posts (
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(articles);
+ stmt.execute(posts);
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
deleted file mode 100644
index db68063..0000000
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/ArticlesSearchService.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.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/PostsSearchService.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/PostsSearchService.java
new file mode 100644
index 0000000..1b29c02
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/service/PostsSearchService.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.PostMetaData;
+import no.eliashaugsbakk.clams.server.repository.PostsRepo;
+
+public class PostsSearchService {
+ private final PostsRepo postsRepo;
+
+ public PostsSearchService(PostsRepo postsRepo) {
+ this.postsRepo = postsRepo;
+ }
+
+ 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 = postsRepo.listPostsMetaData();
+ List<PostMetaData> bodyResults = postsRepo.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 7d356ce..f80d310 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.ArticlesRepo;
+import no.eliashaugsbakk.clams.server.repository.PostsRepo;
public class SlugService {
- private final ArticlesRepo articlesRepo;
+ private final PostsRepo postsRepo;
private static final Pattern NON_LATIN = Pattern.compile("[^\\w-]");
private static final Pattern WHITESPACE = Pattern.compile("[\\s]");
- public SlugService(ArticlesRepo articlesRepo) {
- this.articlesRepo = articlesRepo;
+ public SlugService(PostsRepo postsRepo) {
+ this.postsRepo = postsRepo;
}
public String toSlug(String input) {
@@ -31,7 +31,7 @@ public class SlugService {
String finalSlug = slug;
int counter = 2;
while (true) {
- if (articlesRepo.existsArticleBySlug(finalSlug)) {
+ if (postsRepo.existsPostBySlug(finalSlug)) {
finalSlug = slug + "-" + counter;
counter++;
} else {