diff options
| author | user <user@node5.net> | 2024-02-26 16:38:16 +0100 |
|---|---|---|
| committer | user <user@node5.net> | 2024-02-26 16:38:16 +0100 |
| commit | ac71b7ca1de2462e3101c5360842de80079449d2 (patch) | |
| tree | 36e86ed8ba92cbba12869f899a3f1f7af665afae /src | |
| parent | 920b0d0d862d09ac1364ebd5888fb7e7a59aafc7 (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.py | 33 | ||||
| -rw-r--r-- | src/blog_node5_net.py | 65 |
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 |
