]> git.lizzy.rs Git - cheatdb.git/blob - app/blueprints/threads/__init__.py
09b5eb78fab4ad05e92575aad929f5f7ccbca85a
[cheatdb.git] / app / blueprints / threads / __init__.py
1 # Content DB
2 # Copyright (C) 2018  rubenwardy
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17
18 from flask import *
19
20 bp = Blueprint("threads", __name__)
21
22 from flask_user import *
23 from app.models import *
24 from app.utils import addNotification, clearNotifications
25
26 import datetime
27
28 from flask_wtf import FlaskForm
29 from wtforms import *
30 from wtforms.validators import *
31 from app.utils import get_int_or_abort
32
33 @bp.route("/threads/")
34 def list_all():
35         query = Thread.query
36         if not Permission.SEE_THREAD.check(current_user):
37                 query = query.filter_by(private=False)
38
39         pid = request.args.get("pid")
40         if pid:
41                 pid = get_int_or_abort(pid)
42                 query = query.filter_by(package_id=pid)
43
44         return render_template("threads/list.html", threads=query.all())
45
46
47 @bp.route("/threads/<int:id>/subscribe/", methods=["POST"])
48 @login_required
49 def subscribe(id):
50         thread = Thread.query.get(id)
51         if thread is None or not thread.checkPerm(current_user, Permission.SEE_THREAD):
52                 abort(404)
53
54         if current_user in thread.watchers:
55                 flash("Already subscribed!", "success")
56         else:
57                 flash("Subscribed to thread", "success")
58                 thread.watchers.append(current_user)
59                 db.session.commit()
60
61         return redirect(url_for("threads.view", id=id))
62
63
64 @bp.route("/threads/<int:id>/unsubscribe/", methods=["POST"])
65 @login_required
66 def unsubscribe(id):
67         thread = Thread.query.get(id)
68         if thread is None or not thread.checkPerm(current_user, Permission.SEE_THREAD):
69                 abort(404)
70
71         if current_user in thread.watchers:
72                 flash("Unsubscribed!", "success")
73                 thread.watchers.remove(current_user)
74                 db.session.commit()
75         else:
76                 flash("Not subscribed to thread", "success")
77
78         return redirect(url_for("threads.view", id=id))
79
80
81 @bp.route("/threads/<int:id>/", methods=["GET", "POST"])
82 def view(id):
83         clearNotifications(url_for("threads.view", id=id))
84
85         thread = Thread.query.get(id)
86         if thread is None or not thread.checkPerm(current_user, Permission.SEE_THREAD):
87                 abort(404)
88
89         if current_user.is_authenticated and request.method == "POST":
90                 comment = request.form["comment"]
91
92                 if not current_user.canCommentRL():
93                         flash("Please wait before commenting again", "danger")
94                         if package:
95                                 return redirect(package.getDetailsURL())
96                         else:
97                                 return redirect(url_for("homepage.home"))
98
99                 if len(comment) <= 500 and len(comment) > 3:
100                         reply = ThreadReply()
101                         reply.author = current_user
102                         reply.comment = comment
103                         db.session.add(reply)
104
105                         thread.replies.append(reply)
106                         if not current_user in thread.watchers:
107                                 thread.watchers.append(current_user)
108
109                         msg = None
110                         if thread.package is None:
111                                 msg = "New comment on '{}'".format(thread.title)
112                         else:
113                                 msg = "New comment on '{}' on package {}".format(thread.title, thread.package.title)
114
115
116                         addNotification(thread.watchers, current_user, msg, url_for("threads.view", id=thread.id))
117                         db.session.commit()
118
119                         return redirect(url_for("threads.view", id=id))
120
121                 else:
122                         flash("Comment needs to be between 3 and 500 characters.")
123
124         return render_template("threads/view.html", thread=thread)
125
126
127 class ThreadForm(FlaskForm):
128         title   = StringField("Title", [InputRequired(), Length(3,100)])
129         comment = TextAreaField("Comment", [InputRequired(), Length(10, 500)])
130         private = BooleanField("Private")
131         submit  = SubmitField("Open Thread")
132
133 @bp.route("/threads/new/", methods=["GET", "POST"])
134 @login_required
135 def new():
136         form = ThreadForm(formdata=request.form)
137
138         package = None
139         if "pid" in request.args:
140                 package = Package.query.get(int(request.args.get("pid")))
141                 if package is None:
142                         flash("Unable to find that package!", "danger")
143
144         # Don't allow making orphan threads on approved packages for now
145         if package is None:
146                 abort(403)
147
148         def_is_private   = request.args.get("private") or False
149         if package is None:
150                 def_is_private = True
151         allow_change     = package and package.approved
152         is_review_thread = package and not package.approved
153
154         # Check that user can make the thread
155         if not package.checkPerm(current_user, Permission.CREATE_THREAD):
156                 flash("Unable to create thread!", "danger")
157                 return redirect(url_for("homepage.home"))
158
159         # Only allow creating one thread when not approved
160         elif is_review_thread and package.review_thread is not None:
161                 flash("A review thread already exists!", "danger")
162                 return redirect(url_for("threads.view", id=package.review_thread.id))
163
164         elif not current_user.canOpenThreadRL():
165                 flash("Please wait before opening another thread", "danger")
166
167                 if package:
168                         return redirect(package.getDetailsURL())
169                 else:
170                         return redirect(url_for("homepage.home"))
171
172         # Set default values
173         elif request.method == "GET":
174                 form.private.data = def_is_private
175                 form.title.data   = request.args.get("title") or ""
176
177         # Validate and submit
178         elif request.method == "POST" and form.validate():
179                 thread = Thread()
180                 thread.author  = current_user
181                 thread.title   = form.title.data
182                 thread.private = form.private.data if allow_change else def_is_private
183                 thread.package = package
184                 db.session.add(thread)
185
186                 thread.watchers.append(current_user)
187                 if package is not None and package.author != current_user:
188                         thread.watchers.append(package.author)
189
190                 reply = ThreadReply()
191                 reply.thread  = thread
192                 reply.author  = current_user
193                 reply.comment = form.comment.data
194                 db.session.add(reply)
195
196                 thread.replies.append(reply)
197
198                 db.session.commit()
199
200                 if is_review_thread:
201                         package.review_thread = thread
202
203                 notif_msg = None
204                 if package is not None:
205                         notif_msg = "New thread '{}' on package {}".format(thread.title, package.title)
206                         addNotification(package.maintainers, current_user, notif_msg, url_for("threads.view", id=thread.id))
207                 else:
208                         notif_msg = "New thread '{}'".format(thread.title)
209
210                 editors = User.query.filter(User.rank >= UserRank.EDITOR).all()
211                 addNotification(editors, current_user, notif_msg, url_for("threads.view", id=thread.id))
212
213                 db.session.commit()
214
215                 return redirect(url_for("threads.view", id=thread.id))
216
217
218         return render_template("threads/new.html", form=form, allow_private_change=allow_change, package=package)