pelican_comment_system.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. # -*- coding: utf-8 -*-
  2. """
  3. Pelican Comment System
  4. ======================
  5. A Pelican plugin, which allows you to add comments to your articles.
  6. Author: Bernhard Scheirle
  7. """
  8. from __future__ import unicode_literals
  9. import logging
  10. import os
  11. import copy
  12. logger = logging.getLogger(__name__)
  13. from itertools import chain
  14. from pelican import signals
  15. from pelican.readers import Readers
  16. from pelican.writers import Writer
  17. from . comment import Comment
  18. from . import avatars
  19. def setdefault(pelican, settings):
  20. from pelican.settings import DEFAULT_CONFIG
  21. for key, value in settings:
  22. DEFAULT_CONFIG.setdefault(key, value)
  23. if not pelican:
  24. return
  25. for key, value in settings:
  26. pelican.settings.setdefault(key, value)
  27. def pelican_initialized(pelican):
  28. from pelican.settings import DEFAULT_CONFIG
  29. settings = [
  30. ('PELICAN_COMMENT_SYSTEM', False),
  31. ('PELICAN_COMMENT_SYSTEM_DIR', 'comments'),
  32. ('PELICAN_COMMENT_SYSTEM_IDENTICON_OUTPUT_PATH', 'images/identicon'),
  33. ('PELICAN_COMMENT_SYSTEM_IDENTICON_DATA', ()),
  34. ('PELICAN_COMMENT_SYSTEM_IDENTICON_SIZE', 72),
  35. ('PELICAN_COMMENT_SYSTEM_AUTHORS', {}),
  36. ('PELICAN_COMMENT_SYSTEM_FEED', os.path.join('feeds', 'comment.%s.atom.xml')),
  37. ('COMMENT_URL', '#comment-{slug}')
  38. ]
  39. setdefault(pelican, settings)
  40. DEFAULT_CONFIG['PAGE_EXCLUDES'].append(
  41. DEFAULT_CONFIG['PELICAN_COMMENT_SYSTEM_DIR'])
  42. DEFAULT_CONFIG['ARTICLE_EXCLUDES'].append(
  43. DEFAULT_CONFIG['PELICAN_COMMENT_SYSTEM_DIR'])
  44. if pelican:
  45. pelican.settings['PAGE_EXCLUDES'].append(
  46. pelican.settings['PELICAN_COMMENT_SYSTEM_DIR'])
  47. pelican.settings['ARTICLE_EXCLUDES'].append(
  48. pelican.settings['PELICAN_COMMENT_SYSTEM_DIR'])
  49. def initialize(article_generator):
  50. avatars.init(
  51. article_generator.settings['OUTPUT_PATH'],
  52. article_generator.settings[
  53. 'PELICAN_COMMENT_SYSTEM_IDENTICON_OUTPUT_PATH'],
  54. article_generator.settings['PELICAN_COMMENT_SYSTEM_IDENTICON_DATA'],
  55. article_generator.settings[
  56. 'PELICAN_COMMENT_SYSTEM_IDENTICON_SIZE'] / 3,
  57. article_generator.settings['PELICAN_COMMENT_SYSTEM_AUTHORS'],
  58. )
  59. def warn_on_slug_collision(items):
  60. slugs = {}
  61. for comment in items:
  62. if not comment.slug in slugs:
  63. slugs[comment.slug] = [comment]
  64. else:
  65. slugs[comment.slug].append(comment)
  66. for slug, itemList in slugs.items():
  67. len_ = len(itemList)
  68. if len_ > 1:
  69. logger.warning('There are %s comments with the same slug: %s' %
  70. (len_, slug))
  71. for x in itemList:
  72. logger.warning(' %s' % x.source_path)
  73. def write_feed(gen, items, context, slug):
  74. if gen.settings['PELICAN_COMMENT_SYSTEM_FEED'] is None:
  75. return
  76. path = gen.settings['PELICAN_COMMENT_SYSTEM_FEED'] % slug
  77. writer = Writer(gen.output_path, settings=gen.settings)
  78. writer.write_feed(items, context, path)
  79. def add_static_comments(gen, content):
  80. if gen.settings['PELICAN_COMMENT_SYSTEM'] is not True:
  81. return
  82. content.comments_count = 0
  83. content.comments = []
  84. # Modify the local context, so we get proper values for the feed
  85. context = copy.copy(gen.context)
  86. context['SITEURL'] += "/" + content.url
  87. context['SITENAME'] += " - Comments: " + content.title
  88. context['SITESUBTITLE'] = ""
  89. folder = os.path.join(
  90. gen.settings['PATH'],
  91. gen.settings['PELICAN_COMMENT_SYSTEM_DIR'],
  92. content.slug
  93. )
  94. if not os.path.isdir(folder):
  95. logger.debug("No comments found for: " + content.slug)
  96. write_feed(gen, [], context, content.slug)
  97. return
  98. reader = Readers(gen.settings)
  99. comments = []
  100. replies = []
  101. for file in os.listdir(folder):
  102. name, extension = os.path.splitext(file)
  103. if extension[1:].lower() in reader.extensions:
  104. com = reader.read_file(
  105. base_path=folder, path=file,
  106. content_class=Comment, context=context)
  107. if hasattr(com, 'replyto'):
  108. replies.append(com)
  109. else:
  110. comments.append(com)
  111. warn_on_slug_collision(comments + replies)
  112. write_feed(gen, comments + replies, context, content.slug)
  113. # TODO: Fix this O(n²) loop
  114. for reply in replies:
  115. for comment in chain(comments, replies):
  116. if comment.slug == reply.replyto:
  117. comment.addReply(reply)
  118. count = 0
  119. for comment in comments:
  120. comment.sortReplies()
  121. count += comment.countReplies()
  122. comments = sorted(comments)
  123. content.comments_count = len(comments) + count
  124. content.comments = comments
  125. def writeIdenticonsToDisk(gen, writer):
  126. avatars.generateAndSaveMissingAvatars()
  127. def register():
  128. signals.initialized.connect(pelican_initialized)
  129. signals.article_generator_init.connect(initialize)
  130. signals.article_generator_write_article.connect(add_static_comments)
  131. signals.article_writer_finalized.connect(writeIdenticonsToDisk)