commit 8978c7ae4c08b869de2e4b66686d15e6a507b490 Author: Minecon724 Date: Tue Jan 7 11:41:30 2025 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..7ace097 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..bfaf990 --- /dev/null +++ b/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + eu.m724 + blog-software-java + 1.0-SNAPSHOT + + + 21 + 21 + UTF-8 + + + + + commons-cli + commons-cli + 1.8.0 + + + org.eclipse.jgit + org.eclipse.jgit + 7.1.0.202411261347-r + + + com.hubspot.jinjava + jinjava + 2.7.4 + + + com.google.code.gson + gson + 2.11.0 + + + commons-io + commons-io + 2.16.1 + + + + \ No newline at end of file diff --git a/src/main/java/eu/m724/blog/Main.java b/src/main/java/eu/m724/blog/Main.java new file mode 100644 index 0000000..468235e --- /dev/null +++ b/src/main/java/eu/m724/blog/Main.java @@ -0,0 +1,45 @@ +package eu.m724.blog; + +import org.apache.commons.io.FileUtils; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.lib.RepositoryBuilder; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; + +public class Main { + public static void main(String[] args) throws IOException { + System.out.println("Hello world!"); + + var workingDirectory = new File("m724"); + var templateDirectory = new File(workingDirectory, "template"); + var outputDirectory = new File(workingDirectory, "generated_out"); + var force = true; + + // + + var repository = new RepositoryBuilder() + .setGitDir(workingDirectory) + .build(); + var git = new Git(repository); + + // + + if (outputDirectory.exists()) { + if (force) { + outputDirectory.delete(); + } else { + throw new FileAlreadyExistsException(outputDirectory.getAbsolutePath(), null, "Output directory already exists"); + } + } + + outputDirectory.mkdir(); + FileUtils.copyDirectory(new File(workingDirectory, "assets"), new File(outputDirectory, "assets")); + FileUtils.copyDirectory(new File(templateDirectory, "static"), new File(outputDirectory, "static")); + + + + + } +} \ No newline at end of file diff --git a/src/main/java/eu/m724/blog/Renderer.java b/src/main/java/eu/m724/blog/Renderer.java new file mode 100644 index 0000000..564735a --- /dev/null +++ b/src/main/java/eu/m724/blog/Renderer.java @@ -0,0 +1,28 @@ +package eu.m724.blog; + +import com.google.common.io.Resources; +import com.hubspot.jinjava.Jinjava; +import eu.m724.blog.data.Site; +import org.apache.commons.net.nntp.Article; + +import java.util.Map; + +public class Renderer { + private final + + public void renderIndex(Site site, Article... articles) { + + } + + public void renderArticle(Site site, Article article) { + Jinjava jinjava = new Jinjava(); + Map context = Map.of( + "site", site, + "article", article + ); + + String template = Resources.toString(Resources.getResource("my-template.html"), Charsets.UTF_8); + + return jinjava.render(template, context); + } +} diff --git a/src/main/java/eu/m724/blog/Template.java b/src/main/java/eu/m724/blog/Template.java new file mode 100644 index 0000000..0d88568 --- /dev/null +++ b/src/main/java/eu/m724/blog/Template.java @@ -0,0 +1,25 @@ +package eu.m724.blog; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class Template { + private final Path templateDirectory; + + public Template(Path templateDirectory) { + this.templateDirectory = templateDirectory; + } + + public String postTemplate() throws IOException { + return Files.readString(templateDirectory.resolve("article_template.html")); + } + + public String indexTemplate() throws IOException { + return Files.readString(templateDirectory.resolve("index.html")); + } + + public void copyStatic() { + templateDirectory.resolve("static").co + } +} diff --git a/src/main/java/eu/m724/blog/data/Post.java b/src/main/java/eu/m724/blog/data/Post.java new file mode 100644 index 0000000..ddb683a --- /dev/null +++ b/src/main/java/eu/m724/blog/data/Post.java @@ -0,0 +1,121 @@ +package eu.m724.blog.data; + +import com.google.common.collect.Maps; +import com.google.common.io.Resources; +import com.hubspot.jinjava.Jinjava; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; + +import java.io.*; +import java.nio.file.Files; +import java.time.*; +import java.util.HashMap; +import java.util.Map; + +public record Post( + String slug, + String title, + String summary, + boolean draft, + + int revisions, + String createdBy, + ZonedDateTime createdAt, + String modifiedBy, + ZonedDateTime modifiedAt, + + Map customProperties, + String rawContent +) { + public String renderHtml(String template) { + Jinjava jinjava = new Jinjava(); + + Map context = Map.of( + "article", this + ) + + return jinjava.render(template, context); + } + + public String getHtmlContent() { + return rawContent; + } + + public static Post fromFile(Git git, String slug) throws IOException { + /* read properties before filtering */ + + var properties = new HashMap(); + + var lines = Files.readAllLines(new File(git.getRepository().getDirectory(), "archive/" + slug + ".html").toPath()); + + String line; + while ((line = lines.removeFirst()) != null) { + var parts = line.split(" "); + + var key = parts[0].toLowerCase(); + var data = line.substring(key.length()).strip(); + + if (key.isEmpty()) // empty key means end of content + break; + + if (properties.putIfAbsent(key, data) != null) + System.out.printf("%s: Duplicate property \"%s\". Only the first one will be used.\n", slug, key); + } + + var content = String.join("\n", lines).strip(); + + /* filter properties from read file */ + + String title = null; + String summary = null; + boolean draft = false; + + var custom = new HashMap(); + + for (Map.Entry property : properties.entrySet()) { + var value = property.getValue(); + + switch (property.getKey()) { + case "title": + title = value; + break; + case "summary": + summary = value; + break; + case "draft": // a post is a draft if the key is there + draft = true; + break; + default: + custom.put(property.getKey(), value); + } + } + + /* get revisions */ + + int revisions = 0; + String createdBy = null; + ZonedDateTime createdAt = null; + String modifiedBy = null; + ZonedDateTime modifiedAt = null; + + try { + var commits = git.log().addPath("archive/" + slug + ".html").call().iterator(); + + while (commits.hasNext()) { + var commit = commits.next(); + createdBy = commit.getAuthorIdent().getName(); + createdAt = Instant.ofEpochSecond(commit.getCommitTime()).atZone(ZoneOffset.UTC); + + if (revisions++ == 0) { + modifiedBy = createdBy; + modifiedAt = createdAt; + } + } + } catch (GitAPIException e) { + draft = true; + System.out.printf("%s: Git exception, assuming draft: %s\n", slug, e.getMessage()); + } + + return new Post(slug, title, summary, draft, revisions, createdBy, createdAt, modifiedBy, modifiedAt, custom, content); + } +} diff --git a/src/main/java/eu/m724/blog/data/Site.java b/src/main/java/eu/m724/blog/data/Site.java new file mode 100644 index 0000000..5513fec --- /dev/null +++ b/src/main/java/eu/m724/blog/data/Site.java @@ -0,0 +1,22 @@ +package eu.m724.blog.data; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.eclipse.jgit.api.Git; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +public record Site( + String name, + String baseUrl, + + JsonObject customProperties +) { + public static Site fromConfig(Git git) throws IOException { + var content = Files.readString(new File(git.getRepository().getDirectory(), "config.json").toPath()); + + return new Gson().fromJson(content, Site.class); + } +} diff --git a/src/main/java/eu/m724/blog/data/Template.java b/src/main/java/eu/m724/blog/data/Template.java new file mode 100644 index 0000000..426b3be --- /dev/null +++ b/src/main/java/eu/m724/blog/data/Template.java @@ -0,0 +1,23 @@ +package eu.m724.blog.data; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public record Template( + String name, + int version, + + int articlesPerPage, + + JsonObject customProperties +) { + public static Template fromDirectory(Path templateDirectory) throws IOException { + var content = Files.readString(templateDirectory.resolve("template.json")); + + return new Gson().fromJson(content, Template.class); + } +}