Added plugin: pelican comment system
This commit is contained in:
110
pelican_comment_system/Readme.md
Normal file
110
pelican_comment_system/Readme.md
Normal file
@@ -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 %}
|
||||||
|
<article id="comment-{{comment.id}}" style="border: 1px solid #DDDDDD; padding: 5px 0px 0px 5px; margin: 0px -1px 5px {{marginLeft}}px;">
|
||||||
|
<a href="{{ SITEURL }}/{{ article.url }}#comment-{{comment.id}}" rel="bookmark" title="Permalink to this comment">Permalink</a>
|
||||||
|
<h4>{{ metadata['author'] }}</h4>
|
||||||
|
<p>Posted on <abbr class="published" title="{{ metadata['date'].isoformat() }}">{{ metadata['locale_date'] }}</abbr></p>
|
||||||
|
|
||||||
|
{{ comment.content }}
|
||||||
|
{% if comment.replies %}
|
||||||
|
{{ loop(comment.replies) }}
|
||||||
|
{% endif %}
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<p>There are no comments yet.<p>
|
||||||
|
{% endif %}
|
||||||
|
```
|
||||||
1
pelican_comment_system/__init__.py
Normal file
1
pelican_comment_system/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .pelican_comment_system import *
|
||||||
104
pelican_comment_system/pelican_comment_system.py
Normal file
104
pelican_comment_system/pelican_comment_system.py
Normal file
@@ -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)
|
||||||
Reference in New Issue
Block a user