A Python content management system designed for kirsle.net featuring a blog, comments and photo albums. https://rophako.kirsle.net/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
7.2KB

  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals, absolute_import
  3. """Endpoints for the commenting subsystem."""
  4. from flask import Blueprint, g, request, redirect, url_for, flash
  5. import time
  6. import rophako.model.user as User
  7. import rophako.model.comment as Comment
  8. from rophako.utils import (template, pretty_time, login_required, sanitize_name,
  9. remote_addr)
  10. from rophako.plugin import load_plugin
  11. from rophako.settings import Config
  12. mod = Blueprint("comment", __name__, url_prefix="/comments")
  13. load_plugin("rophako.modules.emoticons")
  14. @mod.route("/")
  15. def index():
  16. return template("blog/index.html")
  17. @mod.route("/preview", methods=["POST"])
  18. def preview():
  19. # Get the form fields.
  20. form = get_comment_form(request.form)
  21. thread = sanitize_name(form["thread"])
  22. # Trap fields.
  23. trap1 = request.form.get("website", "x") != "http://"
  24. trap2 = request.form.get("email", "x") != ""
  25. if trap1 or trap2:
  26. flash("Wanna try that again?")
  27. return redirect(url_for("index"))
  28. # Validate things.
  29. if len(form["message"]) == 0:
  30. flash("You must provide a message with your comment.")
  31. return redirect(form["url"])
  32. # Gravatar?
  33. gravatar = Comment.gravatar(form["contact"])
  34. # Are they submitting?
  35. if form["action"] == "submit":
  36. Comment.add_comment(
  37. thread=thread,
  38. uid=g.info["session"]["uid"],
  39. ip=remote_addr(),
  40. time=int(time.time()),
  41. image=gravatar,
  42. name=form["name"],
  43. subject=form["subject"],
  44. message=form["message"],
  45. url=form["url"],
  46. )
  47. # Are we subscribing to the thread?
  48. if form["subscribe"] == "true":
  49. email = form["contact"]
  50. if "@" in email:
  51. Comment.add_subscriber(thread, email)
  52. flash("You have been subscribed to future comments on this page.")
  53. flash("Your comment has been added!")
  54. return redirect(form["url"])
  55. # Gravatar.
  56. g.info["gravatar"] = gravatar
  57. g.info["preview"] = Comment.format_message(form["message"])
  58. g.info["pretty_time"] = pretty_time(Config.comment.time_format, time.time())
  59. g.info.update(form)
  60. return template("comment/preview.html")
  61. @mod.route("/delete/<thread>/<cid>")
  62. @login_required
  63. def delete(thread, cid):
  64. """Delete a comment."""
  65. url = request.args.get("url")
  66. Comment.delete_comment(thread, cid)
  67. flash("Comment deleted!")
  68. return redirect(url or url_for("index"))
  69. @mod.route("/edit/<thread>/<cid>", methods=["GET", "POST"])
  70. @login_required
  71. def edit(thread, cid):
  72. """Edit an existing comment."""
  73. url = request.args.get("url")
  74. comment = Comment.get_comment(thread, cid)
  75. if not comment:
  76. flash("The comment wasn't found!")
  77. return redirect(url or url_for("index"))
  78. # Submitting?
  79. if request.method == "POST":
  80. action = request.form.get("action")
  81. message = request.form.get("message")
  82. url = request.form.get("url") # Preserve the URL!
  83. if len(message) == 0:
  84. flash("The comment must have a message!")
  85. return redirect(url_for(".edit", thread=thread, cid=cid, url=url))
  86. # Update the real comment data with the submitted message (for preview),
  87. # if they clicked Save it will then be saved back to disk.
  88. comment["message"] = message
  89. if action == "save":
  90. # Saving the changes!
  91. Comment.update_comment(thread, cid, comment)
  92. flash("Comment updated successfully!")
  93. return redirect(url or url_for("index"))
  94. # Render the Markdown.
  95. comment["formatted_message"] = Comment.format_message(comment["message"])
  96. g.info["thread"] = thread
  97. g.info["cid"] = cid
  98. g.info["comment"] = comment
  99. g.info["url"] = url or ""
  100. return template("comment/edit.html")
  101. @mod.route("/privacy")
  102. def privacy():
  103. """The privacy policy and global unsubscribe page."""
  104. return template("comment/privacy.html")
  105. @mod.route("/unsubscribe", methods=["GET", "POST"])
  106. def unsubscribe():
  107. """Unsubscribe an e-mail from a comment thread (or all threads)."""
  108. # This endpoint can be called with either method. For the unsubscribe links
  109. # inside the e-mails, it uses GET. For the global out-opt, it uses POST.
  110. thread, email = None, None
  111. if request.method == "POST":
  112. thread = request.form.get("thread", "")
  113. email = request.form.get("email", "")
  114. # Spam check.
  115. trap1 = request.form.get("url", "x") != "http://"
  116. trap2 = request.form.get("message", "x") != ""
  117. if trap1 or trap2:
  118. flash("Wanna try that again?")
  119. return redirect(url_for("index"))
  120. else:
  121. thread = request.args.get("thread", "")
  122. email = request.args.get("who", "")
  123. # Input validation.
  124. if not thread:
  125. flash("Comment thread not found.")
  126. return redirect(url_for("index"))
  127. if not email:
  128. flash("E-mail address not provided.")
  129. return redirect(url_for("index"))
  130. # Do the unsubscribe. If thread is *, this means a global unsubscribe from
  131. # all threads.
  132. Comment.unsubscribe(thread, email)
  133. g.info["thread"] = thread
  134. g.info["email"] = email
  135. return template("comment/unsubscribed.html")
  136. def partial_index(thread, subject, header=True, addable=True):
  137. """Partial template for including the index view of a comment thread.
  138. * thread: unique name for the comment thread
  139. * subject: subject name for the comment thread
  140. * header: show the Comments h1 header
  141. * addable: boolean, can new comments be added to the thread"""
  142. comments = Comment.get_comments(thread)
  143. # Sort the comments by most recent on bottom.
  144. sorted_cids = [ x for x in sorted(comments, key=lambda y: comments[y]["time"]) ]
  145. sorted_comments = []
  146. for cid in sorted_cids:
  147. comment = comments[cid]
  148. comment["id"] = cid
  149. # Was the commenter logged in?
  150. if comment["uid"] > 0:
  151. user = User.get_user(uid=comment["uid"])
  152. avatar = User.get_picture(uid=comment["uid"])
  153. comment["name"] = user["name"]
  154. comment["username"] = user["username"]
  155. comment["image"] = avatar
  156. # Add the pretty time.
  157. comment["pretty_time"] = pretty_time(Config.comment.time_format, comment["time"])
  158. # Format the message for display.
  159. comment["formatted_message"] = Comment.format_message(comment["message"])
  160. sorted_comments.append(comment)
  161. g.info["header"] = header
  162. g.info["thread"] = thread
  163. g.info["subject"] = subject
  164. g.info["commenting_disabled"] = not addable
  165. g.info["url"] = request.url
  166. g.info["comments"] = sorted_comments
  167. g.info["photo_url"] = Config.photo.root_public
  168. return template("comment/index.inc.html")
  169. def get_comment_form(form):
  170. return dict(
  171. action = request.form.get("action", ""),
  172. thread = request.form.get("thread", ""),
  173. url = request.form.get("url", ""),
  174. subject = request.form.get("subject", "[No Subject]"),
  175. name = request.form.get("name", ""),
  176. contact = request.form.get("contact", ""),
  177. message = request.form.get("message", ""),
  178. subscribe = request.form.get("subscribe", "false"),
  179. )