diff --git a/pelican_comment_system/Readme.md b/pelican_comment_system/Readme.md new file mode 100644 index 0000000..441cbab --- /dev/null +++ b/pelican_comment_system/Readme.md @@ -0,0 +1,110 @@ +# Pelican comment system +The pelican comment system allows you to add static comments to your articles. It also supports replies to comments. + +The comments are stored in Markdown files. Each comment in it own file. + +See it in action here: [blog.scheirle.de](http://blog.scheirle.de/posts/2014/March/29/static-comments-via-email/) + +Thanks to jesrui the author of [Static comments](https://github.com/getpelican/pelican-plugins/tree/master/static_comments). I reused some code from it. + +## Installation +Activate the plugin by adding it you your `pelicanconf.py` + + PLUGIN_PATH = '/path/to/pelican-plugins' + PLUGINS = ['pelican_comment_system'] + PELICAN_COMMENT_SYSTEM = True + +And modify your `article.html` theme (see below). + +## Settings +Name | Type | Default | Description +-----------------------------|-----------|------------|------- +`PELICAN_COMMENT_SYSTEM` | `boolean` | `False` | Activates or deactivates the comment system +`PELICAN_COMMENT_SYSTEM_DIR` | `string` | `comments` | Folder where the comments are stored + + +### Folder structure +Every comment file has to be stored in a sub folder of `PELICAN_COMMENT_SYSTEM_DIR`. +Sub folders are named after the `slug` of the articles. + +So the comments to your `foo-bar` article are stored in `comments/foo-bar/` + +The filenames of the comment files are up to you. But the filename is the Identifier of the comment (without extension). + +##### Example folder structure + + . + └── comments + └── foo-bar + │ ├── 1.md + │ └── 0.md + └── some-other-slug + ├── random-Name.md + ├── 1.md + └── 0.md + + +### Comment file +##### Meta information +Tag | Required | Description +--------------|-----------|---------------- +`date` | yes | Date when the comment was posted +`replyto` | no | Identifier of the parent comment. Identifier = Filename (without extension) +`locale_date` | forbidden | Will be overwritten with a locale representation of the date + +Every other (custom) tag gets parsed as well and will be available through the theme. + + +##### Example of a comment file + + date: 2014-3-21 15:02 + author: Author of the comment + website: http://authors.website.com + replyto: 7 + anothermetatag: some random tag + + Content of the comment. + +### Theme +In the `article.html` theme file are now two more variables available. + +Variables | Description +----------------------------------|-------------------------- +`article.metadata.comments_count` | Amount of total comments for this article (including replies to comments) +`article.metadata.comments` | Array containing the top level comments for this article (no replies to comments) + +#### Comment object +Variables | Description +-----------|-------------------------- +`id` | Identifier of this comment +`content` | Content of this comment +`metadata` | All metadata as in the comment file (or described above) +`replies` | Array containing the top level replies for this comment + +##### Example article.html theme +(only the comment section) + +```html +{% if article.metadata.comments %} + {% for comment in article.metadata.comments recursive %} + {% set metadata = comment.metadata %} + {% if loop.depth0 == 0 %} + {% set marginLeft = 0 %} + {% else %} + {% set marginLeft = 50 %} + {% endif %} +
+ Permalink +

{{ metadata['author'] }}

+

Posted on {{ metadata['locale_date'] }}

+ + {{ comment.content }} + {% if comment.replies %} + {{ loop(comment.replies) }} + {% endif %} +
+ {% endfor %} +{% else %} +

There are no comments yet.

+{% endif %} +``` diff --git a/pelican_comment_system/__init__.py b/pelican_comment_system/__init__.py new file mode 100644 index 0000000..4c8a3ca --- /dev/null +++ b/pelican_comment_system/__init__.py @@ -0,0 +1 @@ +from .pelican_comment_system import * diff --git a/pelican_comment_system/pelican_comment_system.py b/pelican_comment_system/pelican_comment_system.py new file mode 100644 index 0000000..bf281bf --- /dev/null +++ b/pelican_comment_system/pelican_comment_system.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- + +import logging +import os + +logger = logging.getLogger(__name__) + +from itertools import chain +from pelican import signals +from pelican.utils import strftime +from pelican.readers import MarkdownReader + +class Comment: + def __init__(self, id, metadata, content): + self.id = id + self.content = content + self.metadata = metadata + self.replies = [] + + def addReply(self, comment): + self.replies.append(comment) + + def getReply(self, id): + for reply in self.replies: + if reply.id == id: + return reply + else: + deepReply = reply.getReply(id) + if deepReply != None: + return deepReply + return None + + def __lt__(self, other): + return self.metadata['date'] < other.metadata['date'] + + def sort(self): + for r in self.replies: + r.sort() + self.replies = sorted(self.replies) + + def countReplies(self): + amount = 0 + for r in self.replies: + amount += r.countReplies() + return amount + len(self.replies) + +def initialized(pelican): + from pelican.settings import DEFAULT_CONFIG + DEFAULT_CONFIG.setdefault('PELICAN_COMMENT_SYSTEM', False) + DEFAULT_CONFIG.setdefault('PELICAN_COMMENT_SYSTEM_DIR' 'comments') + if pelican: + pelican.settings.setdefault('PELICAN_COMMENT_SYSTEM', False) + pelican.settings.setdefault('PELICAN_COMMENT_SYSTEM_DIR', 'comments') + + +def add_static_comments(gen, metadata): + if gen.settings['PELICAN_COMMENT_SYSTEM'] != True: + return + + metadata['comments_count'] = 0 + metadata['comments'] = [] + + if not 'slug' in metadata: + logger.warning("pelican_comment_system: cant't locate comments files without slug tag in the article") + return + + reader = MarkdownReader(gen.settings) + comments = [] + replies = [] + folder = os.path.join(gen.settings['PELICAN_COMMENT_SYSTEM_DIR'], metadata['slug']) + + if not os.path.isdir(folder): + logger.debug("No comments found for: " + metadata['slug']) + return + + for file in os.listdir(folder): + name, extension = os.path.splitext(file) + if extension[1:].lower() in reader.file_extensions: + content, meta = reader.read(folder + "/" + file) + meta['locale_date'] = strftime(meta['date'], gen.settings['DEFAULT_DATE_FORMAT']) + com = Comment(name, meta, content) + if 'replyto' in meta: + replies.append( com ) + else: + comments.append( com ) + + for reply in replies: + for comment in chain(comments, replies): + if comment.id == reply.metadata['replyto']: + comment.addReply(reply) + + count = 0 + for comment in comments: + comment.sort() + count += comment.countReplies() + + comments = sorted(comments) + + metadata['comments_count'] = len(comments) + count + metadata['comments'] = comments + +def register(): + signals.initialized.connect(initialized) + signals.article_generator_context.connect(add_static_comments)