initial commit

This commit is contained in:
Minecon724 2025-01-07 11:41:30 +01:00
commit 8978c7ae4c
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
13 changed files with 501 additions and 0 deletions

38
.gitignore vendored Normal file
View file

@ -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

3
.idea/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

7
.idea/encodings.xml Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

14
.idea/misc.xml Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="temurin-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

124
.idea/uiDesigner.xml Normal file
View file

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

6
.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

45
pom.xml Normal file
View file

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>eu.m724</groupId>
<artifactId>blog-software-java</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>7.1.0.202411261347-r</version>
</dependency>
<dependency>
<groupId>com.hubspot.jinjava</groupId>
<artifactId>jinjava</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.16.1</version>
</dependency>
</dependencies>
</project>

View file

@ -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"));
}
}

View file

@ -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<String, Object> context = Map.of(
"site", site,
"article", article
);
String template = Resources.toString(Resources.getResource("my-template.html"), Charsets.UTF_8);
return jinjava.render(template, context);
}
}

View file

@ -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
}
}

View file

@ -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<String, String> customProperties,
String rawContent
) {
public String renderHtml(String template) {
Jinjava jinjava = new Jinjava();
Map<String, Object> 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<String, String>();
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<String, String>();
for (Map.Entry<String, String> 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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}