]> git.lizzy.rs Git - cheatdb.git/blob - app/views/users.py
Add support for importing generic git releases
[cheatdb.git] / app / views / users.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 from flask_user import *
20 from flask_login import login_user, logout_user
21 from flask.ext import menu
22 from app import app
23 from app.models import *
24 from flask_wtf import FlaskForm
25 from flask_user.forms import RegisterForm
26 from wtforms import *
27 from wtforms.validators import *
28 from app.utils import rank_required, randomString, loginUser
29 from app.tasks.forumtasks import checkForumAccount
30 from app.tasks.emails import sendVerifyEmail
31 from app.tasks.phpbbparser import getProfile
32
33 # Define the User profile form
34 class UserProfileForm(FlaskForm):
35         display_name = StringField("Display name", [Optional(), Length(2, 20)])
36         email = StringField("Email", [Optional(), Email()])
37         rank = SelectField("Rank", [Optional()], choices=UserRank.choices(), coerce=UserRank.coerce, default=UserRank.NEW_MEMBER)
38         submit = SubmitField("Save")
39
40 @app.route("/users/", methods=["GET"])
41 @login_required
42 def user_list_page():
43         users = User.query.order_by(db.desc(User.rank), db.asc(User.display_name)).all()
44         return render_template("users/list.html", users=users)
45
46
47 @app.route("/users/<username>/", methods=["GET", "POST"])
48 def user_profile_page(username):
49         user = User.query.filter_by(username=username).first()
50         if not user:
51                 abort(404)
52
53         form = None
54         if user.checkPerm(current_user, Permission.CHANGE_DNAME) or \
55                         user.checkPerm(current_user, Permission.CHANGE_EMAIL) or \
56                         user.checkPerm(current_user, Permission.CHANGE_RANK):
57                 # Initialize form
58                 form = UserProfileForm(formdata=request.form, obj=user)
59
60                 # Process valid POST
61                 if request.method=="POST" and form.validate():
62                         # Copy form fields to user_profile fields
63                         if user.checkPerm(current_user, Permission.CHANGE_DNAME):
64                                 user.display_name = form["display_name"].data
65
66                         if user.checkPerm(current_user, Permission.CHANGE_RANK):
67                                 newRank = form["rank"].data
68                                 if current_user.rank.atLeast(newRank):
69                                         user.rank = form["rank"].data
70                                 else:
71                                         flash("Can't promote a user to a rank higher than yourself!", "error")
72
73                         if user.checkPerm(current_user, Permission.CHANGE_EMAIL):
74                                 newEmail = form["email"].data
75                                 if newEmail != user.email and newEmail.strip() != "":
76                                         token = randomString(32)
77
78                                         ver = UserEmailVerification()
79                                         ver.user = user
80                                         ver.token = token
81                                         ver.email = newEmail
82                                         db.session.add(ver)
83                                         db.session.commit()
84
85                                         task = sendVerifyEmail.delay(newEmail, token)
86                                         return redirect(url_for("check_task", id=task.id, r=url_for("user_profile_page", username=username)))
87
88                         # Save user_profile
89                         db.session.commit()
90
91                         # Redirect to home page
92                         return redirect(url_for("user_profile_page", username=username))
93
94         packages = user.packages.filter_by(soft_deleted=False)
95         if not current_user.is_authenticated or (user != current_user and not current_user.canAccessTodoList()):
96                 packages = packages.filter_by(approved=True)
97         packages = packages.order_by(db.asc(Package.title))
98
99         topics_to_add = None
100         if current_user == user or user.checkPerm(current_user, Permission.CHANGE_AUTHOR):
101                 topics_to_add = KrockForumTopic.query \
102                                         .filter_by(author_id=user.id) \
103                                         .filter(~ db.exists().where(Package.forums==KrockForumTopic.topic_id)) \
104                                         .order_by(db.asc(KrockForumTopic.name), db.asc(KrockForumTopic.title)) \
105                                         .all()
106
107         # Process GET or invalid POST
108         return render_template("users/user_profile_page.html",
109                         user=user, form=form, packages=packages, topics_to_add=topics_to_add)
110
111 class SetPasswordForm(FlaskForm):
112         email = StringField("Email", [Optional(), Email()])
113         password = PasswordField("New password", [InputRequired(), Length(2, 20)])
114         password2 = PasswordField("Verify password", [InputRequired(), Length(2, 20)])
115         submit = SubmitField("Save")
116
117 @app.route("/user/set-password/", methods=["GET", "POST"])
118 @login_required
119 def set_password_page():
120         if current_user.password is not None:
121                 return redirect(url_for("user.change_password"))
122
123         form = SetPasswordForm(request.form)
124         if current_user.email == None:
125                 form.email.validators = [InputRequired(), Email()]
126
127         if request.method == "POST" and form.validate():
128                 one = form.password.data
129                 two = form.password2.data
130                 if one == two:
131                         # Hash password
132                         hashed_password = user_manager.hash_password(form.password.data)
133
134                         # Change password
135                         user_manager.update_password(current_user, hashed_password)
136
137                         # Send 'password_changed' email
138                         if user_manager.enable_email and user_manager.send_password_changed_email and current_user.email:
139                                 emails.send_password_changed_email(current_user)
140
141                         # Send password_changed signal
142                         signals.user_changed_password.send(current_app._get_current_object(), user=current_user)
143
144                         # Prepare one-time system message
145                         flash('Your password has been changed successfully.', 'success')
146
147                         newEmail = form["email"].data
148                         if newEmail != current_user.email and newEmail.strip() != "":
149                                 token = randomString(32)
150
151                                 ver = UserEmailVerification()
152                                 ver.user = current_user
153                                 ver.token = token
154                                 ver.email = newEmail
155                                 db.session.add(ver)
156                                 db.session.commit()
157
158                                 task = sendVerifyEmail.delay(newEmail, token)
159                                 return redirect(url_for("check_task", id=task.id, r=url_for("user_profile_page", username=current_user.username)))
160                         else:
161                                 return redirect(url_for("user_profile_page", username=current_user.username))
162                 else:
163                         flash("Passwords do not match", "error")
164
165         return render_template("users/set_password.html", form=form, optional=request.args.get("optional"))
166
167
168 @app.route("/user/claim/", methods=["GET", "POST"])
169 def user_claim_page():
170         username = request.args.get("username")
171         if username is None:
172                 username = ""
173         else:
174                 method = request.args.get("method")
175                 user = User.query.filter_by(forums_username=username).first()
176                 if user and user.rank.atLeast(UserRank.NEW_MEMBER):
177                         flash("User has already been claimed", "error")
178                         return redirect(url_for("user_claim_page"))
179                 elif user is None and method == "github":
180                         flash("Unable to get Github username for user", "error")
181                         return redirect(url_for("user_claim_page"))
182                 elif user is None:
183                         flash("Unable to find that user", "error")
184                         return redirect(url_for("user_claim_page"))
185
186                 if user is not None and method == "github":
187                         return redirect(url_for("github_signin_page"))
188
189         token = None
190         if "forum_token" in session:
191                 token = session["forum_token"]
192         else:
193                 token = randomString(32)
194                 session["forum_token"] = token
195
196         if request.method == "POST":
197                 ctype   = request.form.get("claim_type")
198                 username = request.form.get("username")
199
200                 if username is None or len(username.strip()) < 2:
201                         flash("Invalid username", "error")
202                 elif ctype == "github":
203                         task = checkForumAccount.delay(username)
204                         return redirect(url_for("check_task", id=task.id, r=url_for("user_claim_page", username=username, method="github")))
205                 elif ctype == "forum":
206                         user = User.query.filter_by(forums_username=username).first()
207                         if user is not None and user.rank.atLeast(UserRank.NEW_MEMBER):
208                                 flash("That user has already been claimed!", "error")
209                                 return redirect(url_for("user_claim_page"))
210
211                         # Get signature
212                         sig = None
213                         try:
214                                 profile = getProfile("https://forum.minetest.net", username)
215                                 sig = profile.signature
216                         except IOError:
217                                 flash("Unable to get forum signature - does the user exist?", "error")
218                                 return redirect(url_for("user_claim_page", username=username))
219
220                         # Look for key
221                         if token in sig:
222                                 if user is None:
223                                         user = User(username)
224                                         user.forums_username = username
225                                         db.session.add(user)
226                                         db.session.commit()
227
228                                 if loginUser(user):
229                                         return redirect(url_for("set_password_page"))
230                                 else:
231                                         flash("Unable to login as user", "error")
232                                         return redirect(url_for("user_claim_page", username=username))
233
234                         else:
235                                 flash("Could not find the key in your signature!", "error")
236                                 return redirect(url_for("user_claim_page", username=username))
237                 else:
238                         flash("Unknown claim type", "error")
239
240         return render_template("users/claim.html", username=username, key=token)
241
242 @app.route("/users/verify/")
243 def verify_email_page():
244         token = request.args.get("token")
245         ver = UserEmailVerification.query.filter_by(token=token).first()
246         if ver is None:
247                 flash("Unknown verification token!", "error")
248         else:
249                 ver.user.email = ver.email
250                 db.session.delete(ver)
251                 db.session.commit()
252
253         if current_user.is_authenticated:
254                 return redirect(url_for("user_profile_page", username=current_user.username))
255         else:
256                 return redirect(url_for("home_page"))