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