1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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", "Blog",
"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;
}
}
|