108 lines
3.7 KiB
Python
108 lines
3.7 KiB
Python
from flask_login import current_user
|
||
from flask import request, redirect, url_for, abort, flash
|
||
|
||
from app import app, db
|
||
from config import V5Config
|
||
from app.utils.render import render
|
||
from app.utils.glados import say, BOLD
|
||
from app.forms.forum import TopicCreationForm, AnonymousTopicCreationForm
|
||
from app.models.forum import Forum
|
||
from app.models.topic import Topic
|
||
from app.models.thread import Thread
|
||
from app.models.comment import Comment
|
||
from app.models.user import Guest
|
||
from app.models.attachment import Attachment
|
||
|
||
|
||
@app.route('/forum/')
|
||
def forum_index():
|
||
return render('/forum/index.html')
|
||
|
||
@app.route('/forum/<forum:f>/', methods=['GET', 'POST'])
|
||
@app.route('/forum/<forum:f>/p/<int:page>', methods=['GET', 'POST'])
|
||
def forum_page(f, page=1):
|
||
if not f.is_default_accessible() and not (
|
||
current_user.is_authenticated and current_user.can_access_forum(f)):
|
||
abort(403)
|
||
|
||
if current_user.is_authenticated:
|
||
form = TopicCreationForm()
|
||
else:
|
||
form = AnonymousTopicCreationForm()
|
||
|
||
if form.validate_on_submit() and (
|
||
(V5Config.ENABLE_GUEST_POST and f.is_default_postable()) or \
|
||
(current_user.is_authenticated and current_user.can_post_in_forum(f))):
|
||
|
||
# Manage author
|
||
if current_user.is_authenticated:
|
||
author = current_user
|
||
else:
|
||
author = Guest(form.pseudo.data)
|
||
db.session.add(author)
|
||
|
||
# First create the thread, then the comment, then the topic
|
||
th = Thread()
|
||
db.session.add(th)
|
||
db.session.commit()
|
||
|
||
c = Comment(author, form.message.data, th)
|
||
db.session.add(c)
|
||
db.session.commit()
|
||
|
||
th.set_top_comment(c)
|
||
db.session.merge(th)
|
||
|
||
t = Topic(f, author, form.title.data, th)
|
||
t.summary = form.summary.data
|
||
db.session.add(t)
|
||
db.session.commit()
|
||
|
||
# Manage files
|
||
attachments = []
|
||
for file in form.attachments.data:
|
||
if file.filename != "":
|
||
a = Attachment(file, c)
|
||
attachments.append((a, file))
|
||
db.session.add(a)
|
||
db.session.commit()
|
||
for a, file in attachments:
|
||
a.set_file(file)
|
||
|
||
# If there's a thumbnail, set it
|
||
if form.thumbnail.data:
|
||
t.thumbnail = c.attachments[int(form.thumbnail.data)-1]
|
||
|
||
# Update member's xp and trophies
|
||
if current_user.is_authenticated:
|
||
current_user.add_xp(2) # 2 points for a topic
|
||
current_user.update_trophies('new-post')
|
||
|
||
flash('Le sujet a bien été créé', 'ok')
|
||
app.v5logger.info(f"<{t.author.name}> has created the topic #{t.id}")
|
||
if f.is_default_accessible():
|
||
say(f"Nouveau topic de {author.name} : {BOLD}{t.title}{BOLD}")
|
||
say(url_for('forum_topic', f=f, page=(t, 1), _external=True))
|
||
|
||
return redirect(url_for('forum_topic', f=f, page=(t,1)))
|
||
|
||
# Paginate topic pages
|
||
# TODO: order by last comment date
|
||
topics = f.topics.order_by(Topic.date_created.desc()).paginate(
|
||
page, Forum.TOPICS_PER_PAGE, True)
|
||
|
||
# Count comments; this direct request avoids performing one request for
|
||
# each topic.thread.comments.count() in the view, which the database
|
||
# doesn't really appreciate performance-wise.
|
||
selection = " OR ".join(f"thread_id={t.thread.id}" for t in topics.items)
|
||
selection = "WHERE " + selection if selection else ""
|
||
|
||
comment_counts = db.session.execute(f"""
|
||
SELECT thread_id, COUNT(*) FROM comment {selection}
|
||
GROUP BY thread_id
|
||
""")
|
||
comment_counts = dict(list(comment_counts))
|
||
|
||
return render('/forum/forum.html', f=f, topics=topics, form=form,
|
||
comment_counts=comment_counts)
|