-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathviews.py
More file actions
551 lines (509 loc) · 20.2 KB
/
views.py
File metadata and controls
551 lines (509 loc) · 20.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
from app import *
from utils import *
import os
from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory, abort, jsonify
from mylib.cipher import encode, decode
from mylib.mail import send_email_to_somebody
from constants import *
from challenges import Entry
from pprint import pprint
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin, LoginManager, login_user, login_required, logout_user
import json
try:
verbose = read('args.txt')['verbose']
except KeyError:
verbose = False
# __ _ _ _ __ __
# / _|| | __ _ ___| | __ ___| |_ _ _ / _|/ _|
# | |_ | |/ _` / __| |/ / / __| __| | | | |_| |_
# | _|| | (_| \__ \ < \__ \ |_| |_| | _| _|
# |_| |_|\__,_|___/_|\_\ |___/\__|\__,_|_| |_|
@app.route('/favicon.ico')
def favicon():
return send_from_directory(os.path.join(app.root_path, 'static'),
'favicon.ico', mimetype='image/vnd.microsoft.icon')
@app.errorhandler(404)
def page_not_found(e):
# note that we set the 404 status explicitly
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_error(error):
return "500 error"+str(error)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
# _ _
# _ _ _ __ __ _ _ _| |_| |__
# | | | | '_ \ / _` | | | | __| '_ \
# | |_| | | | | (_| | |_| | |_| | | |
# \__,_|_| |_|\__,_|\__,_|\__|_| |_|
@app.route('/')
def landing_page():
variables = read('vars.txt')
for key, _ in variables.items():
variables[key] = None
variables['logged_in'] = False # everything but this should be set to False
write('vars.txt',variables)
return render_template('unauth/landing_page.html') # kwargs are used for html
@app.route('/signup', methods=['GET', 'POST'])
def signup():
SECURITY_QUESTIONS = load_security_questions()
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
if request.method == 'POST':
users = User.query.all()
variables = read('vars.txt')
first_name = request.form.get('first_name')
gender = request.form.get('gender')
if first_name:
# signup1
first_name = request.form.get('first_name')
last_name = request.form.get('last_name')
if limit_input_size(name=first_name, max_size=20):
return redirect('/signup')
if limit_input_size(name=last_name, max_size=20):
return redirect('/signup')
# yr = request.form.get('year')
# month = request.form.get('month')
# day = request.form.get('day')
birthday_str = request.form.get( 'birthday' )
try:
birthday = datetime.strptime(birthday_str, '%Y-%m-%d')
except ValueError:
flash('Please reenter your birthday in the format \'yyyy-mm-dd\'')
return render_template('unauth/signup.html',first_name=first_name, last_name=last_name, gender=gender)
if birthday.year > datetime.now().year - 3:
flash('Check the year again on your birthday')
return render_template('unauth/signup.html',first_name=first_name, last_name=last_name, gender=gender)
# age = datetime.today().year - birthday.year
# user.birthday = birthday
signup1 = {
'first_name':to_name_case(first_name),
'last_name':to_name_case(last_name),
'gender':gender,
'birthday':birthday
}
users_lst = list(users)[:-1] # everything but last one
for user in users_lst:
if user.first_name == to_name_case(first_name) \
and user.last_name == to_name_case(last_name):
flash('You have already registered for an account')
return render_template("unauth/signup.html", months=months)
debug('date: ',birthday.date)
variables['half_user'] = signup1
write('vars.txt',variables)
return render_template('unauth/signup2.html', security_questions=SECURITY_QUESTIONS)
else:
debug('signup part 2')
# switching over to signup2 template
username = request.form.get('username')
password = request.form.get('password')
if limit_input_size(name=username, max_size=20, item="username"):
return render_template('unauth/signup2.html', security_questions=SECURITY_QUESTIONS)
if limit_input_size(name=password, max_size=40, item="password"):
return render_template('unauth/signup2.html', security_questions=SECURITY_QUESTIONS)
confirm_password = request.form.get('confirm_password')
security_question = request.form.get('security_question')
answer = request.form.get('answer')
if limit_input_size(name=answer, max_size=50, item="answer"):
debug(f'username is {username}')
return render_template('unauth/signup2.html', username=username, password=password, confirm_password=confirm_password, security_questions=SECURITY_QUESTIONS, security_question=security_question)
security = {'question':security_question,'answer':encode(answer)}
users_lst = list(users)[:-1] # all but current one which is only partly signed up.
for user in users_lst:
debug(f'{user}\nusername: {user.username} \nshould be true:{user.username==username}')
if user.username == username:
flash('That username is already taken')
return render_template("unauth/signup2.html", password=password, confirm_password=confirm_password, security_questions=SECURITY_QUESTIONS, security_question=security_question, answer=answer)
variables = read('vars.txt')
v = variables['half_user']
max_uid = 0
for u in users:
if max_uid < u.id:
max_uid = u.id
id = max_uid + 1
debug('user id is ',id)
birthday = v['birthday']
debug('birthday is ',birthday)
debug()
age = datetime.today().year - birthday.year
print("\n/////////////\n New user is: ", username, "\n User.age is: ", age, "\n////////////////\n")
user = User(id=id,
first_name=v['first_name'],
last_name=v['last_name'],
age=age,
birthday=birthday, #(db.Datetime)
gender=v['gender'],
username=username,
password=encode(password),
security_question_id=security['question'],
security_question_ans=security['answer'])
debug('user: ',user)
variables['half_user'] = None
write('vars.txt', variables)
db.session.add(user)
db.session.commit()
user = User.query.get(id)
if user is not None:
login_user(user)
return redirect('/'+username+'/')
return render_template('unauth/signup.html', months=months)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == "POST":
username = request.form.get('username')
entered_password = request.form.get('password')
user = User.query.filter_by(username=username).first()
if user is None:
flash('Invalid Username')
return render_template('unauth/login.html')
password = decode(user.password)
first_name = user.first_name
if entered_password == password:
login_user(user)
debug('you are logged in')
return redirect('/'+ username)
if entered_password != password and entered_password:
flash('Incorrect Password')
return render_template('unauth/login.html', username=username)
return render_template('unauth/login.html')
@app.route('/leaderboard', methods=['GET','POST'])
def leaderboard():
all_users = User.query.all()
if request.method == "POST":
selected_challenge = request.form.get('challenge')
checked = request.form.get('bracketswitch')
selected_challenge_type = get_challenge_type(selected_challenge)
data = []
for user in all_users:
user_challenges = json_to_objects(user.challenges)
if selected_challenge in user_challenges.keys():
entry = get_best(user_challenges[selected_challenge], selected_challenge_type)
data.append(
[user.get_profile_pic(),
get_full_name(user.id),
entry.score,
entry.comment,
user.id]
)
# `data` is a list containing lists that have †he same five things
'''
[
placement (1st 2nd 3rd),
profile pic,
full name of user,
user's profile picture,
score of challenge,
comment about challenge,
user id
]
'''
if checked:
brackets = get_brackets(data, selected_challenge_type)
print('BRACKETS ARE:', brackets)
return render_template('unauth/leaderboard_brackets.html', tables=brackets, header=selected_challenge, \
challenge_type=to_name_case(selected_challenge_type), \
brackets=brackets, bracket_names=BRACKETS)
else:
sorted_data = sort_data(data, selected_challenge_type)
debug('no brackets')
return render_template('unauth/leaderboard_no_brackets.html', data=sorted_data, header=selected_challenge, \
challenge_type=to_name_case(selected_challenge_type), \
checked=repr(checked))
return render_template('unauth/leaderboard_no_brackets.html',challenge_dict=load_challenge_dict(),header="Leaderboard")
# _ _ ___ ___ _ __
# | | | / __|/ _ \ '__|
# | |_| \__ \ __/ |
# \__,_|___/\___|_|
@app.route('/<username>/')
@login_required
def home(username):
user = User.query.filter_by(username=username).first()
if user is None:
abort(404)
name = user.first_name
return render_template('user/home.html', username=username, user=user)
@app.route('/forgot-password', methods=['GET','POST'])
def forgot_password():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
if username: # if there is no username in the form then they are on the next step. Ask them for security question
# username step
variables = read('vars.txt')
variables['forgot_username'] = username
write('vars.txt',variables)
user = User.query.filter_by(username=username).first()
if user is None:
flash('That username does not exist')
return redirect('/forgot-password')
question = user.security_question_id
return render_template('unauth/forgot_password.html', username=username, security_question=question)
if not username and not password:
# security question step
variables = read('vars.txt')
username = variables['forgot_username']
user = User.query.filter_by(username=username).first()
assert user is not None, f'could not find user with username {username}'
entered_answer = request.form.get('answer')
actual_answer = decode(user.security_question_ans)
if entered_answer.lower() == actual_answer.lower(): # case insensitive
debug('answers match!')
return render_template('unauth/forgot_password.html',success=True)
else:
question = user.security_question_id
debug('answers do not match')
debug('question is ',question)
flash('Incorrect Answer')
return render_template('unauth/forgot_password.html', username=username, security_question=question)
if password:
if limit_input_size(name=password, max_size=40, item="password"):
return redirect('/forgot-password')
# password step
variables = read('vars.txt')
username = variables['forgot_username']
debug('new password is ',password)
user = User.query.filter_by(username=username).first()
user.password = encode(password)
db.session.add(user)
db.session.commit()
variables['forgot_username'] = None
write('vars.txt',variables)
return redirect('/'+username+'/')
else:
debug('something went wrong')
return render_template('unauth/forgot_password.html')
@app.route('/<username>/logout')
@login_required
def logout(username):
logout_user()
return redirect('/')
# ____ ____ ___ _____ ____ ____ ___
# ( _ \( ___)/ __)( _ )( _ \( _ \ / __)
# ) / )__)( (__ )(_)( ) / )(_) )\__ \
# (_)\_)(____)\___)(_____)(_)\_)(____/ (___/
@app.route('/<username>/records-add', methods=['GET','POST'])
@login_required
def records_add(username):
user = User.query.filter_by(username=username).first()
# user = db.session.query(User).filter_by(username=username).first()
if request.method == "POST":
challenge = request.form.get('challenge')
challenge_type = get_challenge_type(challenge)
score = request.form.get('score')
if type(score) in [int, float]:
if check_negative(score) != False:
return redirect('/'+username+'/records-add')
if score == None:
# THIS HAPPENED BECAUSE THERE WAS NO SCORE ENTERED
raise ValueError("look at line 328 in records_add in views.py - score is None")
comment = request.form.get('comment')
# bad user input handling
if challenge_type == ChallengeTypes.time:
try:
score = float(score)
except ValueError:
flash('Please enter a number for your time')
return redirect('/'+username+'/records-add')
if challenge_type in [ChallengeTypes.reps, ChallengeTypes.laps]:
try:
score = int(score)
except ValueError:
flash('Please enter a whole number for ' + challenge_type)
return redirect('/'+username+'/records-add')
en = Entry([score, datetime_to_string(datetime.today()), comment]).to_json()
user_id = get_user_id(username)
challenges = user.challenges
try:
# there is already an entry for the challenge. append the entry to the list
debug(f'adding entry for "{challenge}" to personal records...')
challenges[challenge].append(en)
except KeyError:
# there is no entry for that challenge yet. Create a list for it and add the entry
challenges[challenge] = [en]
# this clears the dict for that user. It seemed to fix everything when it was not working
reset_user_challenges(username)
user.challenges = challenges
db.session.add(user)
db.session.commit()
debug('record added')
return redirect('/'+username+'/records-view')
return render_template('user/records/add.html',challenge_dict=load_challenge_dict(), user=user, username=username)
@app.route('/<username>/records-view')
@login_required
def records_view(username):
user = User.query.filter_by(username=username).first()
ch = json_to_objects(user.challenges)
return render_template('user/records/view.html',challenge_dict=load_challenge_dict(),username=username,user=user, ch=ch)
@app.route('/<username>/records-delete', methods=['GET','POST'])
@login_required
def records_delete(username):
user = User.query.filter_by(username=username).first()
challenges = user.challenges
if request.method == "POST":
challenge_type = request.form.get("challenge")
try:
del challenges[challenge_type]
except KeyError:
flash("unable to delete data for the challenge:"+challenge_type)
reset_user_challenges(user.username)
user.challenges = challenges
db.session.add(user)
db.session.commit()
debug(f'Deleted challenge "{challenge_type}"',color='yellow')
return redirect('/'+user.username+'/records-view')
ch = json_to_objects(user.challenges)
return render_template('user/records/delete.html',challenge_dict=load_challenge_dict(),username=username,user=user, ch=challenges)
@app.route('/<username>/suggest-challenge', methods=['GET','POST'])
@login_required
def suggest_challenge(username):
user = User.query.filter_by(username=username).first()
if request.method == "POST":
challenge_type = request.form.get('type')
challenge_name = request.form.get('challenge_name')
# force challenge names to be less than 30 characters
if limit_input_size(name=challenge_name, max_size=30):
return redirect(f'/{username}/suggest-challenge')
already_exists = Suggestion.query.filter_by(name=challenge_name).first()
if already_exists:
flash(f'That Challenge was already suggested by {User.query.get(already_exists.user_id).first_name}')
return render_template('user/new_challenge.html',username=username, user=user)
challenge = Suggestion(
type=challenge_type,
name=challenge_name,
user_id=user.id
)
send_emails = read('args.txt')['email']
# save suggestion to database
db.session.add(challenge)
db.session.commit()
if send_emails == True:
try:
body = f"""{user.first_name} {user.last_name} suggested a new challenge:
{repr(challenge_name)}
of type {repr(challenge_type)}"
click here to accept the challenge:
http://ninjapark-tracker.herokuapp.com/admin
- Ninja Park Tracker"""
send_email_to_somebody(
'Challenge submission: '+str(challenge_name),
body,
'devin.s.shende@gmail.com')
send_email_to_somebody(
'Challenge submission: '+str(challenge_name),
int,
'ravi.sameer.shende@gmail.com')
except:
debug('Error sending email',color='red',figlet=True)
return render_template('user/home.html', username=username, user=user) # redirect home after submitting
return render_template('user/new_challenge.html',username=username, user=user)
@app.route('/<username>/leaderboard', methods=['GET','POST'])
@login_required
def userleaderboard(username):
user = User.query.filter_by(username=username).first()
all_users = User.query.all()
if request.method == "POST":
selected_challenge = request.form.get('challenge')
checked = request.form.get('bracketswitch')
selected_challenge_type = get_challenge_type(selected_challenge)
data = []
for the_user in all_users:
user_challenges = json_to_objects(the_user.challenges)
if selected_challenge in user_challenges.keys():
entry = get_best(user_challenges[selected_challenge], selected_challenge_type)
data.append(
[get_full_name(the_user.id),
entry.score,
entry.comment,
the_user.id]
# [entry, user]
)
if checked:
brackets = get_brackets(data, selected_challenge_type)
return render_template('user/leaderboard_brackets.html', tables=brackets, header=selected_challenge, \
challenge_type=to_name_case(selected_challenge_type), \
username=username, brackets=brackets, bracket_names=BRACKETS, user=user)
else:
sorted_data = sort_data(data, selected_challenge_type)
from pprint import pprint
print('\nsorted data\n\n')
pprint(sorted_data)
return render_template('user/leaderboard_no_brackets.html', data=sorted_data, header=selected_challenge, \
challenge_type=to_name_case(selected_challenge_type), \
username=username,checked=repr(checked), user=user)
return render_template('user/leaderboard_no_brackets.html',challenge_dict=load_challenge_dict(), header="Leaderboard", \
username=username, user=user)
# ____ ____ _____ ____ ____ __ ____
# ( _ \( _ \( _ )( ___)(_ _)( ) ( ___)
# )___/ ) / )(_)( )__) _)(_ )(__ )__)
# (__) (_)\_)(_____)(__) (____)(____)(____)
@app.route('/<username>/profile')
@login_required
def profile(username):
user = User.query.filter_by(username=username).first()
print( "\n--------------\n coming from profile view, user = ",user, "\n age = ", user.age, "\n--------------\n")
return render_template('user/profile.html', user=user, username=username)
@app.route('/<username>/profile/edit', methods=['GET','POST'])
@login_required
def edit_profile(username):
from app import DBENV
user = User.query.filter_by(username=username).first()
if request.method == 'POST':
first_name = request.form.get( 'first_name' )
last_name = request.form.get( 'last_name' )
gender = request.form.get( 'gender' )
birthday_str = request.form.get( 'birthday' )
if birthday_str:
try:
birthday = datetime.strptime(birthday_str, '%Y-%m-%d')
except ValueError:
flash('Please reenter your birthday in the format \'yyyy-mm-dd\'')
return redirect('/'+username+'/profile')
age = datetime.today().year - birthday.year
user.birthday = birthday
debug(f'birthday is {birthday}')
if not gender:
gender
user.first_name = first_name
user.last_name = last_name
user.gender = gender
db.session.add(user)
db.session.commit()
return redirect('/'+username+'/profile')
return render_template('user/profile_edit.html', user=user, username=username, months=monthsDict)
@app.route('/<username>/profile/delete_account', methods=['GET','POST'])
@login_required
def profile_delete(username):
auth = False
user = User.query.filter_by(username=username).first()
if request.method == 'POST':
entered_password = request.form.get('password')
if entered_password:
# "enter your password"
if entered_password == decode(user.password):
auth = True
else:
flash('incorrect password!')
return redirect(f'/{username}/profile/edit')
else:
# "are you sure?"
flash('Deleted account for user '+username)
path = 'static/profile_pics/'+str(user.id)+'.jpg'
if os.path.exists(path):
os.remove(path)
logout_user()
delete_user(user)
return redirect('/')
return render_template(
'user/delete_account.html',
username=username,
user=user,
auth=auth
)
# _ _
# __ _ __| |_ __ ___ (_)_ __
# / _` |/ _` | '_ ` _ \| | '_ \
# | (_| | (_| | | | | | | | | | |
# \__,_|\__,_|_| |_| |_|_|_| |_|
from adminviews import *