summaryrefslogtreecommitdiff
path: root/clams-server
diff options
context:
space:
mode:
Diffstat (limited to 'clams-server')
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/config/AppContext.java7
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/config/AppRoutes.java9
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ProjectsController.java44
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Project.java4
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/PostsRepoSqlite.java2
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ProjectsRepo.java12
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ProjectsRepoSqlite.java112
-rw-r--r--clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/SqliteManager.java12
-rw-r--r--clams-server/src/main/resources/public/css/common.css4
-rw-r--r--clams-server/src/main/resources/templates/projects.html42
10 files changed, 214 insertions, 34 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 30c22e1..2d52374 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
@@ -4,10 +4,13 @@ import java.nio.file.Path;
import no.eliashaugsbakk.clams.server.controller.PostsController;
import no.eliashaugsbakk.clams.server.controller.MediaController;
import no.eliashaugsbakk.clams.server.controller.PostController;
+import no.eliashaugsbakk.clams.server.controller.ProjectsController;
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.ProjectsRepo;
+import no.eliashaugsbakk.clams.server.repository.ProjectsRepoSqlite;
import no.eliashaugsbakk.clams.server.repository.SqliteManager;
import no.eliashaugsbakk.clams.server.service.AuthService;
import no.eliashaugsbakk.clams.server.service.SlugService;
@@ -17,6 +20,7 @@ public class AppContext implements AutoCloseable {
private final PostsController postsController;
private final MediaController mediaController;
private final PostController postController;
+ private final ProjectsController projectsController;
private final AuthService authService;
public AppContext() {
@@ -29,16 +33,19 @@ public class AppContext implements AutoCloseable {
PostsRepo postsRepo = new PostsRepoSqlite(dbManager);
MediaRepo mediaRepo = new MediaRepoSqlite(dbManager);
+ ProjectsRepo projectsRepo = new ProjectsRepoSqlite(dbManager);
SlugService slugService = new SlugService(postsRepo);
this.postsController = new PostsController(dbManager);
this.mediaController = new MediaController(mediaRepo, appConfig);
+ this.projectsController = new ProjectsController(projectsRepo);
this.postController = new PostController(postsRepo, slugService);
this.authService = new AuthService(appConfig);
}
public PostsController getPostsController() { return postsController; }
public MediaController getMediaController() { return mediaController; }
+ public ProjectsController getProjectsController() { return projectsController; }
public PostController getPostController() { return postController; }
public AuthService getAuthService() { return authService; }
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 0157496..abd2926 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
@@ -22,14 +22,14 @@ public class AppRoutes implements EndpointGroup {
get("/", ctx -> ctx.redirect("/home"));
get("/home", ctx -> ctx.render("templates/home.html",
Map.of("page_title", "Elias Haugsbakk", "page_css", "home")));
- get("/projects", ctx -> ctx.render("templates/projects.html",
- Map.of("page_title", "Projects - Elias Haugsbakk", "page_css", "projects")));
path("posts", () -> {
get(appContext.getPostsController()::handleGetPosts);
get("{slug}", appContext.getPostsController()::handleGetPost);
});
+ path("projects", () -> get(appContext.getProjectsController()::handleGetProjects));
+
path("api", () -> {
before("*", ctx -> {
String authHeader = ctx.header("Authorization");
@@ -54,6 +54,11 @@ public class AppRoutes implements EndpointGroup {
put("posts/{slug}", appContext.getPostController()::handlePutPost);
delete("posts/{slug}", appContext.getPostController()::handleDeletePost);
+ get("projects", appContext.getProjectsController()::handleGetProjectsApi);
+ post("projects", appContext.getProjectsController()::handlePostProject);
+ put("projects/{id}", appContext.getProjectsController()::handlePutProject);
+ delete("projects/{id}", appContext.getProjectsController()::handleDeleteProject);
+
get("media", appContext.getMediaController()::handleGetMediaIndex);
get("media/{uuid}", appContext.getMediaController()::handleGetMedia);
post("media", appContext.getMediaController()::handlePostMedia);
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ProjectsController.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ProjectsController.java
new file mode 100644
index 0000000..f3e0463
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/controller/ProjectsController.java
@@ -0,0 +1,44 @@
+package no.eliashaugsbakk.clams.server.controller;
+
+import io.javalin.http.Context;
+import java.util.List;
+import java.util.Map;
+import no.eliashaugsbakk.clams.server.model.Project;
+import no.eliashaugsbakk.clams.server.repository.ProjectsRepo;
+
+public class ProjectsController {
+ private final ProjectsRepo projectsRepo;
+
+ public ProjectsController(ProjectsRepo projectsRepo) {
+ this.projectsRepo = projectsRepo;
+ }
+
+ public void handleGetProjects(Context ctx) {
+ List<Project> allProjects = projectsRepo.getAllProjects();
+ ctx.render("templates/projects.html",
+ Map.of(
+ "page_title", "Blog",
+ "page_css", "projects",
+ "projects", allProjects
+ ));
+ }
+
+ public void handlePostProject(Context ctx) {
+ Project newProject = ctx.bodyAsClass(Project.class);
+ projectsRepo.addProject(newProject);
+ }
+
+ public void handlePutProject(Context ctx) {
+ Project updateProject = ctx.bodyAsClass(Project.class);
+ projectsRepo.updateProject(Long.parseLong(ctx.pathParam("id")), updateProject);
+ }
+
+ public void handleDeleteProject(Context ctx) {
+ projectsRepo.deleteProject(Long.parseLong(ctx.pathParam("id")));
+ }
+
+ public void handleGetProjectsApi(Context ctx) {
+ List<Project> allProjects = projectsRepo.getAllProjects();
+ ctx.json(allProjects);
+ }
+}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Project.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Project.java
new file mode 100644
index 0000000..fb4e313
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/model/Project.java
@@ -0,0 +1,4 @@
+package no.eliashaugsbakk.clams.server.model;
+
+public record Project(long id, String name, String readMoreUrl, String gitUrl, String gitHubUrl, String description) {
+}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/PostsRepoSqlite.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/PostsRepoSqlite.java
index 8ed15af..6943d97 100644
--- a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/PostsRepoSqlite.java
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/PostsRepoSqlite.java
@@ -187,7 +187,7 @@ public class PostsRepoSqlite implements PostsRepo {
stmt.executeUpdate();
} catch (SQLException e) {
- throw new RepoException("Error deleting posts post: " + slug, e);
+ throw new RepoException("Error deleting post " + slug + ": ", e);
}
}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ProjectsRepo.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ProjectsRepo.java
new file mode 100644
index 0000000..6477d68
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ProjectsRepo.java
@@ -0,0 +1,12 @@
+package no.eliashaugsbakk.clams.server.repository;
+
+import java.util.List;
+import no.eliashaugsbakk.clams.server.model.Project;
+
+public interface ProjectsRepo {
+ void addProject(Project post);
+ void updateProject(long id, Project project);
+ void deleteProject(long id);
+
+ List<Project> getAllProjects();
+}
diff --git a/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ProjectsRepoSqlite.java b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ProjectsRepoSqlite.java
new file mode 100644
index 0000000..b761286
--- /dev/null
+++ b/clams-server/src/main/java/no/eliashaugsbakk/clams/server/repository/ProjectsRepoSqlite.java
@@ -0,0 +1,112 @@
+package no.eliashaugsbakk.clams.server.repository;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import no.eliashaugsbakk.clams.server.model.Project;
+
+public class ProjectsRepoSqlite implements ProjectsRepo {
+ private final SqliteManager manager;
+
+ public ProjectsRepoSqlite(SqliteManager manager) {
+ this.manager = manager;
+ }
+
+ @Override
+ public void addProject(Project project) {
+ String sql = """
+ INSERT INTO projects (name, read_more_url, git_url, git_hub_url, description)
+ VALUES (?, ?, ?, ?, ?)
+ """;
+
+ try (Connection conn = manager.getConnection();
+ PreparedStatement stmt = conn.prepareStatement(sql)) {
+
+ stmt.setString(1, project.name());
+ stmt.setString(2, project.readMoreUrl());
+ stmt.setString(3, project.gitUrl());
+ stmt.setString(4, project.gitHubUrl());
+ stmt.setString(5, project.description());
+
+ stmt.executeUpdate();
+ } catch (SQLException e) {
+ throw new RepoException("Error adding project: " + project.name(), e);
+ }
+ }
+
+ @Override
+ public void updateProject(long id, Project project) {
+ String sql = """
+ UPDATE projects
+ SET name = ?, read_more_url = ?, git_url = ?, git_hub_url = ?, description = ?
+ WHERE id = ?
+ """;
+
+ try (Connection conn = manager.getConnection();
+ PreparedStatement stmt = conn.prepareStatement(sql)) {
+
+ stmt.setString(1, project.name());
+ stmt.setString(2, project.readMoreUrl());
+ stmt.setString(3, project.gitUrl());
+ stmt.setString(4, project.gitHubUrl());
+ stmt.setString(5, project.description());
+ stmt.setLong(6, id);
+
+ stmt.executeUpdate();
+ } catch (SQLException e) {
+ throw new RepoException("Error updating project: ", e);
+ }
+ }
+
+ @Override
+ public void deleteProject(long id) {
+ String sql = """
+ DELETE FROM projects
+ WHERE id = ?
+ """;
+
+ try (Connection conn = manager.getConnection();
+ PreparedStatement stmt = conn.prepareStatement(sql)) {
+
+ stmt.setLong(1, id);
+
+ stmt.executeUpdate();
+
+ } catch (SQLException e) {
+ throw new RepoException("Error deleting project " + id + ": ", e);
+ }
+ }
+
+ @Override
+ public List<Project> getAllProjects() {
+ String sql = """
+ SELECT id, name, read_more_url, git_url, git_hub_url, description
+ FROM projects
+ """;
+
+ List<Project> projects = new ArrayList<>();
+
+ try (Connection conn = manager.getConnection();
+ PreparedStatement stmt = conn.prepareStatement(sql);
+ ResultSet resultSet = stmt.executeQuery()) {
+
+ while (resultSet.next()) {
+ long id = resultSet.getLong("id");
+ String name = resultSet.getString("name");
+ String read_more_url = resultSet.getString("read_more_url");
+ String git_url = resultSet.getString("git_url");
+ String git_hub_url = resultSet.getString("git_hub_url");
+ String description = resultSet.getString("description");
+
+ projects.add(new Project(id, name, read_more_url, git_url, git_hub_url, description));
+ }
+
+ return projects;
+ } catch (SQLException e) {
+ throw new RepoException("Error fetching all projects", 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 898729a..cf4b8ee 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
@@ -47,10 +47,22 @@ public class SqliteManager implements AutoCloseable {
);
""";
+ String projects = """
+ CREATE TABLE IF NOT EXISTS projects (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ name TEXT NOT NULL,
+ read_more_url TEXT,
+ git_url TEXT,
+ git_hub_url TEXT,
+ description TEXT
+ );
+ """;
+
try (Connection conn = dataSource.getConnection(); Statement stmt = conn.createStatement()) {
stmt.execute(posts);
stmt.execute(images);
+ stmt.execute(projects);
} catch (SQLException e) {
throw new RepoException("Error while initializing database", e);
diff --git a/clams-server/src/main/resources/public/css/common.css b/clams-server/src/main/resources/public/css/common.css
index dc81927..91f14b1 100644
--- a/clams-server/src/main/resources/public/css/common.css
+++ b/clams-server/src/main/resources/public/css/common.css
@@ -107,13 +107,13 @@ a:hover {
font-size: 0.8rem;
text-decoration: none;
display: inline-block;
- transition: background-color 0.2s ease, color 0.2s ease;
+ transition: color ,background-color 0.2s ease, color 0.2s ease;
}
.pill-button:hover,
.pill-button:focus-visible {
background: var(--surface-hover-color);
- color: var(--text-color);
+ color: var(--accent-color);
}
.pill-button:focus-visible {
diff --git a/clams-server/src/main/resources/templates/projects.html b/clams-server/src/main/resources/templates/projects.html
index 8d476cd..6e31def 100644
--- a/clams-server/src/main/resources/templates/projects.html
+++ b/clams-server/src/main/resources/templates/projects.html
@@ -9,41 +9,25 @@
<section class="projects-category">
<ul class="project-list">
+ {% for project in projects %}
<li class="project-item">
<div class="project-meta">
- <h3>Project One Name</h3>
- <p>Short project description / introduction.</p>
+ <h3>{{ project.name }}</h3>
+ <p>{{ project.description }}</p>
</div>
<div class="project-actions">
- <a href="#" class="pill-button">Read More</a>
- <a href="#" class="pill-button">Self-Hosted Git</a>
- <a href="#" class="pill-button">GitHub</a>
- </div>
- </li>
-
- <li class="project-item">
- <div class="project-meta">
- <h3>Project Two Name</h3>
- <p>Short project description / introduction.</p>
- </div>
- <div class="project-actions">
- <a href="#" class="pill-button">Read More</a>
- <a href="#" class="pill-button">Self-Hosted Git</a>
- <a href="#" class="pill-button">GitHub</a>
- </div>
- </li>
-
- <li class="project-item">
- <div class="project-meta">
- <h3>Other Project One</h3>
- <p>A short one-line description.</p>
- </div>
- <div class="project-actions">
- <a href="#" class="pill-button">Read More</a>
- <a href="#" class="pill-button">Self-Hosted Git</a>
- <a href="#" class="pill-button">GitHub</a>
+ {% if project.readMoreUrl %}
+ <a href="{{ project.readMoreUrl }}" class="pill-button">Read More</a>
+ {% endif %}
+ {% if project.gitUrl %}
+ <a href="{{ project.gitUrl }}" class="pill-button">Self-Hosted Git</a>
+ {% endif %}
+ {% if project.gitHubUrl %}
+ <a href="{{ project.gitHubUrl }}" class="pill-button">GitHub</a>
+ {% endif %}
</div>
</li>
+ {% endfor %}
</ul>
</section>
</main>