views.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. # -*- coding: utf-8 -*-
  2. """
  3. flaskbb.forum.views
  4. ~~~~~~~~~~~~~~~~~~~~
  5. This module handles the forum logic like creating and viewing
  6. topics and posts.
  7. :copyright: (c) 2013 by the FlaskBB Team.
  8. :license: BSD, see LICENSE for more details.
  9. """
  10. import datetime
  11. import math
  12. from flask import (Blueprint, render_template, redirect, url_for, current_app,
  13. request, flash)
  14. from flask.ext.login import login_required, current_user
  15. from flaskbb.extensions import db
  16. from flaskbb.utils.helpers import (can_post_reply, can_delete_topic,
  17. can_edit_post, can_post_topic,
  18. can_delete_post, can_lock_topic,
  19. get_online_users, time_diff)
  20. from flaskbb.forum.models import Forum, Topic, Post, ForumsRead, TopicsRead
  21. from flaskbb.forum.forms import QuickreplyForm, ReplyForm, NewTopicForm
  22. from flaskbb.forum.helpers import get_forums
  23. from flaskbb.user.models import User
  24. forum = Blueprint("forum", __name__)
  25. @forum.route("/")
  26. def index():
  27. # Get the categories and forums
  28. if current_user.is_authenticated():
  29. categories_query = Forum.query.\
  30. outerjoin(ForumsRead,
  31. db.and_(ForumsRead.forum_id == Forum.id,
  32. ForumsRead.user_id == current_user.id)).\
  33. add_entity(ForumsRead).\
  34. order_by(Forum.position.asc()).\
  35. all()
  36. categories = get_forums(categories_query, current_user=True)
  37. else:
  38. categories_query = Forum.query.order_by(Forum.position.asc()).all()
  39. categories = get_forums(categories_query, current_user=False)
  40. # Fetch a few stats about the forum
  41. user_count = User.query.count()
  42. topic_count = Topic.query.count()
  43. post_count = Post.query.count()
  44. newest_user = User.query.order_by(User.id.desc()).first()
  45. # Check if we use redis or not
  46. if not current_app.config["USE_REDIS"]:
  47. online_users = User.query.filter(User.lastseen >= time_diff()).count()
  48. online_guests = None
  49. else:
  50. online_users = len(get_online_users())
  51. online_guests = len(get_online_users(guest=True))
  52. return render_template("forum/index.html",
  53. categories=categories,
  54. user_count=user_count,
  55. topic_count=topic_count,
  56. post_count=post_count,
  57. newest_user=newest_user,
  58. online_users=online_users,
  59. online_guests=online_guests)
  60. @forum.route("/forum/<int:forum_id>")
  61. def view_forum(forum_id):
  62. page = request.args.get('page', 1, type=int)
  63. if current_user.is_authenticated():
  64. forum = Forum.query.filter(Forum.id == forum_id).first()
  65. subforums = Forum.query.\
  66. filter(Forum.parent_id == forum.id).\
  67. outerjoin(ForumsRead,
  68. db.and_(ForumsRead.forum_id == Forum.id,
  69. ForumsRead.user_id == current_user.id)).\
  70. add_entity(ForumsRead).\
  71. all()
  72. topics = Topic.query.filter_by(forum_id=forum.id).\
  73. filter(Post.topic_id == Topic.id).\
  74. outerjoin(TopicsRead,
  75. db.and_(TopicsRead.topic_id == Topic.id,
  76. TopicsRead.user_id == current_user.id)).\
  77. add_entity(TopicsRead).\
  78. order_by(Post.id.desc()).\
  79. paginate(page, current_app.config['TOPICS_PER_PAGE'], True)
  80. else:
  81. forum = Forum.query.filter(Forum.id == forum_id).first()
  82. subforums = Forum.query.filter(Forum.parent_id == forum.id).all()
  83. # This isn't really nice imho, but "add_entity" (see above)
  84. # makes a list with tuples
  85. subforums = [(item, None) for item in subforums]
  86. topics = Topic.query.filter_by(forum_id=forum.id).\
  87. filter(Post.topic_id == Topic.id).\
  88. order_by(Post.id.desc()).\
  89. paginate(page, current_app.config['TOPICS_PER_PAGE'], True, True)
  90. return render_template("forum/forum.html",
  91. forum=forum, topics=topics, subforums=subforums)
  92. @forum.route("/topic/<int:topic_id>", methods=["POST", "GET"])
  93. def view_topic(topic_id):
  94. page = request.args.get('page', 1, type=int)
  95. topic = Topic.query.filter_by(id=topic_id).first()
  96. posts = Post.query.filter_by(topic_id=topic.id).\
  97. paginate(page, current_app.config['POSTS_PER_PAGE'], False)
  98. # Count the topic views
  99. topic.views += 1
  100. # Update the topicsread status if the user hasn't read it
  101. topic.update_read(current_user, topic.forum)
  102. topic.save()
  103. form = None
  104. if not topic.locked \
  105. and not topic.forum.locked \
  106. and can_post_reply(user=current_user,
  107. forum=topic.forum):
  108. form = QuickreplyForm()
  109. if form.validate_on_submit():
  110. post = form.save(current_user, topic)
  111. return view_post(post.id)
  112. return render_template("forum/topic.html", topic=topic, posts=posts,
  113. last_seen=time_diff(), form=form)
  114. @forum.route("/post/<int:post_id>")
  115. def view_post(post_id):
  116. post = Post.query.filter_by(id=post_id).first()
  117. count = post.topic.post_count
  118. page = math.ceil(count / current_app.config["POSTS_PER_PAGE"])
  119. if count > 10:
  120. page += 1
  121. else:
  122. page = 1
  123. return redirect(url_for("forum.view_topic", topic_id=post.topic.id) +
  124. "?page=%d#pid%s" % (page, post.id))
  125. @forum.route("/forum/<int:forum_id>/topic/new", methods=["POST", "GET"])
  126. @login_required
  127. def new_topic(forum_id):
  128. forum = Forum.query.filter_by(id=forum_id).first()
  129. if forum.locked:
  130. flash("This forum is locked; you cannot submit new topics or posts.",
  131. "error")
  132. return redirect(url_for('forum.view_forum', forum_id=forum.id))
  133. if not can_post_topic(user=current_user, forum=forum):
  134. flash("You do not have the permissions to create a new topic.", "error")
  135. return redirect(url_for('forum.view_forum', forum_id=forum.id))
  136. form = NewTopicForm()
  137. if form.validate_on_submit():
  138. topic = form.save(current_user, forum)
  139. # redirect to the new topic
  140. return redirect(url_for('forum.view_topic', topic_id=topic.id))
  141. return render_template("forum/new_topic.html", forum=forum, form=form)
  142. @forum.route("/topic/<int:topic_id>/delete")
  143. @login_required
  144. def delete_topic(topic_id):
  145. topic = Topic.query.filter_by(id=topic_id).first()
  146. if not can_delete_topic(user=current_user, forum=topic.forum,
  147. post_user_id=topic.first_post.user_id):
  148. flash("You do not have the permissions to delete the topic", "error")
  149. return redirect(url_for("forum.view_forum", forum_id=topic.forum_id))
  150. involved_users = User.query.filter(Post.topic_id == topic.id,
  151. User.id == Post.user_id).all()
  152. topic.delete(users=involved_users)
  153. return redirect(url_for("forum.view_forum", forum_id=topic.forum_id))
  154. @forum.route("/topic/<int:topic_id>/lock")
  155. @login_required
  156. def lock_topic(topic_id):
  157. topic = Topic.query.filter_by(id=topic_id).first_or_404()
  158. if not can_lock_topic(user=current_user, forum=topic.forum):
  159. flash("Yo do not have the permissions to lock this topic", "danger")
  160. return redirect(url_for("forum.view_topic", topic_id=topic.id))
  161. topic.locked = True
  162. topic.save()
  163. return redirect(url_for("forum.view_topic", topic_id=topic.id))
  164. @forum.route("/topic/<int:topic_id>/unlock")
  165. @login_required
  166. def unlock_topic(topic_id):
  167. topic = Topic.query.filter_by(id=topic_id).first_or_404()
  168. # Unlock is basically the same as lock
  169. if not can_lock_topic(user=current_user, forum=topic.forum):
  170. flash("Yo do not have the permissions to unlock this topic", "danger")
  171. return redirect(url_for("forum.view_topic", topic_id=topic.id))
  172. topic.locked = False
  173. topic.save()
  174. return redirect(url_for("forum.view_topic", topic_id=topic.id))
  175. @forum.route("/topic/<int:topic_id>/move")
  176. @login_required
  177. def move_topic(topic_id):
  178. pass
  179. @forum.route("/topic/<int:topic_id>/post/new", methods=["POST", "GET"])
  180. @login_required
  181. def new_post(topic_id):
  182. topic = Topic.query.filter_by(id=topic_id).first()
  183. if topic.forum.locked:
  184. flash("This forum is locked; you cannot submit new topics or posts.",
  185. "error")
  186. return redirect(url_for('forum.view_forum', forum_id=topic.forum.id))
  187. if topic.locked:
  188. flash("The topic is locked.", "error")
  189. return redirect(url_for("forum.view_forum", forum_id=topic.forum_id))
  190. if not can_post_reply(user=current_user, forum=topic.forum):
  191. flash("You do not have the permissions to delete the topic", "error")
  192. return redirect(url_for("forum.view_forum", forum_id=topic.forum_id))
  193. form = ReplyForm()
  194. if form.validate_on_submit():
  195. post = form.save(current_user, topic)
  196. return view_post(post.id)
  197. return render_template("forum/new_post.html", topic=topic, form=form)
  198. @forum.route("/post/<int:post_id>/edit", methods=["POST", "GET"])
  199. @login_required
  200. def edit_post(post_id):
  201. post = Post.query.filter_by(id=post_id).first()
  202. if post.topic.forum.locked:
  203. flash("This forum is locked; you cannot submit new topics or posts.",
  204. "error")
  205. return redirect(url_for("forum.view_forum",
  206. forum_id=post.topic.forum.id))
  207. if post.topic.locked:
  208. flash("The topic is locked.", "error")
  209. return redirect(url_for("forum.view_forum",
  210. forum_id=post.topic.forum_id))
  211. if not can_edit_post(user=current_user, forum=post.topic.forum,
  212. post_user_id=post.user_id):
  213. flash("You do not have the permissions to edit this post", "error")
  214. return redirect(url_for('forum.view_topic', topic_id=post.topic_id))
  215. form = ReplyForm()
  216. if form.validate_on_submit():
  217. form.populate_obj(post)
  218. post.date_modified = datetime.datetime.utcnow()
  219. post.save()
  220. return redirect(url_for("forum.view_topic", topic_id=post.topic.id))
  221. else:
  222. form.content.data = post.content
  223. return render_template("forum/new_post.html", topic=post.topic, form=form)
  224. @forum.route("/post/<int:post_id>/delete")
  225. @login_required
  226. def delete_post(post_id):
  227. post = Post.query.filter_by(id=post_id).first()
  228. if not can_delete_post(user=current_user, forum=post.topic.forum,
  229. post_user_id=post.user_id):
  230. flash("You do not have the permissions to edit this post", "error")
  231. return redirect(url_for('forum.view_topic', topic_id=post.topic_id))
  232. topic_id = post.topic_id
  233. post.delete()
  234. # If the post was the first post in the topic, redirect to the forums
  235. if post.first_post:
  236. return redirect(url_for('forum.view_forum',
  237. forum_id=post.topic.forum_id))
  238. return redirect(url_for('forum.view_topic', topic_id=topic_id))
  239. @forum.route("/who_is_online")
  240. def who_is_online():
  241. if current_app.config['USE_REDIS']:
  242. online_users = get_online_users()
  243. else:
  244. online_users = User.query.filter(User.lastseen >= time_diff()).all()
  245. return render_template("forum/online_users.html",
  246. online_users=online_users)
  247. @forum.route("/memberlist")
  248. def memberlist():
  249. page = request.args.get('page', 1, type=int)
  250. users = User.query.order_by(User.id).\
  251. paginate(page, current_app.config['POSTS_PER_PAGE'], False)
  252. return render_template("forum/memberlist.html",
  253. users=users)
  254. @forum.route("/topictracker")
  255. def topictracker():
  256. page = request.args.get("page", 1, type=int)
  257. topics = current_user.tracked_topics.\
  258. outerjoin(TopicsRead,
  259. db.and_(TopicsRead.topic_id == Topic.id,
  260. TopicsRead.user_id == current_user.id)).\
  261. add_entity(TopicsRead).\
  262. order_by(Post.id.desc()).\
  263. paginate(page, current_app.config['TOPICS_PER_PAGE'], True)
  264. return render_template("forum/topictracker.html", topics=topics)
  265. @forum.route("/topictracker/<topic_id>/add")
  266. def track_topic(topic_id):
  267. topic = Topic.query.filter_by(id=topic_id).first()
  268. current_user.track_topic(topic)
  269. current_user.save()
  270. return redirect(url_for("forum.view_topic", topic_id=topic.id))
  271. @forum.route("/topictracker/<topic_id>/delete")
  272. def untrack_topic(topic_id):
  273. topic = Topic.query.filter_by(id=topic_id).first()
  274. current_user.untrack_topic(topic)
  275. current_user.save()
  276. return redirect(url_for("forum.view_topic", topic_id=topic.id))