12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241 |
- # -*- coding: utf-8 -*-
- '''
- flaskbb.forum.views
- ~~~~~~~~~~~~~~~~~~~
- This module handles the forum logic like creating and viewing
- topics and posts.
- :copyright: (c) 2014 by the FlaskBB Team.
- :license: BSD, see LICENSE for more details.
- '''
- import logging
- import math
- from flask import (Blueprint, abort, current_app, flash, redirect, request,
- url_for)
- from flask.views import MethodView
- from flask_allows import And, Permission
- from flask_babelplus import gettext as _
- from flask_login import current_user, login_required
- from pluggy import HookimplMarker
- from sqlalchemy import asc, desc
- from flaskbb.extensions import allows, db
- from flaskbb.forum.forms import (NewTopicForm, QuickreplyForm, ReplyForm,
- ReportForm, SearchPageForm, UserSearchForm)
- from flaskbb.forum.models import (Category, Forum, ForumsRead, Post, Topic,
- TopicsRead)
- from flaskbb.user.models import User
- from flaskbb.utils.helpers import (do_topic_action, format_quote,
- get_online_users, real, register_view,
- render_template, time_diff, time_utcnow,
- FlashAndRedirect)
- from flaskbb.utils.requirements import (CanAccessForum,
- CanDeletePost, CanDeleteTopic,
- CanEditPost, CanPostReply,
- CanPostTopic, Has,
- IsAtleastModeratorInForum)
- from flaskbb.utils.settings import flaskbb_config
- from .locals import current_topic, current_forum, current_category
- impl = HookimplMarker('flaskbb')
- logger = logging.getLogger(__name__)
- class ForumIndex(MethodView):
- def get(self):
- categories = Category.get_all(user=real(current_user))
- # Fetch a few stats about the forum
- user_count = User.query.count()
- topic_count = Topic.query.count()
- post_count = Post.query.count()
- newest_user = User.query.order_by(User.id.desc()).first()
- # Check if we use redis or not
- if not current_app.config['REDIS_ENABLED']:
- online_users = User.query.filter(User.lastseen >= time_diff()
- ).count()
- # Because we do not have server side sessions,
- # we cannot check if there are online guests
- online_guests = None
- else:
- online_users = len(get_online_users())
- online_guests = len(get_online_users(guest=True))
- return render_template(
- 'forum/index.html',
- categories=categories,
- user_count=user_count,
- topic_count=topic_count,
- post_count=post_count,
- newest_user=newest_user,
- online_users=online_users,
- online_guests=online_guests
- )
- class ViewCategory(MethodView):
- def get(self, category_id, slug=None):
- category, forums = Category.get_forums(
- category_id=category_id, user=real(current_user)
- )
- return render_template(
- 'forum/category.html', forums=forums, category=category
- )
- class ViewForum(MethodView):
- decorators = [allows.requires(
- CanAccessForum(),
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to access that forum"),
- level="warning",
- endpoint=lambda *a, **k: current_category.url
- )
- )]
- def get(self, forum_id, slug=None):
- page = request.args.get('page', 1, type=int)
- forum_instance, forumsread = Forum.get_forum(
- forum_id=forum_id, user=real(current_user)
- )
- if forum_instance.external:
- return redirect(forum_instance.external)
- topics = Forum.get_topics(
- forum_id=forum_instance.id,
- user=real(current_user),
- page=page,
- per_page=flaskbb_config['TOPICS_PER_PAGE']
- )
- return render_template(
- 'forum/forum.html',
- forum=forum_instance,
- topics=topics,
- forumsread=forumsread,
- )
- class ViewPost(MethodView):
- decorators = [allows.requires(
- CanAccessForum(),
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to access that topic"),
- level="warning",
- endpoint=lambda *a, **k: current_category.url
- )
- )]
- def get(self, post_id):
- '''Redirects to a post in a topic.'''
- post = Post.query.filter_by(id=post_id).first_or_404()
- post_in_topic = Post.query.filter(
- Post.topic_id == post.topic_id, Post.id <= post_id
- ).order_by(Post.id.asc()).count()
- page = int(
- math.ceil(post_in_topic / float(flaskbb_config['POSTS_PER_PAGE']))
- )
- return redirect(
- url_for(
- 'forum.view_topic',
- topic_id=post.topic.id,
- slug=post.topic.slug,
- page=page,
- _anchor='pid{}'.format(post.id)
- )
- )
- class ViewTopic(MethodView):
- decorators = [allows.requires(
- CanAccessForum(),
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to access that topic"),
- level="warning",
- endpoint=lambda *a, **k: current_category.url
- )
- )]
- def get(self, topic_id, slug=None):
- page = request.args.get('page', 1, type=int)
- # Fetch some information about the topic
- topic = Topic.get_topic(topic_id=topic_id, user=real(current_user))
- # Count the topic views
- topic.views += 1
- topic.save()
- # Update the topicsread status if the user hasn't read it
- forumsread = None
- if current_user.is_authenticated:
- forumsread = ForumsRead.query.filter_by(
- user_id=current_user.id,
- forum_id=topic.forum_id).first()
- topic.update_read(real(current_user), topic.forum, forumsread)
- # fetch the posts in the topic
- posts = Post.query.outerjoin(
- User, Post.user_id == User.id
- ).filter(
- Post.topic_id == topic.id
- ).add_entity(
- User
- ).order_by(
- Post.id.asc()
- ).paginate(page, flaskbb_config['POSTS_PER_PAGE'], False)
- # Abort if there are no posts on this page
- if len(posts.items) == 0:
- abort(404)
- return render_template(
- 'forum/topic.html',
- topic=topic,
- posts=posts,
- last_seen=time_diff(),
- form=self.form()
- )
- @allows.requires(
- CanPostReply,
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to post a reply to this topic."),
- level="warning",
- endpoint=lambda *a, **k: url_for(
- "forum.view_topic",
- topic_id=k['topic_id'],
- )
- )
- )
- def post(self, topic_id, slug=None):
- topic = Topic.get_topic(topic_id=topic_id, user=real(current_user))
- form = self.form()
- if not form:
- flash(_('Cannot post reply'), 'warning')
- return redirect('forum.view_topic', topic_id=topic_id, slug=slug)
- elif form.validate_on_submit():
- post = form.save(real(current_user), topic)
- return redirect(url_for('forum.view_post', post_id=post.id))
- else:
- for e in form.errors.get('content', []):
- flash(e, 'danger')
- return redirect(
- url_for('forum.view_topic', topic_id=topic_id, slug=slug)
- )
- def form(self):
- if Permission(CanPostReply):
- return QuickreplyForm()
- return None
- class NewTopic(MethodView):
- decorators = [
- login_required,
- allows.requires(
- CanAccessForum(), CanPostTopic,
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to post a topic here"),
- level="warning",
- endpoint=lambda *a, **k: current_forum.url
- )
- ),
- ]
- def get(self, forum_id, slug=None):
- forum_instance = Forum.query.filter_by(id=forum_id).first_or_404()
- return render_template(
- 'forum/new_topic.html', forum=forum_instance, form=self.form()
- )
- def post(self, forum_id, slug=None):
- forum_instance = Forum.query.filter_by(id=forum_id).first_or_404()
- form = self.form()
- if 'preview' in request.form and form.validate():
- return render_template(
- 'forum/new_topic.html',
- forum=forum_instance,
- form=form,
- preview=form.content.data
- )
- elif 'submit' in request.form and form.validate():
- topic = form.save(real(current_user), forum_instance)
- # redirect to the new topic
- return redirect(url_for('forum.view_topic', topic_id=topic.id))
- else:
- return render_template(
- 'forum/new_topic.html', forum=forum_instance, form=form
- )
- def form(self):
- current_app.pluggy.hook.flaskbb_form_new_topic(form=NewTopicForm)
- return NewTopicForm()
- class ManageForum(MethodView):
- decorators = [
- login_required,
- allows.requires(
- IsAtleastModeratorInForum(),
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to manage this forum"),
- level="danger",
- endpoint=lambda *a, **k: url_for(
- "forum.view_forum",
- forum_id=k["forum_id"],
- )
- )
- ),
- ]
- def get(self, forum_id, slug=None):
- forum_instance, forumsread = Forum.get_forum(
- forum_id=forum_id, user=real(current_user)
- )
- if forum_instance.external:
- return redirect(forum_instance.external)
- # remove the current forum from the select field (move).
- available_forums = Forum.query.order_by(Forum.position).all()
- available_forums.remove(forum_instance)
- page = request.args.get('page', 1, type=int)
- topics = Forum.get_topics(
- forum_id=forum_instance.id,
- user=real(current_user),
- page=page,
- per_page=flaskbb_config['TOPICS_PER_PAGE']
- )
- return render_template(
- 'forum/edit_forum.html',
- forum=forum_instance,
- topics=topics,
- available_forums=available_forums,
- forumsread=forumsread,
- )
- # TODO(anr): Clean this up. @_@
- def post(self, forum_id, slug=None):
- forum_instance, __ = Forum.get_forum(
- forum_id=forum_id, user=real(current_user)
- )
- mod_forum_url = url_for(
- 'forum.manage_forum',
- forum_id=forum_instance.id,
- slug=forum_instance.slug
- )
- ids = request.form.getlist('rowid')
- tmp_topics = Topic.query.filter(Topic.id.in_(ids)).all()
- if not len(tmp_topics) > 0:
- flash(
- _(
- 'In order to perform this action you have to select at '
- 'least one topic.'
- ), 'danger'
- )
- return redirect(mod_forum_url)
- # locking/unlocking
- if 'lock' in request.form:
- changed = do_topic_action(
- topics=tmp_topics,
- user=real(current_user),
- action='locked',
- reverse=False
- )
- flash(_('%(count)s topics locked.', count=changed), 'success')
- return redirect(mod_forum_url)
- elif 'unlock' in request.form:
- changed = do_topic_action(
- topics=tmp_topics,
- user=real(current_user),
- action='locked',
- reverse=True
- )
- flash(_('%(count)s topics unlocked.', count=changed), 'success')
- return redirect(mod_forum_url)
- # highlighting/trivializing
- elif 'highlight' in request.form:
- changed = do_topic_action(
- topics=tmp_topics,
- user=real(current_user),
- action='important',
- reverse=False
- )
- flash(_('%(count)s topics highlighted.', count=changed), 'success')
- return redirect(mod_forum_url)
- elif 'trivialize' in request.form:
- changed = do_topic_action(
- topics=tmp_topics,
- user=real(current_user),
- action='important',
- reverse=True
- )
- flash(_('%(count)s topics trivialized.', count=changed), 'success')
- return redirect(mod_forum_url)
- # deleting
- elif 'delete' in request.form:
- changed = do_topic_action(
- topics=tmp_topics,
- user=real(current_user),
- action='delete',
- reverse=False
- )
- flash(_('%(count)s topics deleted.', count=changed), 'success')
- return redirect(mod_forum_url)
- # moving
- elif 'move' in request.form:
- new_forum_id = request.form.get('forum')
- if not new_forum_id:
- flash(_('Please choose a new forum for the topics.'), 'info')
- return redirect(mod_forum_url)
- new_forum = Forum.query.filter_by(id=new_forum_id).first_or_404()
- # check the permission in the current forum and in the new forum
- if not Permission(
- And(IsAtleastModeratorInForum(forum_id=new_forum_id),
- IsAtleastModeratorInForum(forum=forum_instance))):
- flash(
- _('You do not have the permissions to move this topic.'),
- 'danger'
- )
- return redirect(mod_forum_url)
- if new_forum.move_topics_to(tmp_topics):
- flash(_('Topics moved.'), 'success')
- else:
- flash(_('Failed to move topics.'), 'danger')
- return redirect(mod_forum_url)
- # hiding/unhiding
- elif "hide" in request.form:
- changed = do_topic_action(
- topics=tmp_topics,
- user=real(current_user),
- action="hide",
- reverse=False
- )
- flash(_("%(count)s topics hidden.", count=changed), "success")
- return redirect(mod_forum_url)
- elif "unhide" in request.form:
- changed = do_topic_action(
- topics=tmp_topics,
- user=real(current_user),
- action="unhide",
- reverse=False
- )
- flash(_("%(count)s topics unhidden.", count=changed), "success")
- return redirect(mod_forum_url)
- else:
- flash(_('Unknown action requested'), 'danger')
- return redirect(mod_forum_url)
- class NewPost(MethodView):
- decorators = [
- login_required,
- allows.requires(
- CanAccessForum(), CanPostReply,
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to post a reply"),
- level="warning",
- endpoint=lambda *a, **k: url_for(
- "forum.view_topic",
- topic_id=k["topic_id"],
- )
- )
- ),
- ]
- def get(self, topic_id, slug=None, post_id=None):
- topic = Topic.query.filter_by(id=topic_id).first_or_404()
- form = self.form()
- if post_id is not None:
- post = Post.query.filter_by(id=post_id).first_or_404()
- form.content.data = format_quote(post.username, post.content)
- return render_template(
- 'forum/new_post.html', topic=topic, form=form
- )
- def post(self, topic_id, slug=None, post_id=None):
- topic = Topic.query.filter_by(id=topic_id).first_or_404()
- form = self.form()
- # check if topic exists
- if post_id is not None:
- post = Post.query.filter_by(id=post_id).first_or_404()
- if form.validate_on_submit():
- if 'preview' in request.form:
- return render_template(
- 'forum/new_post.html',
- topic=topic,
- form=form,
- preview=form.content.data
- )
- else:
- post = form.save(real(current_user), topic)
- return redirect(url_for('forum.view_post', post_id=post.id))
- return render_template('forum/new_post.html', topic=topic, form=form)
- def form(self):
- current_app.pluggy.hook.flaskbb_form_new_post(form=ReplyForm)
- return ReplyForm()
- class EditPost(MethodView):
- decorators = [
- allows.requires(
- CanEditPost,
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to edit that post"),
- level="danger",
- endpoint=lambda *a, **k: current_topic.url
- )
- ),
- login_required
- ]
- def get(self, post_id):
- post = Post.query.filter_by(id=post_id).first_or_404()
- form = self.form(obj=post)
- return render_template(
- 'forum/new_post.html', topic=post.topic, form=form, edit_mode=True
- )
- def post(self, post_id):
- post = Post.query.filter_by(id=post_id).first_or_404()
- form = self.form(obj=post)
- if form.validate_on_submit():
- if 'preview' in request.form:
- return render_template(
- 'forum/new_post.html',
- topic=post.topic,
- form=form,
- preview=form.content.data,
- edit_mode=True
- )
- else:
- form.populate_obj(post)
- post.date_modified = time_utcnow()
- post.modified_by = real(current_user).username
- post.save()
- return redirect(url_for('forum.view_post', post_id=post.id))
- return render_template(
- 'forum/new_post.html', topic=post.topic, form=form, edit_mode=True
- )
- def form(self, **kwargs):
- current_app.pluggy.hook.flaskbb_form_new_post(form=ReplyForm)
- return ReplyForm(**kwargs)
- class ReportView(MethodView):
- decorators = [login_required]
- form = ReportForm
- def get(self, post_id):
- return render_template('forum/report_post.html', form=self.form())
- def post(self, post_id):
- form = self.form()
- if form.validate_on_submit():
- post = Post.query.filter_by(id=post_id).first_or_404()
- form.save(real(current_user), post)
- flash(_('Thanks for reporting.'), 'success')
- return render_template('forum/report_post.html', form=form)
- class MemberList(MethodView):
- form = UserSearchForm
- def get(self):
- page = request.args.get('page', 1, type=int)
- sort_by = request.args.get('sort_by', 'reg_date')
- order_by = request.args.get('order_by', 'asc')
- if order_by == 'asc':
- order_func = asc
- else:
- order_func = desc
- if sort_by == 'reg_date':
- sort_obj = User.id
- elif sort_by == 'post_count':
- sort_obj = User.post_count
- else:
- sort_obj = User.username
- users = User.query.order_by(order_func(sort_obj)).paginate(
- page, flaskbb_config['USERS_PER_PAGE'], False
- )
- return render_template(
- 'forum/memberlist.html', users=users, search_form=self.form()
- )
- def post(self):
- page = request.args.get('page', 1, type=int)
- sort_by = request.args.get('sort_by', 'reg_date')
- order_by = request.args.get('order_by', 'asc')
- if order_by == 'asc':
- order_func = asc
- else:
- order_func = desc
- if sort_by == 'reg_date':
- sort_obj = User.id
- elif sort_by == 'post_count':
- sort_obj = User.post_count
- else:
- sort_obj = User.username
- form = self.form()
- if form.validate():
- users = form.get_results().paginate(
- page, flaskbb_config['USERS_PER_PAGE'], False
- )
- return render_template(
- 'forum/memberlist.html', users=users, search_form=form
- )
- users = User.query.order_by(order_func(sort_obj)).paginate(
- page, flaskbb_config['USERS_PER_PAGE'], False
- )
- return render_template(
- 'forum/memberlist.html', users=users, search_form=form
- )
- class TopicTracker(MethodView):
- decorators = [login_required]
- def get(self):
- page = request.args.get('page', 1, type=int)
- topics = real(current_user).tracked_topics.\
- outerjoin(
- TopicsRead,
- db.and_(
- TopicsRead.topic_id == Topic.id,
- TopicsRead.user_id == real(current_user).id
- )).\
- outerjoin(Post, Topic.last_post_id == Post.id).\
- outerjoin(Forum, Topic.forum_id == Forum.id).\
- outerjoin(
- ForumsRead,
- db.and_(
- ForumsRead.forum_id == Forum.id,
- ForumsRead.user_id == real(current_user).id
- )).\
- add_entity(Post).\
- add_entity(TopicsRead).\
- add_entity(ForumsRead).\
- order_by(Topic.last_updated.desc()).\
- paginate(page, flaskbb_config['TOPICS_PER_PAGE'], True)
- return render_template('forum/topictracker.html', topics=topics)
- def post(self):
- topic_ids = request.form.getlist('rowid')
- tmp_topics = Topic.query.filter(Topic.id.in_(topic_ids)).all()
- for topic in tmp_topics:
- real(current_user).untrack_topic(topic)
- real(current_user).save()
- flash(
- _('%(topic_count)s topics untracked.', topic_count=len(tmp_topics)),
- 'success'
- )
- return redirect(url_for('forum.topictracker'))
- class Search(MethodView):
- form = SearchPageForm
- def get(self):
- return render_template('forum/search_form.html', form=self.form())
- def post(self):
- form = self.form()
- if form.validate_on_submit():
- result = form.get_results()
- return render_template(
- 'forum/search_result.html', form=form, result=result
- )
- return render_template('forum/search_form.html', form=form)
- class DeleteTopic(MethodView):
- decorators = [
- login_required,
- allows.requires(
- CanDeleteTopic,
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to delete this topic"),
- level="danger",
- # TODO(anr): consider the referrer -- for now, back to topic
- endpoint=lambda *a, **k: current_topic.url
- )
- ),
- ]
- def post(self, topic_id, slug=None):
- topic = Topic.query.filter_by(id=topic_id).first_or_404()
- involved_users = User.query.filter(
- Post.topic_id == topic.id, User.id == Post.user_id
- ).all()
- topic.delete(users=involved_users)
- return redirect(url_for('forum.view_forum', forum_id=topic.forum_id))
- class LockTopic(MethodView):
- decorators = [
- login_required,
- allows.requires(
- IsAtleastModeratorInForum(),
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to lock this topic"),
- level="danger",
- # TODO(anr): consider the referrer -- for now, back to topic
- endpoint=lambda *a, **k: current_topic.url
- )
- ),
- ]
- def post(self, topic_id, slug=None):
- topic = Topic.query.filter_by(id=topic_id).first_or_404()
- topic.locked = True
- topic.save()
- return redirect(topic.url)
- class UnlockTopic(MethodView):
- decorators = [
- login_required,
- allows.requires(
- IsAtleastModeratorInForum(),
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to unlock this topic"),
- level="danger",
- # TODO(anr): consider the referrer -- for now, back to topic
- endpoint=lambda *a, **k: current_topic.url
- )
- ),
- ]
- def post(self, topic_id, slug=None):
- topic = Topic.query.filter_by(id=topic_id).first_or_404()
- topic.locked = False
- topic.save()
- return redirect(topic.url)
- class HighlightTopic(MethodView):
- decorators = [
- login_required,
- allows.requires(
- IsAtleastModeratorInForum(),
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to highlight this topic"),
- level="danger",
- # TODO(anr): consider the referrer -- for now, back to topic
- endpoint=lambda *a, **k: current_topic.url
- )
- ),
- ]
- def post(self, topic_id, slug=None):
- topic = Topic.query.filter_by(id=topic_id).first_or_404()
- topic.important = True
- topic.save()
- return redirect(topic.url)
- class TrivializeTopic(MethodView):
- decorators = [
- login_required,
- allows.requires(
- IsAtleastModeratorInForum(),
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to trivialize this topic"),
- level="danger",
- # TODO(anr): consider the referrer -- for now, back to topic
- endpoint=lambda *a, **k: current_topic.url
- )
- ),
- ]
- def post(self, topic_id=None, slug=None):
- topic = Topic.query.filter_by(id=topic_id).first_or_404()
- topic.important = False
- topic.save()
- return redirect(topic.url)
- class DeletePost(MethodView):
- decorators = [
- login_required,
- allows.requires(
- CanDeletePost,
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to delete this post"),
- level="danger",
- endpoint=lambda *a, **k: current_topic.url
- )
- ),
- ]
- def post(self, post_id):
- post = Post.query.filter_by(id=post_id).first_or_404()
- first_post = post.first_post
- topic_url = post.topic.url
- forum_url = post.topic.forum.url
- post.delete()
- # If the post was the first post in the topic, redirect to the forums
- if first_post:
- return redirect(forum_url)
- return redirect(topic_url)
- class RawPost(MethodView):
- decorators = [
- login_required,
- allows.requires(
- CanAccessForum(),
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to access that forum"),
- level="warning",
- endpoint=lambda *a, **k: current_category.url
- )
- ),
- ]
- def get(self, post_id):
- post = Post.query.filter_by(id=post_id).first_or_404()
- return format_quote(username=post.username, content=post.content)
- class MarkRead(MethodView):
- decorators = [
- login_required,
- allows.requires(
- CanAccessForum(),
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to access that forum"),
- level="warning",
- endpoint=lambda *a, **k: current_category.url
- )
- ),
- ]
- def post(self, forum_id=None, slug=None):
- # Mark a single forum as read
- if forum_id is not None:
- forum_instance = Forum.query.filter_by(id=forum_id).first_or_404()
- forumsread = ForumsRead.query.filter_by(
- user_id=real(current_user).id, forum_id=forum_instance.id
- ).first()
- TopicsRead.query.filter_by(
- user_id=real(current_user).id, forum_id=forum_instance.id
- ).delete()
- if not forumsread:
- forumsread = ForumsRead()
- forumsread.user = real(current_user)
- forumsread.forum = forum_instance
- forumsread.last_read = time_utcnow()
- forumsread.cleared = time_utcnow()
- db.session.add(forumsread)
- db.session.commit()
- flash(
- _(
- 'Forum %(forum)s marked as read.',
- forum=forum_instance.title
- ), 'success'
- )
- return redirect(forum_instance.url)
- # Mark all forums as read
- ForumsRead.query.filter_by(user_id=real(current_user).id).delete()
- TopicsRead.query.filter_by(user_id=real(current_user).id).delete()
- forums = Forum.query.all()
- forumsread_list = []
- for forum_instance in forums:
- forumsread = ForumsRead()
- forumsread.user = real(current_user)
- forumsread.forum = forum_instance
- forumsread.last_read = time_utcnow()
- forumsread.cleared = time_utcnow()
- forumsread_list.append(forumsread)
- db.session.add_all(forumsread_list)
- db.session.commit()
- flash(_('All forums marked as read.'), 'success')
- return redirect(url_for('forum.index'))
- class WhoIsOnline(MethodView):
- def get(self):
- if current_app.config['REDIS_ENABLED']:
- online_users = get_online_users()
- else:
- online_users = User.query.filter(User.lastseen >= time_diff()).all()
- return render_template(
- 'forum/online_users.html', online_users=online_users
- )
- class TrackTopic(MethodView):
- decorators = [
- login_required,
- allows.requires(
- CanAccessForum(),
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to access that forum"),
- level="warning",
- endpoint=lambda *a, **k: current_category.url
- )
- ),
- ]
- def post(self, topic_id, slug=None):
- topic = Topic.query.filter_by(id=topic_id).first_or_404()
- real(current_user).track_topic(topic)
- real(current_user).save()
- return redirect(topic.url)
- class UntrackTopic(MethodView):
- decorators = [
- login_required,
- allows.requires(
- CanAccessForum(),
- on_fail=FlashAndRedirect(
- message=_("You are not allowed to access that forum"),
- level="warning",
- endpoint=lambda *a, **k: current_category.url
- )
- ),
- ]
- def post(self, topic_id, slug=None):
- topic = Topic.query.filter_by(id=topic_id).first_or_404()
- real(current_user).untrack_topic(topic)
- real(current_user).save()
- return redirect(topic.url)
- class HideTopic(MethodView):
- decorators = [login_required]
- def post(self, topic_id, slug=None):
- topic = Topic.query.with_hidden().filter_by(id=topic_id).first_or_404()
- if not Permission(Has('makehidden'), IsAtleastModeratorInForum(
- forum=topic.forum)):
- flash(_("You do not have permission to hide this topic"), "danger")
- return redirect(topic.url)
- topic.hide(user=current_user)
- topic.save()
- if Permission(Has('viewhidden')):
- return redirect(topic.url)
- return redirect(topic.forum.url)
- class UnhideTopic(MethodView):
- decorators = [login_required]
- def post(self, topic_id, slug=None):
- topic = Topic.query.filter_by(id=topic_id).first_or_404()
- if not Permission(Has('makehidden'), IsAtleastModeratorInForum(
- forum=topic.forum)):
- flash(
- _("You do not have permission to unhide this topic"), "danger"
- )
- return redirect(topic.url)
- topic.unhide()
- topic.save()
- return redirect(topic.url)
- class HidePost(MethodView):
- decorators = [login_required]
- def post(self, post_id):
- post = Post.query.filter(Post.id == post_id).first_or_404()
- if not Permission(Has('makehidden'), IsAtleastModeratorInForum(
- forum=post.topic.forum)):
- flash(_("You do not have permission to hide this post"), "danger")
- return redirect(post.topic.url)
- if post.hidden:
- flash(_("Post is already hidden"), "warning")
- return redirect(post.topic.url)
- first_post = post.first_post
- post.hide(current_user)
- post.save()
- if first_post:
- flash(_("Topic hidden"), "success")
- else:
- flash(_("Post hidden"), "success")
- if post.first_post and not Permission(Has("viewhidden")):
- return redirect(post.topic.forum.url)
- return redirect(post.topic.url)
- class UnhidePost(MethodView):
- decorators = [login_required]
- def post(self, post_id):
- post = Post.query.filter(Post.id == post_id).first_or_404()
- if not Permission(Has('makehidden'), IsAtleastModeratorInForum(
- forum=post.topic.forum)):
- flash(_("You do not have permission to unhide this post"), "danger")
- return redirect(post.topic.url)
- if not post.hidden:
- flash(_("Post is already unhidden"), "warning")
- redirect(post.topic.url)
- post.unhide()
- post.save()
- flash(_("Post unhidden"), "success")
- return redirect(post.topic.url)
- @impl(tryfirst=True)
- def flaskbb_load_blueprints(app):
- forum = Blueprint("forum", __name__)
- register_view(
- forum,
- routes=[
- '/category/<int:category_id>', '/category/<int:category_id>-<slug>'
- ],
- view_func=ViewCategory.as_view('view_category')
- )
- register_view(
- forum,
- routes=[
- '/forum/<int:forum_id>/edit', '/forum/<int:forum_id>-<slug>/edit'
- ],
- view_func=ManageForum.as_view('manage_forum')
- )
- register_view(
- forum,
- routes=['/forum/<int:forum_id>', '/forum/<int:forum_id>-<slug>'],
- view_func=ViewForum.as_view('view_forum')
- )
- register_view(
- forum,
- routes=['/<int:forum_id>/markread', '/<int:forum_id>-<slug>/markread'],
- view_func=MarkRead.as_view('markread')
- )
- register_view(
- forum,
- routes=[
- '/<int:forum_id>/topic/new', '/<int:forum_id>-<slug>/topic/new'
- ],
- view_func=NewTopic.as_view('new_topic')
- )
- register_view(
- forum,
- routes=['/memberlist'],
- view_func=MemberList.as_view('memberlist')
- )
- register_view(
- forum,
- routes=['/post/<int:post_id>/delete'],
- view_func=DeletePost.as_view('delete_post')
- )
- register_view(
- forum,
- routes=['/post/<int:post_id>/edit'],
- view_func=EditPost.as_view('edit_post')
- )
- register_view(
- forum,
- routes=['/post/<int:post_id>/raw'],
- view_func=RawPost.as_view('raw_post')
- )
- register_view(
- forum,
- routes=['/post/<int:post_id>/report'],
- view_func=ReportView.as_view('report_post')
- )
- register_view(
- forum,
- routes=['/post/<int:post_id>'],
- view_func=ViewPost.as_view('view_post')
- )
- register_view(forum, routes=['/search'], view_func=Search.as_view('search'))
- register_view(
- forum,
- routes=[
- '/topic/<int:topic_id>/delete',
- '/topic/<int:topic_id>-<slug>/delete'
- ],
- view_func=DeleteTopic.as_view('delete_topic')
- )
- register_view(
- forum,
- routes=[
- '/topic/<int:topic_id>/highlight',
- '/topic/<int:topic_id>-<slug>/highlight'
- ],
- view_func=HighlightTopic.as_view('highlight_topic')
- )
- register_view(
- forum,
- routes=[
- '/topic/<int:topic_id>/lock', '/topic/<int:topic_id>-<slug>/lock'
- ],
- view_func=LockTopic.as_view('lock_topic')
- )
- register_view(
- forum,
- routes=[
- '/topic/<int:topic_id>/post/<int:post_id>/reply',
- '/topic/<int:topic_id>-<slug>/post/<int:post_id>/reply'
- ],
- view_func=NewPost.as_view('reply_post')
- )
- register_view(
- forum,
- routes=[
- '/topic/<int:topic_id>/post/new',
- '/topic/<int:topic_id>-<slug>/post/new'
- ],
- view_func=NewPost.as_view('new_post')
- )
- register_view(
- forum,
- routes=['/topic/<int:topic_id>', '/topic/<int:topic_id>-<slug>'],
- view_func=ViewTopic.as_view('view_topic')
- )
- register_view(
- forum,
- routes=[
- '/topic/<int:topic_id>/trivialize',
- '/topic/<int:topic_id>-<slug>/trivialize'
- ],
- view_func=TrivializeTopic.as_view('trivialize_topic')
- )
- register_view(
- forum,
- routes=[
- '/topic/<int:topic_id>/unlock',
- '/topic/<int:topic_id>-<slug>/unlock'
- ],
- view_func=UnlockTopic.as_view('unlock_topic')
- )
- register_view(
- forum,
- routes=[
- '/topictracker/<int:topic_id>/add',
- '/topictracker/<int:topic_id>-<slug>/add'
- ],
- view_func=TrackTopic.as_view('track_topic')
- )
- register_view(
- forum,
- routes=[
- '/topictracker/<int:topic_id>/delete',
- '/topictracker/<int:topic_id>-<slug>/delete'
- ],
- view_func=UntrackTopic.as_view('untrack_topic')
- )
- register_view(
- forum,
- routes=['/topictracker'],
- view_func=TopicTracker.as_view('topictracker')
- )
- register_view(forum, routes=['/'], view_func=ForumIndex.as_view('index'))
- register_view(
- forum,
- routes=['/who-is-online'],
- view_func=WhoIsOnline.as_view('who_is_online')
- )
- register_view(
- forum,
- routes=[
- "/topic/<int:topic_id>/hide", "/topic/<int:topic_id>-<slug>/hide"
- ],
- view_func=HideTopic.as_view('hide_topic')
- )
- register_view(
- forum,
- routes=[
- "/topic/<int:topic_id>/unhide",
- "/topic/<int:topic_id>-<slug>/unhide"
- ],
- view_func=UnhideTopic.as_view('unhide_topic')
- )
- register_view(
- forum,
- routes=["/post/<int:post_id>/hide"],
- view_func=HidePost.as_view('hide_post')
- )
- register_view(
- forum,
- routes=["/post/<int:post_id>/unhide"],
- view_func=UnhidePost.as_view('unhide_post')
- )
- app.register_blueprint(forum, url_prefix=app.config["FORUM_URL_PREFIX"])
|