diff --git a/src/main/java/eu/m724/blog/BlogBuilder.java b/src/main/java/eu/m724/blog/BlogBuilder.java index 32dba3b..591e9bb 100644 --- a/src/main/java/eu/m724/blog/BlogBuilder.java +++ b/src/main/java/eu/m724/blog/BlogBuilder.java @@ -15,6 +15,11 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.stream.Collectors; +/** + * The {@code BlogBuilder} class facilitates building a static blog by managing templates, + * assets, posts, and rendering output files. It uses a Git repository as the + * source for the blog's content and configuration. + */ public class BlogBuilder { private final Git git; private final Path workingDirectory; @@ -26,6 +31,11 @@ public class BlogBuilder { private Path outputDirectory; private boolean renderDrafts = false; + /** + * Constructs a {@link BlogBuilder} instance using the provided Git repository. + * + * @param git the Git repository to be used for the blog. + */ public BlogBuilder(Git git) { this.git = git; @@ -34,6 +44,14 @@ public class BlogBuilder { this.outputDirectory = workingDirectory.resolve("generated_out"); } + /** + * Creates a new {@link BlogBuilder} instance for the specified working directory. + * The directory is expected to be a Git repository. + * + * @param workingDirectory the root path of the blog, which must contain a Git repository. + * @return a {@link BlogBuilder} instance + * @throws IOException if there is an error accessing the Git repository + */ public static BlogBuilder fromPath(Path workingDirectory) throws IOException { var repository = new RepositoryBuilder() .setGitDir(workingDirectory.resolve(".git").toFile()) @@ -45,16 +63,34 @@ public class BlogBuilder { return new BlogBuilder(git); } + /** + * Sets the directory to be used for templates in the blog build process. + * + * @param templateDirectory the path to the template directory + * @return the current instance of {@link BlogBuilder} + */ public BlogBuilder templateDirectory(Path templateDirectory) { this.templateDirectory = templateDirectory; return this; } + /** + * Sets the directory where the output files will be saved during the blog build process. + * + * @param outputDirectory the path representing the directory for output files + * @return the current instance of {@link BlogBuilder} + */ public BlogBuilder outputDirectory(Path outputDirectory) { this.outputDirectory = outputDirectory; return this; } + /** + * Configures whether drafts should be rendered in the blog build process. + * + * @param renderDrafts a boolean flag indicating whether to include drafts in the rendering process. + * @return the current instance of {@link BlogBuilder} + */ public BlogBuilder renderDrafts(boolean renderDrafts) { this.renderDrafts = renderDrafts; return this; @@ -72,6 +108,11 @@ public class BlogBuilder { Files.createDirectory(outputDirectory); } + /** + * Builds the blog by generating templates, copying assets, and rendering posts. + * + * @throws IOException if an I/O error occurs + */ public void build() throws IOException { if (site == null) this.site = Site.fromConfig(workingDirectory.resolve("site-config.json")); diff --git a/src/main/java/eu/m724/blog/Server.java b/src/main/java/eu/m724/blog/Server.java index 1a0c7f0..2260503 100644 --- a/src/main/java/eu/m724/blog/Server.java +++ b/src/main/java/eu/m724/blog/Server.java @@ -10,19 +10,41 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +/** + * The {@code Server} class represents a basic HTTP server designed to serve files + * from a specified webroot directory. + */ public class Server implements HttpHandler { private final Path webroot; private InetSocketAddress listenAddress; + /** + * Constructs a {@link Server} instance with the specified webroot directory + * and the specified listening address. + * + * @param webroot the path to the webroot directory from which files will be served + * @param listenAddress the address and port the server will listen on + */ public Server(Path webroot, InetSocketAddress listenAddress) { this.webroot = webroot; this.listenAddress = listenAddress; } + /** + * Constructs a {@link Server} instance with the specified webroot directory. + * The server will bind to the localhost address with a dynamically chosen port. + * + * @param webroot the path to the webroot directory from which files will be served + */ public Server(Path webroot) { this(webroot, new InetSocketAddress("localhost", 0)); } + /** + * Starts an HTTP server on the specified listen address. + * + * @throws IOException if an I/O error occurs during server initialization + */ public void start() throws IOException { var server = HttpServer.create(listenAddress, 0); server.createContext("/", this); @@ -33,6 +55,9 @@ public class Server implements HttpHandler { this.listenAddress = server.getAddress(); } + /** + * Attempts to open the default web browser and navigate to the server's URL. + */ public void openBrowser() { try { var process = Runtime.getRuntime().exec(new String[] { "xdg-open", "http://" + listenAddress.getHostString() + ":" + listenAddress.getPort() }); diff --git a/src/main/java/eu/m724/blog/TemplateRenderer.java b/src/main/java/eu/m724/blog/TemplateRenderer.java index a8eaaf5..5378e4f 100644 --- a/src/main/java/eu/m724/blog/TemplateRenderer.java +++ b/src/main/java/eu/m724/blog/TemplateRenderer.java @@ -16,9 +16,18 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +/** + * The {@code TemplateRenderer} class is responsible for rendering dynamic HTML templates + * using the Pebble templating engine. + */ public class TemplateRenderer { private final PebbleTemplate indexTemplate, articleTemplate; + /** + * Constructs a TemplateRenderer instance for rendering templates from the specified directory. + * + * @param templateDirectory the root directory containing the template files + */ public TemplateRenderer(Path templateDirectory) { var loader = new FileLoader(); loader.setPrefix(templateDirectory.toString()); @@ -61,6 +70,14 @@ public class TemplateRenderer { this.articleTemplate = pebbleEngine.getTemplate("article_template"); } + /** + * Renders the index page using this template. + * + * @param site the {@link Site} this index is for + * @param posts the {@link Post}s to be included in the index page + * @return the rendered index HTML page as a string + * @throws IOException if an error occurs during the template evaluation + */ public String renderIndex(Site site, ArrayList posts) throws IOException { Map context = Map.of( "site", site, @@ -73,6 +90,14 @@ public class TemplateRenderer { return writer.toString(); } + /** + * Renders the content of a post using this template. + * + * @param site the {@link Site} containing the post + * @param post the {@link Post} to be rendered + * @return the rendered post HTML page as a string + * @throws IOException if an error occurs during template evaluation + */ public String renderPost(Site site, Post post) throws IOException { Map context = Map.of( "site", site, diff --git a/src/main/java/eu/m724/blog/data/Feed.java b/src/main/java/eu/m724/blog/data/Feed.java index 82c9b03..97dd9d5 100644 --- a/src/main/java/eu/m724/blog/data/Feed.java +++ b/src/main/java/eu/m724/blog/data/Feed.java @@ -4,6 +4,13 @@ import java.time.format.DateTimeFormatter; import java.util.List; public class Feed { + /** + * Generates an RSS feed XML string for a given website and its list of blog posts. + * + * @param site the {@code Site} object representing the website for which the RSS feed is generated + * @param posts the list of {@code Post} objects representing the blog posts to include in the RSS feed + * @return a {@code String} containing the formatted RSS feed in XML + */ public static String generateRss(Site site, List posts) { var content = ""; content += "%s%s".formatted(site.name(), site.baseUrl()); diff --git a/src/main/java/eu/m724/blog/data/Post.java b/src/main/java/eu/m724/blog/data/Post.java index bf1ab59..99bc62a 100644 --- a/src/main/java/eu/m724/blog/data/Post.java +++ b/src/main/java/eu/m724/blog/data/Post.java @@ -10,6 +10,21 @@ import java.time.*; import java.util.HashMap; import java.util.Map; +/** + * The {@code Post} class represents a blog post with various attributes including metadata and content. + * + * @param slug A unique identifier for the post derived from the file name. + * @param title The title of the post. + * @param summary A brief summary of the post content. + * @param draft Indicates whether the post is marked as a draft or published. + * @param revisions The number of revisions the post has undergone in version control. + * @param createdBy The name of the author who created the post. + * @param createdAt The timestamp of when the post was first created. + * @param modifiedBy The name of the author who last modified the post. + * @param modifiedAt The timestamp of the last modification to the post. + * @param custom A map of custom properties or metadata associated with the post. + * @param rawContent The raw content of the post, which currently is usually HTML. + */ public record Post( String slug, String title, @@ -25,11 +40,17 @@ public record Post( Map custom, String rawContent ) { - // this is because we'll be not only supporting html - public String htmlContent() { - return rawContent; - } - + /** + * Creates a {@link Post} instance by reading and parsing the content of a post file. + *

+ * The method extracts metadata properties, content, and versioning information + * based on the Git history of the file. + * + * @param git the Git repository used to retrieve versioning and commit information + * @param path the relative path to the file within the "posts" directory + * @return a {@link Post} object populated with data extracted from the specified file + * @throws IOException if an error occurs during file reading + */ public static Post fromFile(Git git, Path path) throws IOException { /* read properties before filtering */ @@ -106,4 +127,13 @@ public record Post( return new Post(slug, title, summary, draft, revisions, createdBy, createdAt, modifiedBy, modifiedAt, custom, content); } + + /** + * Retrieves the raw HTML content associated with the post. + * + * @return the raw HTML content as a string + */ + public String htmlContent() { + return rawContent; + } } diff --git a/src/main/java/eu/m724/blog/data/Site.java b/src/main/java/eu/m724/blog/data/Site.java index f928667..9dc5f74 100644 --- a/src/main/java/eu/m724/blog/data/Site.java +++ b/src/main/java/eu/m724/blog/data/Site.java @@ -8,12 +8,27 @@ import java.nio.file.Path; import java.util.HashMap; import java.util.Map; +/** + * The {@code Site} class represents a website and its configuration. + * + * @param name the name of the site + * @param baseUrl the base URL of the site + * @param custom a map of additional custom properties + */ public record Site( String name, String baseUrl, Map custom ) { + /** + * Creates a {@link Site} object by reading and parsing the configuration file at the specified path.
+ * The configuration file must be a JSON file. + * + * @param path the path to the configuration file + * @return a {@link Site} object initialized with the data from the configuration file + * @throws IOException if an error occurs during file reading + */ public static Site fromConfig(Path path) throws IOException { var content = Files.readString(path); var json = new JSONObject(content); @@ -41,36 +56,4 @@ public record Site( name, baseUrl, custom ); } - - /* remained from gson - - private static Map deep(JsonObject jsonObject) { - return jsonObject.entrySet().stream() - .map(e -> new AbstractMap.SimpleEntry<>(e.getKey(), eToO(e.getValue()))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - } - - private static Object eToO(JsonElement element) { - if (element.isJsonArray()) { - return element.getAsJsonArray().asList().stream().map(Site::eToO).toList(); - } else if (element.isJsonObject()) { - return deep(element.getAsJsonObject()); - } else if (element.isJsonPrimitive()) { - try { - return element.getAsBoolean(); - } catch (IllegalStateException e) { } - - try { - return element.getAsLong(); - } catch (NumberFormatException e) { } - - try { - return element.getAsDouble(); - } catch (NumberFormatException e) { } - - // TODO - } - - return null; - }*/ }