contentdb/app/blueprints/threads/__init__.py

219 lines
6.4 KiB
Python
Raw Normal View History

2018-06-11 23:49:25 +02:00
# Content DB
# Copyright (C) 2018 rubenwardy
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from flask import *
bp = Blueprint("threads", __name__)
2018-06-11 23:49:25 +02:00
from flask_user import *
from app.models import *
from app.utils import addNotification, clearNotifications
2018-06-11 23:49:25 +02:00
import datetime
2018-06-11 23:49:25 +02:00
from flask_wtf import FlaskForm
from wtforms import *
from wtforms.validators import *
2020-01-21 23:40:51 +01:00
from app.utils import get_int_or_abort
2018-06-11 23:49:25 +02:00
@bp.route("/threads/")
def list_all():
2018-07-13 22:28:08 +02:00
query = Thread.query
if not Permission.SEE_THREAD.check(current_user):
query = query.filter_by(private=False)
2020-01-21 23:40:51 +01:00
pid = request.args.get("pid")
if pid:
pid = get_int_or_abort(pid)
query = query.filter_by(package_id=pid)
2018-07-13 22:28:08 +02:00
return render_template("threads/list.html", threads=query.all())
2018-06-11 23:49:25 +02:00
2018-07-28 16:30:59 +02:00
@bp.route("/threads/<int:id>/subscribe/", methods=["POST"])
2018-07-28 16:30:59 +02:00
@login_required
def subscribe(id):
2018-07-28 16:30:59 +02:00
thread = Thread.query.get(id)
if thread is None or not thread.checkPerm(current_user, Permission.SEE_THREAD):
abort(404)
if current_user in thread.watchers:
flash("Already subscribed!", "success")
else:
flash("Subscribed to thread", "success")
thread.watchers.append(current_user)
db.session.commit()
return redirect(url_for("threads.view", id=id))
2018-07-28 16:30:59 +02:00
@bp.route("/threads/<int:id>/unsubscribe/", methods=["POST"])
2018-07-28 16:30:59 +02:00
@login_required
def unsubscribe(id):
2018-07-28 16:30:59 +02:00
thread = Thread.query.get(id)
if thread is None or not thread.checkPerm(current_user, Permission.SEE_THREAD):
abort(404)
if current_user in thread.watchers:
flash("Unsubscribed!", "success")
thread.watchers.remove(current_user)
db.session.commit()
else:
flash("Not subscribed to thread", "success")
return redirect(url_for("threads.view", id=id))
2018-07-28 16:30:59 +02:00
@bp.route("/threads/<int:id>/", methods=["GET", "POST"])
def view(id):
clearNotifications(url_for("threads.view", id=id))
2018-06-11 23:49:25 +02:00
thread = Thread.query.get(id)
if thread is None or not thread.checkPerm(current_user, Permission.SEE_THREAD):
abort(404)
if current_user.is_authenticated and request.method == "POST":
comment = request.form["comment"]
if not current_user.canCommentRL():
flash("Please wait before commenting again", "danger")
if package:
return redirect(package.getDetailsURL())
else:
2019-11-21 20:38:26 +01:00
return redirect(url_for("homepage.home"))
2018-06-11 23:49:25 +02:00
if len(comment) <= 500 and len(comment) > 3:
reply = ThreadReply()
reply.author = current_user
reply.comment = comment
db.session.add(reply)
thread.replies.append(reply)
2018-06-12 00:38:03 +02:00
if not current_user in thread.watchers:
thread.watchers.append(current_user)
msg = None
if thread.package is None:
msg = "New comment on '{}'".format(thread.title)
else:
msg = "New comment on '{}' on package {}".format(thread.title, thread.package.title)
addNotification(thread.watchers, current_user, msg, url_for("threads.view", id=thread.id))
2018-06-11 23:49:25 +02:00
db.session.commit()
return redirect(url_for("threads.view", id=id))
2018-06-11 23:49:25 +02:00
else:
flash("Comment needs to be between 3 and 500 characters.")
return render_template("threads/view.html", thread=thread)
class ThreadForm(FlaskForm):
title = StringField("Title", [InputRequired(), Length(3,100)])
comment = TextAreaField("Comment", [InputRequired(), Length(10, 500)])
private = BooleanField("Private")
submit = SubmitField("Open Thread")
@bp.route("/threads/new/", methods=["GET", "POST"])
2018-06-11 23:49:25 +02:00
@login_required
def new():
2018-06-11 23:49:25 +02:00
form = ThreadForm(formdata=request.form)
package = None
if "pid" in request.args:
package = Package.query.get(int(request.args.get("pid")))
if package is None:
2020-01-24 19:15:09 +01:00
flash("Unable to find that package!", "danger")
2018-06-11 23:49:25 +02:00
# Don't allow making orphan threads on approved packages for now
2018-07-28 16:19:30 +02:00
if package is None:
2018-06-11 23:49:25 +02:00
abort(403)
def_is_private = request.args.get("private") or False
2019-11-12 23:39:17 +01:00
if package is None:
2018-06-11 23:49:25 +02:00
def_is_private = True
allow_change = package and package.approved
is_review_thread = package and not package.approved
2018-06-11 23:49:25 +02:00
# Check that user can make the thread
2018-07-28 16:19:30 +02:00
if not package.checkPerm(current_user, Permission.CREATE_THREAD):
2020-01-24 19:15:09 +01:00
flash("Unable to create thread!", "danger")
2019-11-21 20:38:26 +01:00
return redirect(url_for("homepage.home"))
2018-06-11 23:49:25 +02:00
# Only allow creating one thread when not approved
elif is_review_thread and package.review_thread is not None:
2020-01-24 19:15:09 +01:00
flash("A review thread already exists!", "danger")
return redirect(url_for("threads.view", id=package.review_thread.id))
elif not current_user.canOpenThreadRL():
flash("Please wait before opening another thread", "danger")
if package:
return redirect(package.getDetailsURL())
else:
2019-11-21 20:38:26 +01:00
return redirect(url_for("homepage.home"))
2018-06-11 23:49:25 +02:00
# Set default values
elif request.method == "GET":
form.private.data = def_is_private
form.title.data = request.args.get("title") or ""
# Validate and submit
elif request.method == "POST" and form.validate():
thread = Thread()
thread.author = current_user
thread.title = form.title.data
thread.private = form.private.data if allow_change else def_is_private
thread.package = package
db.session.add(thread)
2018-06-12 00:38:03 +02:00
thread.watchers.append(current_user)
if package is not None and package.author != current_user:
thread.watchers.append(package.author)
2018-06-11 23:49:25 +02:00
reply = ThreadReply()
reply.thread = thread
reply.author = current_user
reply.comment = form.comment.data
db.session.add(reply)
thread.replies.append(reply)
db.session.commit()
if is_review_thread:
package.review_thread = thread
notif_msg = None
2018-06-11 23:49:25 +02:00
if package is not None:
notif_msg = "New thread '{}' on package {}".format(thread.title, package.title)
addNotification(package.maintainers, current_user, notif_msg, url_for("threads.view", id=thread.id))
else:
notif_msg = "New thread '{}'".format(thread.title)
editors = User.query.filter(User.rank >= UserRank.EDITOR).all()
addNotification(editors, current_user, notif_msg, url_for("threads.view", id=thread.id))
2018-06-11 23:49:25 +02:00
db.session.commit()
return redirect(url_for("threads.view", id=thread.id))
2018-06-11 23:49:25 +02:00
2019-01-28 20:41:24 +01:00
return render_template("threads/new.html", form=form, allow_private_change=allow_change, package=package)