aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoruser <user@node5.net>2024-02-26 16:38:16 +0100
committeruser <user@node5.net>2024-02-26 16:38:16 +0100
commitac71b7ca1de2462e3101c5360842de80079449d2 (patch)
tree36e86ed8ba92cbba12869f899a3f1f7af665afae /src
parent920b0d0d862d09ac1364ebd5888fb7e7a59aafc7 (diff)
article and folder data retrieved on request, support trailing slashes, host article static content
Diffstat (limited to 'src')
-rw-r--r--src/article_handler.py33
-rw-r--r--src/blog_node5_net.py65
2 files changed, 72 insertions, 26 deletions
diff --git a/src/article_handler.py b/src/article_handler.py
index 2655bcc..6ee0420 100644
--- a/src/article_handler.py
+++ b/src/article_handler.py
@@ -5,6 +5,8 @@ import logging
import pathlib
import glob
import typing
+from typing import Tuple
+
import yaml
@@ -22,7 +24,12 @@ class ArticleNoMetaData(ArticleHandlerException):
@dataclasses.dataclass
-class MetaData:
+class WebPage:
+ url: str
+
+
+@dataclasses.dataclass
+class MetaData():
description: str
created: datetime.date
@@ -34,7 +41,7 @@ class MetaData:
@dataclasses.dataclass
-class Article:
+class Article(WebPage):
title: str
meta_data: MetaData
web_dir: tuple
@@ -43,31 +50,27 @@ class Article:
folder_path: typing.Union[None, str | os.PathLike] = None
@property
- def web_path(self):
- return f'{"/" if self.web_dir else ""}{"/".join(self.web_dir)}/{self.title}'
-
- @property
def pretty_print(self) -> str:
return f'''
Title: {self.title}
Meta data: {self.meta_data.pretty_print}
Web dir: {self.web_dir}
-Web path: {self.web_path}
+URL: {self.url}
Source path: {self.source_path}
Folder path: {self.folder_path}
Source: {f'{self.source[0:49]}...' if len(self.source) >= 50 else self.source}''' # Truncate long source text
@dataclasses.dataclass
-class Folder(list):
+class Folder(WebPage):
articles: typing.List[Article] = dataclasses.field(default_factory=list)
sub_folders: typing.Dict[str, typing.Self] = dataclasses.field(default_factory=dict)
-def get_web_dir(path, title) -> typing.Tuple[str]:
+def get_web_dir(path, title) -> tuple[str, ...]:
dir_structure = path.split(title)[0]
# Split into tuple, remove first part, assemble to path again, all to remove the first source dir agnostically
- dir_structure_prefix_striped = pathlib.Path(dir_structure).parts[1:]
+ dir_structure_prefix_striped = pathlib.Path(dir_structure).parts[2:]
return dir_structure_prefix_striped
@@ -97,6 +100,7 @@ def get_article(path: str | os.PathLike) -> Article:
if basename == 'index':
# Article is the folder
article_folder_name = os.path.dirname(path)
+ article_args['folder_path'] = article_folder_name
dir_basename = os.path.basename(article_folder_name)
article_args['title'] = dir_basename
else:
@@ -105,6 +109,9 @@ def get_article(path: str | os.PathLike) -> Article:
article_args['web_dir'] = get_web_dir(path, article_args['title'])
article_args['source_path'] = path
+ article_args[
+ 'url'] = f'{"/" if article_args["web_dir"] else ""}{"/".join(article_args["web_dir"])}/{article_args["title"]}'
+
with open(path, 'r') as file:
source = file.read()
article_args['source'], article_args['meta_data'] = parse_article_meta_data(source)
@@ -113,14 +120,14 @@ def get_article(path: str | os.PathLike) -> Article:
return article
-def discover_folder_structure(article: Article, articles: typing.List[Article]):
+def discover_folder_structure(article: Article, articles: Folder):
previous_folder = articles
for folder_name in article.web_dir:
logging.debug(folder_name)
if folder_name not in previous_folder.sub_folders:
logging.debug('new')
- current_folder = Folder()
+ current_folder = Folder(url=f'{previous_folder.url}{folder_name}/')
previous_folder.sub_folders[folder_name] = current_folder
else:
logging.debug('reuse')
@@ -133,7 +140,7 @@ def discover_folder_structure(article: Article, articles: typing.List[Article]):
def discover_articles(path):
articles_paths = glob.glob(f'{path}/**/*.md', recursive=True) # Equivalent to ls ./**.md
- articles = Folder()
+ articles = Folder(url='/')
for article_path in articles_paths:
article = get_article(article_path)
logging.debug(article.pretty_print)
diff --git a/src/blog_node5_net.py b/src/blog_node5_net.py
index 91e9884..fcaf750 100644
--- a/src/blog_node5_net.py
+++ b/src/blog_node5_net.py
@@ -1,27 +1,66 @@
import logging
import flask
+import typing
import os
-import pathlib
+
import article_handler
logging.basicConfig(format='%(asctime)s,%(msecs)03d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
- datefmt='%Y-%m-%d:%H:%M:%S',
- level=logging.DEBUG)
+ datefmt='%Y-%m-%d:%H:%M:%S',
+ level=logging.DEBUG)
logger = logging.getLogger(__name__)
app = flask.Flask(__name__)
-def article():
- return "article"
+site_root_folder_path = 'blog.node5.net'
-try:
- articles = article_handler.discover_articles('articles')
-except article_handler.ArticleHandlerException as exception: # Known exception
- logger.error(exception)
- exit(1) # Exit code 1: Code for generic errors
+folders_by_url: typing.Dict[str, article_handler.Folder] = {}
+articles_by_url: typing.Dict[str, article_handler.Article] = {}
+
+
+def strip_trailing_slash(path):
+ '''
+ Strip trailing slashes from path
+ '''
+ stripped_path = path if not path[len(path) - 1] == '/' else path[:-1]
+ return stripped_path
+
+def view_folder():
+ path = flask.request.path
+ if path is not '/':
+ path = strip_trailing_slash(flask.request.path)
+ a = folders_by_url[path]
+ return 'Folder'
-@app.route("/")
-def index():
- return ""
+def view_article():
+ path = strip_trailing_slash(flask.request.path)
+ return articles_by_url[path].pretty_print
+
+def register_urls(folder: article_handler.Folder):
+ # Use recursion to traverse folder tree structure
+ app.add_url_rule(folder.url, view_func=view_folder)
+ folders_by_url[strip_trailing_slash(folder.url)] = folder
+ for article in folder.articles:
+ logger.debug(f"Registering url: {article.url}, static path: {article.folder_path}")
+ blueprint_args = {}
+ # Some articles are one file, and don't have a folder, hence argument would give an error
+ if article.folder_path:
+ blueprint_args['static_folder'] = os.path.abspath(article.folder_path)
+ blueprint_args['static_url_path'] = ''
+ blueprint = flask.Blueprint(article.title, __name__, url_prefix=article.url, **blueprint_args)
+ blueprint.add_url_rule('/', view_func=view_article)
+ app.register_blueprint(blueprint)
+ # app.add_url_rule(article.url, view_func=view_article)
+ articles_by_url[article.url] = article
+ for sub_folder in folder.sub_folders.values():
+ register_urls(sub_folder)
+
+
+try:
+ articles = article_handler.discover_articles(os.path.join(site_root_folder_path, 'articles'))
+ register_urls(articles)
+except article_handler.ArticleHandlerException as exception: # Known exceptions
+ logger.error(exception)
+ exit(1) # Exit code 1: Code for generic errors