diff --git a/.gitignore b/.gitignore index f5ae3c53..09bc2eb6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,53 @@ -*.pyc +# --- Security (CRITICAL) --- .env -.venv -__pycache__ -.DS_Store +.env.* +*.key +secrets.json + +# --- Python --- +__pycache__/ +*.py[cod] +*$py.class + +# --- Virtual Environments --- +.venv/ +venv/ +ENV/ +env/ + +# --- Distribution / Build --- +build/ +dist/ +*.egg-info/ +.eggs/ + +# --- Testing & Coverage (The "Ugly" Folders) --- +htmlcov/ .coverage +.coverage.* +.tox/ +.pytest_cache/ +nosetests.xml +coverage.xml + +# --- Flask --- +instance/ +.webassets-cache + +# --- IDEs & Editors --- +.vscode/ +.idea/ +*.swp +*.swo + +# --- OS Specific --- +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# --- Project Specific --- picturedata.txt \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 23fd35f0..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "editor.formatOnSave": true -} \ No newline at end of file diff --git a/htmlcov/admin_py.html b/htmlcov/admin_py.html deleted file mode 100644 index 99351216..00000000 --- a/htmlcov/admin_py.html +++ /dev/null @@ -1,613 +0,0 @@ - - - - - Coverage for admin.py: 18% - - - - - -
-
-

- Coverage for admin.py: - 18% -

- -

- 350 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1#----------------------------------------------------------------------- 

-

2# admin.py 

-

3# Contains Flask App Routing 

-

4#----------------------------------------------------------------------- 

-

5 

-

6#external libraries 

-

7import flask 

-

8import os 

-

9import auth 

-

10import dotenv 

-

11import random 

-

12 

-

13#Tiger Spot files 

-

14import database 

-

15import challenges_database 

-

16import matches_database 

-

17import versus_database 

-

18import pictures_database 

-

19import user_database 

-

20import distance_func 

-

21import daily_user_database 

-

22import points 

-

23import user_database 

-

24 

-

25#----------------------------------------------------------------------- 

-

26app = flask.Flask(__name__, template_folder='.') 

-

27dotenv.load_dotenv() 

-

28#used for CAS login 

-

29app.secret_key = os.environ['APP_SECRET_KEY'] 

-

30 

-

31#----------------------------------------------------------------------- 

-

32# GLOBAL VAR DEFAULT VAL FOR ID, NEED TO RESOLVE SECURITY MEASURES 

-

33id = 1 

-

34#----------------------------------------------------------------------- 

-

35 

-

36# For error handling 

-

37# checks if a function call had a database error based on function's return value 

-

38def database_check(list): 

-

39 if "database error" in list: 

-

40 return False 

-

41 return True 

-

42 

-

43#----------------------------------------------------------------------- 

-

44 

-

45# If the user is playing the game for the first time of today, their matches and challenges are cleared 

-

46def reset_versus(username): 

-

47 

-

48 last_date = daily_user_database.get_last_versus_date(username) 

-

49 print(f"LAST VERSUS DATE IS: {last_date}") 

-

50 current_date = pictures_database.get_current_date() 

-

51 print(f"CURRENT DATE IS: {current_date}") 

-

52 

-

53 if last_date != current_date: 

-

54 challenges_database.clear_user_challenges(username) 

-

55 daily_user_database.update_player_versus(username) 

-

56 

-

57#----------------------------------------------------------------------- 

-

58 

-

59@app.route('/sam', methods=['GET']) 

-

60def sam(): 

-

61 html_code = flask.render_template('sam.html') 

-

62 response = flask.make_response(html_code) 

-

63 return response 

-

64 

-

65#----------------------------------------------------------------------- 

-

66 

-

67# Routes for authentication. 

-

68@app.route('/logoutapp', methods=['GET']) 

-

69def logoutapp(): 

-

70 return auth.logoutapp() 

-

71 

-

72@app.route('/logoutcas', methods=['GET']) 

-

73def logoutcas(): 

-

74 return auth.logoutcas() 

-

75 

-

76#----------------------------------------------------------------------- 

-

77# Displays page with log in button 

-

78@app.route('/', methods=['GET']) 

-

79@app.route('/index', methods=['GET']) 

-

80def index(): 

-

81 

-

82 html_code = flask.render_template('index.html') 

-

83 response = flask.make_response(html_code) 

-

84 return response 

-

85 

-

86#----------------------------------------------------------------------- 

-

87 

-

88# Home page after user logs in through Princeton's CAS 

-

89@app.route('/menu', methods=['GET']) 

-

90def menu(): 

-

91 global id 

-

92 username = auth.authenticate() 

-

93 user_insert = user_database.insert_player(username) 

-

94 daily_insert = daily_user_database.insert_player_daily(username) 

-

95 played_date = daily_user_database.get_last_played_date(username) 

-

96 current_date = pictures_database.get_current_date() 

-

97 

-

98 check = database_check([user_insert, daily_insert, played_date, current_date]) 

-

99 if check is False: 

-

100 html_code = flask.render_template('contact_admin.html') 

-

101 return flask.make_response(html_code) 

-

102 

-

103 if played_date != current_date: 

-

104 reset = daily_user_database.reset_player(username) 

-

105 user_played = daily_user_database.player_played(username) 

-

106 id = pictures_database.pic_of_day() 

-

107 check = database_check([reset, user_played, id]) 

-

108 if check is False: 

-

109 html_code = flask.render_template('contact_admin.html') 

-

110 return flask.make_response(html_code) 

-

111 

-

112 html_code = flask.render_template('menu.html', username = username) 

-

113 response = flask.make_response(html_code) 

-

114 return response 

-

115 

-

116#----------------------------------------------------------------------- 

-

117 

-

118# if there are no database errors, renders versus page listing a user's challenges. Otherwise, renders error page 

-

119@app.route('/requests', methods=['GET']) 

-

120def requests(): 

-

121 username = flask.request.args.get('username') 

-

122 username_auth = auth.authenticate() 

-

123 last_date = daily_user_database.get_last_versus_date(username) 

-

124 current_date = pictures_database.get_current_date() 

-

125 

-

126 check = database_check([last_date, current_date]) 

-

127 if check is False: 

-

128 html_code = flask.render_template('contact_admin.html') 

-

129 return flask.make_response(html_code) 

-

130 

-

131 if last_date != current_date: 

-

132 challenges_database.clear_user_challenges(username) 

-

133 daily_user_database.update_player_versus(username) 

-

134 # Need to add check here too 

-

135 

-

136 pending_challenges = challenges_database.get_user_challenges(username_auth) 

-

137 users = user_database.get_players() 

-

138 

-

139 check = database_check([pending_challenges, users]) 

-

140 if check is False: 

-

141 html_code = flask.render_template('contact_admin.html') 

-

142 else: 

-

143 html_code = flask.render_template('Versus/challenges.html', challenges=pending_challenges, user=username_auth, users=flask.json.dumps(users), username=username) 

-

144 

-

145 response = flask.make_response(html_code) 

-

146 return response 

-

147 

-

148#----------------------------------------------------------------------- 

-

149 

-

150# if there are no errors, loads the daily game  

-

151# or if user has already played today's game, loads a page stating their points and distance between their guess and correct location 

-

152@app.route('/game', methods=['GET']) 

-

153def game(): 

-

154 

-

155 global id 

-

156 

-

157 username = auth.authenticate() 

-

158 

-

159 user_played = daily_user_database.player_played(username) 

-

160 today_points = daily_user_database.get_daily_points(username) 

-

161 today_distance = daily_user_database.get_daily_distance(username) 

-

162 

-

163 check = database_check([user_played, today_points, today_distance]) 

-

164 if check is False: 

-

165 html_code = flask.render_template('contact_admin.html') 

-

166 return flask.make_response(html_code) 

-

167 

-

168 if user_played: 

-

169 html_code = flask.render_template('alrplayed.html', username = username, today_points = today_points, today_distance = today_distance) 

-

170 response = flask.make_response(html_code) 

-

171 return response 

-

172 

-

173 link = pictures_database.get_pic_info("link", id) 

-

174 

-

175 check = database_check([link]) 

-

176 if check is False: 

-

177 html_code = flask.render_template('contact_admin.html') 

-

178 else: 

-

179 html_code = flask.render_template('gamepage.html', link = link, id = id) 

-

180 

-

181 response = flask.make_response(html_code) 

-

182 return response 

-

183 

-

184#----------------------------------------------------------------------- 

-

185 

-

186# if there are no errors with database, calculates distance and points and updates usersDaily table with points and adds today's points to total points column in users table 

-

187# Then loads the results page which displays the correct location, the distance from guess to acutal location, points earned, place where picture was taken 

-

188@app.route('/submit', methods=['POST']) 

-

189def submit(): 

-

190 

-

191 username = auth.authenticate() 

-

192 

-

193 user_played = daily_user_database.player_played(username) 

-

194 today_points = daily_user_database.get_daily_points(username) 

-

195 today_distance = daily_user_database.get_daily_distance(username) 

-

196 

-

197 check = database_check([user_played, today_points, today_distance]) 

-

198 if check is False: 

-

199 html_code = flask.render_template('contact_admin.html') 

-

200 return flask.make_response(html_code) 

-

201 

-

202 if user_played: 

-

203 html_code = flask.render_template('alrplayed.html', username = username, today_points = today_points, today_distance = today_distance) 

-

204 response = flask.make_response(html_code) 

-

205 return response 

-

206 

-

207 # get user input using flask.request.args.get('') 

-

208 #once user clicks submit then get coordinates 

-

209 currLat = flask.request.form.get('currLat') # Use .get for safe retrieval 

-

210 currLon = flask.request.form.get('currLon') 

-

211 if not currLat or not currLon: 

-

212 return 

-

213 

-

214 coor = pictures_database.get_pic_info("coordinates", id) 

-

215 place = pictures_database.get_pic_info("place", id) 

-

216 distance = round(distance_func.calc_distance(currLat, currLon, coor)) 

-

217 today_points = round(points.calculate_today_points(distance)) 

-

218 total_points = round(points.calculate_total_points(username, today_points)) 

-

219 update= user_database.update_player(username, total_points) 

-

220 daily_update = daily_user_database.update_player_daily(username, today_points, distance) 

-

221 

-

222 check = database_check([coor, place, update, daily_update]) 

-

223 if check is False: 

-

224 html_code = flask.render_template('contact_admin.html') 

-

225 else: 

-

226 html_code = flask.render_template('results.html', dis = distance, lat = currLat, lon = currLon, coor=coor, today_points = today_points, place = place, today_distance = distance) 

-

227 

-

228 response = flask.make_response(html_code) 

-

229 return response 

-

230 

-

231#----------------------------------------------------------------------- 

-

232 

-

233# Displays rules page for both daily game and versus mode 

-

234@app.route('/rules', methods=['GET']) 

-

235def rules(): 

-

236 # user must be logged in to access page 

-

237 auth.authenticate() 

-

238 html_code = flask.render_template('rules.html') 

-

239 response = flask.make_response(html_code) 

-

240 return response 

-

241 

-

242#----------------------------------------------------------------------- 

-

243 

-

244# Displays about the team page 

-

245@app.route('/team', methods=['GET']) 

-

246def team(): 

-

247 # user must be logged in to access page 

-

248 auth.authenticate() 

-

249 html_code = flask.render_template('team.html') 

-

250 response = flask.make_response(html_code) 

-

251 return response 

-

252 

-

253#----------------------------------------------------------------------- 

-

254 

-

255# Displays the leaderboard for overall points 

-

256@app.route('/totalboard', methods=['GET']) 

-

257def leaderboard(): 

-

258 top_players = user_database.get_top_players() 

-

259 username = auth.authenticate() 

-

260 points = user_database.get_points(username) 

-

261 daily_points = daily_user_database.get_daily_points(username) 

-

262 rank = user_database.get_rank(username) 

-

263 daily_rank = daily_user_database.get_daily_rank(username) 

-

264 streak = daily_user_database.get_streak(username) 

-

265 

-

266 check = database_check([top_players, points, daily_points, rank, daily_rank, streak]) 

-

267 

-

268 if check is False: 

-

269 html_code = flask.render_template('contact_admin.html') 

-

270 else: 

-

271 html_code = flask.render_template('totalboard.html', top_players = top_players, points = points, daily_points = daily_points, rank = rank, daily_rank = daily_rank, streak = streak) 

-

272 

-

273 response = flask.make_response(html_code) 

-

274 return response 

-

275 

-

276#----------------------------------------------------------------------- 

-

277 

-

278# Displays the leaderboard for today's daily game points 

-

279@app.route('/leaderboard', methods=['GET']) 

-

280def totalleaderboard(): 

-

281 top_players = daily_user_database.get_daily_top_players() 

-

282 username = auth.authenticate() 

-

283 points = user_database.get_points(username) 

-

284 daily_points = daily_user_database.get_daily_points(username) 

-

285 rank = user_database.get_rank(username) 

-

286 daily_rank = daily_user_database.get_daily_rank(username) 

-

287 streak = daily_user_database.get_streak(username) 

-

288 

-

289 check = database_check([top_players, points, daily_points, rank, daily_rank, streak]) 

-

290 if check is False: 

-

291 html_code = flask.render_template('contact_admin.html') 

-

292 else: 

-

293 html_code = flask.render_template('leaderboard.html', top_players = top_players, points = points, daily_points = daily_points, rank = rank, daily_rank = daily_rank, streak = streak) 

-

294 

-

295 response = flask.make_response(html_code) 

-

296 return response 

-

297 

-

298#----------------------------------------------------------------------- 

-

299 

-

300# checks that users table is not corrupted and then displays the versus page where users can initiate and see challenges 

-

301@app.route('/versus', methods=['GET']) 

-

302def versus_func(): 

-

303 users = user_database.get_players() 

-

304 username = flask.request.args.get('username') 

-

305 

-

306 check = database_check([users]) 

-

307 if check is False: 

-

308 html_code = flask.render_template('contact_admin.html') 

-

309 else: 

-

310 html_code = flask.render_template('Versus/challenges.html', users=flask.json.dumps(users), username=username) 

-

311 

-

312 response = flask.make_response(html_code) 

-

313 return response 

-

314 

-

315#----------------------------------------------------------------------- 

-

316 

-

317# checks that user table is not corrupted and that opponent enters is a valid user (exisiting netiID and has logged in before) 

-

318@app.route('/create-challenge', methods=['POST']) 

-

319def create_challenge_route(): 

-

320 challengee_id = flask.request.form['challengee_id'].strip() # Trim whitespace 

-

321 users = user_database.get_players() 

-

322 

-

323 check = database_check([users]) 

-

324 if check is False: 

-

325 html_code = flask.render_template('contact_admin.html') 

-

326 return flask.make_response(html_code) 

-

327 

-

328 # Ensure challengee_id is not empty and exists in the users list 

-

329 if challengee_id == None or challengee_id not in users or challengee_id == auth.authenticate(): 

-

330 response = {'status': 'error', 'message': 'Invalid challengee ID'} 

-

331 return flask.jsonify(response), 400 # Including a 400 Bad Request status code 

-

332 else: 

-

333 result = challenges_database.create_challenge(auth.authenticate(), challengee_id) 

-

334 

-

335 # Handle the response from the database function 

-

336 if 'error' in result: 

-

337 return flask.jsonify({'status': 'error', 'message': result['error']}), 400 

-

338 else: 

-

339 return flask.jsonify({'status': 'success', 'message': result['success'], 'challenge_id': result['challenge_id']}), 200 

-

340 

-

341#----------------------------------------------------------------------- 

-

342 

-

343# Accepts challenge unless there is a database error 

-

344@app.route('/accept_challenge', methods=['POST']) 

-

345def accept_challenge_route(): 

-

346 challenge_id = flask.request.form.get('challenge_id') 

-

347 result = challenges_database.accept_challenge(challenge_id) # Returns whether or not challenge acceptance was successful 

-

348 

-

349 check = database_check([result]) 

-

350 if check is False: 

-

351 html_code = flask.render_template('contact_admin.html') 

-

352 return flask.make_response(html_code) 

-

353 

-

354 if result == "accepted": 

-

355 flask.flash('Challenge accepted successfully.') 

-

356 else: 

-

357 flask.flash('Error accepting challenge.') 

-

358 return flask.redirect(flask.url_for('requests')) # Redirects back to the versus page with the tables of user's challenges 

-

359 

-

360#----------------------------------------------------------------------- 

-

361 

-

362# Declines challenge unless there is a database error 

-

363@app.route('/decline_challenge', methods=['POST']) 

-

364def decline_challenge_route(): 

-

365 challenge_id = flask.request.form.get('challenge_id') 

-

366 result = challenges_database.decline_challenge(challenge_id) 

-

367 

-

368 check = database_check([result]) 

-

369 if check is False: 

-

370 html_code = flask.render_template('contact_admin.html') 

-

371 return flask.make_response(html_code) 

-

372 

-

373 if result == "declined": 

-

374 flask.flash('Challenge declined successfully.') 

-

375 else: 

-

376 flask.flash('Error declining challenge.') 

-

377 return flask.redirect(flask.url_for('requests')) 

-

378 

-

379#----------------------------------------------------------------------- 

-

380 

-

381@app.route('/play_button', methods=['POST']) 

-

382def play_button(): 

-

383 challenge_id = flask.request.form.get('challenge_id') 

-

384 user = auth.authenticate() 

-

385 status = challenges_database.get_playbutton_status(challenge_id, user) 

-

386 if status is None: 

-

387 return flask.redirect(flask.url_for('requests')) 

-

388 elif status is False: 

-

389 challenges_database.update_playbutton_status(challenge_id, user) 

-

390 return flask.redirect(flask.url_for('start_challenge', challenge_id=challenge_id)) 

-

391 elif status is True: 

-

392 challenges_database.update_finish_status(challenge_id, user) 

-

393 status = challenges_database.check_finish_status(challenge_id) 

-

394 if status['status'] == "finished": 

-

395 result = challenges_database.get_challenge_results(challenge_id) 

-

396 matches_database.complete_match(challenge_id, result['winner'], result['challenger_points'], result['challengee_points']) 

-

397 return flask.redirect(flask.url_for('requests')) 

-

398 else: 

-

399 return flask.redirect(flask.url_for('requests')) 

-

400 

-

401#----------------------------------------------------------------------- 

-

402 

-

403@app.route('/start_challenge', methods=['GET']) 

-

404def start_challenge(): 

-

405 challenge_id = flask.request.args.get('challenge_id') 

-

406 if challenge_id is None: 

-

407 return flask.redirect(flask.url_for('requests')) 

-

408 

-

409 index = int(flask.request.args.get('index', 0)) 

-

410 versusList = challenges_database.get_random_versus(challenge_id) 

-

411 if versusList is None: 

-

412 return flask.redirect(flask.url_for('requests')) 

-

413 

-

414 if index < len(versusList): 

-

415 link = pictures_database.get_pic_info("link", versusList[index]) 

-

416 html_code = flask.render_template('versusgame.html', challenge_id=challenge_id, index=index, link=link) 

-

417 return flask.make_response(html_code) 

-

418 else: 

-

419 return flask.redirect(flask.url_for('requests')) 

-

420 

-

421#----------------------------------------------------------------------- 

-

422 

-

423@app.route('/end_challenge', methods=['POST']) 

-

424def end_challenge(): 

-

425 challenge_id = flask.request.form.get('challenge_id') 

-

426 user = auth.authenticate() 

-

427 finish = challenges_database.update_finish_status(challenge_id, user) 

-

428 if finish == None: 

-

429 return flask.redirect(flask.url_for('requests')) 

-

430 status = challenges_database.check_finish_status(challenge_id) 

-

431 if status['status'] == "finished": 

-

432 result = challenges_database.get_challenge_results(challenge_id) 

-

433 matches_database.complete_match(challenge_id, result['winner'], result['challenger_points'], result['challengee_points']) 

-

434 return flask.redirect(flask.url_for('requests')) 

-

435 else: 

-

436 return flask.redirect(flask.url_for('requests')) 

-

437 

-

438#----------------------------------------------------------------------- 

-

439 

-

440@app.route('/submit2', methods=['POST']) 

-

441def submit2(): 

-

442 currLat = flask.request.form.get('currLat') 

-

443 currLon = flask.request.form.get('currLon') 

-

444 points = 0 

-

445 if not currLat or not currLon: 

-

446 index = int(flask.request.form.get('index')) 

-

447 challenge_id = flask.request.form.get('challenge_id') 

-

448 distance = 0 

-

449 pic_status = versus_database.get_versus_pic_status(challenge_id, auth.authenticate(), index+1) 

-

450 if pic_status is None: 

-

451 return flask.redirect(flask.url_for('requests')) 

-

452 if pic_status == False: 

-

453 fin1 = versus_database.update_versus_pic_status(challenge_id, auth.authenticate(), index+1) 

-

454 print(fin1) 

-

455 if fin1 is None: 

-

456 return flask.redirect(flask.url_for('requests')) 

-

457 fin2 = versus_database.store_versus_pic_points(challenge_id, auth.authenticate(), index+1, points) 

-

458 print(fin2) 

-

459 if fin2 is None: 

-

460 return flask.redirect(flask.url_for('requests')) 

-

461 fin3 = versus_database.update_versus_points(challenge_id, auth.authenticate(), points) 

-

462 print(fin3) 

-

463 if fin3 is None: 

-

464 return flask.redirect(flask.url_for('requests')) 

-

465 else: 

-

466 points = "Already submitted." 

-

467 index = int(index) + 1 

-

468 html_code = flask.render_template('versusresults.html', dis = distance, lat = None, lon = None, coor=None, index=index, challenge_id=challenge_id, points=str(points)) 

-

469 response = flask.make_response(html_code) 

-

470 return response 

-

471 

-

472 index = int(flask.request.form.get('index')) 

-

473 challenge_id = flask.request.form.get('challenge_id') 

-

474 time = int(flask.request.form.get('time')) 

-

475 versusList = challenges_database.get_random_versus(challenge_id) 

-

476 print(versusList) 

-

477 if versusList is None: 

-

478 return flask.redirect(flask.url_for('requests')) 

-

479 coor = pictures_database.get_pic_info("coordinates", versusList[index]) 

-

480 distance = round(distance_func.calc_distance(currLat, currLon, coor)) 

-

481 pic_status = versus_database.get_versus_pic_status(challenge_id, auth.authenticate(), index+1) 

-

482 print(pic_status) 

-

483 if pic_status is None: 

-

484 return flask.redirect(flask.url_for('requests')) 

-

485 if pic_status == False: 

-

486 points = round(versus_database.calculate_versus(distance, time)) 

-

487 fin1 = versus_database.store_versus_pic_points(challenge_id, auth.authenticate(), index+1, points) 

-

488 print(fin1) 

-

489 if fin1 is None: 

-

490 return flask.redirect(flask.url_for('requests')) 

-

491 fin2 = versus_database.update_versus_points(challenge_id, auth.authenticate(), points) 

-

492 print(fin2) 

-

493 if fin2 is None: 

-

494 return flask.redirect(flask.url_for('requests')) 

-

495 fin3 = versus_database.update_versus_pic_status(challenge_id, auth.authenticate(), index+1) 

-

496 print(fin3) 

-

497 if fin3 is None: 

-

498 return flask.redirect(flask.url_for('requests')) 

-

499 else: 

-

500 points = "Already submitted." 

-

501 index = int(index) + 1 

-

502 html_code = flask.render_template('versusresults.html', dis = distance, lat = currLat, lon = currLon, coor=coor, index=index, challenge_id=challenge_id, points=str(points)) 

-

503 response = flask.make_response(html_code) 

-

504 return response 

-

505 

-

506#----------------------------------------------------------------------- 

-

507 

-

508@app.route('/versus_stats', methods=['GET']) 

-

509def versus_stats(): 

-

510 challenge_id = flask.request.args.get('challenge_id') 

-

511 results = challenges_database.get_challenge_results(challenge_id) 

-

512 versusList = challenges_database.get_random_versus(challenge_id) 

-

513 pictures = [pictures_database.get_pic_info("link", pic) for pic in versusList] 

-

514 html_code = flask.render_template('versus_stats.html', results=results, images=pictures) 

-

515 response = flask.make_response(html_code) 

-

516 return response 

-
- - - diff --git a/htmlcov/auth_py.html b/htmlcov/auth_py.html deleted file mode 100644 index c5bdde85..00000000 --- a/htmlcov/auth_py.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - Coverage for auth.py: 22% - - - - - -
-
-

- Coverage for auth.py: - 22% -

- -

- 45 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1 

-

2#----------------------------------------------------------------------- 

-

3# auth.py 

-

4#----------------------------------------------------------------------- 

-

5 

-

6import urllib.request 

-

7import urllib.parse 

-

8import re 

-

9import flask 

-

10 

-

11#----------------------------------------------------------------------- 

-

12 

-

13_CAS_URL = 'https://fed.princeton.edu/cas/' 

-

14 

-

15#----------------------------------------------------------------------- 

-

16 

-

17# Return url after stripping out the "ticket" parameter that was 

-

18# added by the CAS server. 

-

19 

-

20def strip_ticket(url): 

-

21 if url is None: 

-

22 return "something is badly wrong" 

-

23 url = re.sub(r'ticket=[^&]*&?', '', url) 

-

24 url = re.sub(r'\?&?$|&$', '', url) 

-

25 return url 

-

26 

-

27#----------------------------------------------------------------------- 

-

28 

-

29# Validate a login ticket by contacting the CAS server. If 

-

30# valid, return the user's username; otherwise, return None. 

-

31 

-

32def validate(ticket): 

-

33 val_url = (_CAS_URL + "validate" + '?service=' 

-

34 + urllib.parse.quote(strip_ticket(flask.request.url)) 

-

35 + '&ticket=' + urllib.parse.quote(ticket)) 

-

36 lines = [] 

-

37 with urllib.request.urlopen(val_url) as flo: 

-

38 lines = flo.readlines() # Should return 2 lines. 

-

39 if len(lines) != 2: 

-

40 return None 

-

41 first_line = lines[0].decode('utf-8') 

-

42 second_line = lines[1].decode('utf-8') 

-

43 if not first_line.startswith('yes'): 

-

44 return None 

-

45 return second_line 

-

46 

-

47#----------------------------------------------------------------------- 

-

48 

-

49# Authenticate the remote user, and return the user's username. 

-

50# Do not return unless the user is successfully authenticated. 

-

51 

-

52def authenticate(): 

-

53 

-

54 # If the username is in the session, then the user was 

-

55 # authenticated previously. So return the username. 

-

56 if 'username' in flask.session: 

-

57 return flask.session.get('username') 

-

58 

-

59 # If the request does not contain a login ticket, then redirect 

-

60 # the browser to the login page to get one. 

-

61 ticket = flask.request.args.get('ticket') 

-

62 if ticket is None: 

-

63 login_url = (_CAS_URL + 'login?service=' + 

-

64 urllib.parse.quote(flask.request.url)) 

-

65 flask.abort(flask.redirect(login_url)) 

-

66 

-

67 # If the login ticket is invalid, then redirect the browser 

-

68 # to the login page to get a new one. 

-

69 username = validate(ticket) 

-

70 if username is None: 

-

71 login_url = (_CAS_URL + 'login?service=' 

-

72 + urllib.parse.quote(strip_ticket(flask.request.url))) 

-

73 flask.abort(flask.redirect(login_url)) 

-

74 

-

75 # The user is authenticated, so store the username in 

-

76 # the session. 

-

77 username = username.strip() 

-

78 flask.session['username'] = username 

-

79 return username 

-

80 

-

81#----------------------------------------------------------------------- 

-

82 

-

83def logoutapp(): 

-

84 

-

85 # Log out of the application. 

-

86 flask.session.clear() 

-

87 html_code = flask.render_template('index.html') 

-

88 response = flask.make_response(html_code) 

-

89 return response 

-

90 

-

91#----------------------------------------------------------------------- 

-

92 

-

93def logoutcas(): 

-

94 

-

95 # Log out of the CAS session, and then the application. 

-

96 logout_url = (_CAS_URL + 'logout?service=' 

-

97 + urllib.parse.quote( 

-

98 re.sub('logoutcas', 'logoutapp', flask.request.url))) 

-

99 flask.abort(flask.redirect(logout_url)) 

-
- - - diff --git a/htmlcov/challenges_database_py.html b/htmlcov/challenges_database_py.html deleted file mode 100644 index 327b5444..00000000 --- a/htmlcov/challenges_database_py.html +++ /dev/null @@ -1,637 +0,0 @@ - - - - - Coverage for challenges_database.py: 8% - - - - - -
-
-

- Coverage for challenges_database.py: - 8% -

- -

- 287 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1import psycopg2 

-

2import random 

-

3import database 

-

4import versus_database 

-

5 

-

6DATABASE_URL = 'postgres://tigerspot_user:9WtP1U9PRdh1VLlP4VdwnT0BFSdbrPWk@dpg-cnrjs7q1hbls73e04390-a.ohio-postgres.render.com/tigerspot' 

-

7 

-

8#dont run again 

-

9def create_challenges_table(): 

-

10 conn = psycopg2.connect(DATABASE_URL) 

-

11 cur = conn.cursor() 

-

12 cur.execute('''CREATE TABLE IF NOT EXISTS challenges( 

-

13 id SERIAL PRIMARY KEY, 

-

14 challenger_id VARCHAR(255), 

-

15 challengee_id VARCHAR(255), 

-

16 status VARCHAR(50));''') 

-

17 conn.commit() 

-

18 cur.close() 

-

19 conn.close() 

-

20 

-

21#----------------------------------------------------------------------- 

-

22 

-

23def clear_challenges_table(): 

-

24 conn = None 

-

25 try: 

-

26 conn = psycopg2.connect(DATABASE_URL) 

-

27 cur = conn.cursor() 

-

28 # Deletes all records from the challenges table 

-

29 cur.execute("DELETE FROM challenges;") 

-

30 conn.commit() # Commit the transaction to make changes permanent 

-

31 print("Challenges table cleared.") 

-

32 cur.execute("DELETE FROM matches;") 

-

33 conn.commit() # Commit the transaction to make changes permanent 

-

34 print("Matches table cleared.") 

-

35 cur.execute("ALTER SEQUENCE challenges_id_seq RESTART WITH 1;") 

-

36 conn.commit() # Commit the change to make it permanent 

-

37 print("Challenges id sequence reset.") 

-

38 cur.execute("ALTER SEQUENCE matches_id_seq RESTART WITH 1;") 

-

39 conn.commit() # Commit the change to make it permanent 

-

40 print("Matches id sequence reset.") 

-

41 except (Exception, psycopg2.DatabaseError) as error: 

-

42 print(f"Error clearing challenges table: {error}") 

-

43 finally: 

-

44 if conn is not None: 

-

45 conn.close() 

-

46 

-

47 

-

48def clear_user_challenges(user_id): 

-

49 conn = None 

-

50 try: 

-

51 conn = psycopg2.connect(DATABASE_URL) 

-

52 cur = conn.cursor() 

-

53 

-

54 # Query to find challenges related to the user_id 

-

55 cur.execute(""" 

-

56 SELECT id FROM challenges  

-

57 WHERE challenger_id = %s OR challengee_id = %s; 

-

58 """, (user_id, user_id)) 

-

59 

-

60 challenge_ids = [row[0] for row in cur.fetchall()] 

-

61 

-

62 if challenge_ids: 

-

63 # Delete matching entries from the matches table 

-

64 cur.execute(""" 

-

65 DELETE FROM matches  

-

66 WHERE challenge_id IN %s; 

-

67 """, (tuple(challenge_ids),)) 

-

68 

-

69 # Delete entries from the challenges table 

-

70 cur.execute(""" 

-

71 DELETE FROM challenges  

-

72 WHERE id IN %s; 

-

73 """, (tuple(challenge_ids),)) 

-

74 

-

75 conn.commit() # Commit the transaction to make changes permanent 

-

76 print(f"Entries related to user_id {user_id} cleared from challenges and matches tables.") 

-

77 

-

78 except (Exception, psycopg2.DatabaseError) as error: 

-

79 print(f"Error clearing entries for user_id {user_id}: {error}") 

-

80 finally: 

-

81 if conn is not None: 

-

82 conn.close() 

-

83 

-

84#----------------------------------------------------------------------- 

-

85 

-

86def create_challenge(challenger_id, challengee_id): 

-

87 conn = None 

-

88 try: 

-

89 conn = psycopg2.connect(DATABASE_URL) 

-

90 cur = conn.cursor() 

-

91 

-

92 # Check for existing challenge between the two users 

-

93 cur.execute(""" 

-

94 SELECT id FROM challenges  

-

95 WHERE  

-

96 ((challenger_id = %s AND challengee_id = %s) OR  

-

97 (challenger_id = %s AND challengee_id = %s))  

-

98 AND status IN ('pending', 'accepted') 

-

99 """, (challenger_id, challengee_id, challengee_id, challenger_id)) 

-

100 

-

101 existing_challenge = cur.fetchone() 

-

102 

-

103 if existing_challenge: 

-

104 # An existing challenge was found 

-

105 return {'error': 'Challenge already exists', 'challenge_id': existing_challenge[0]} 

-

106 

-

107 # No existing challenge found, proceed to create a new one 

-

108 cur.execute(""" 

-

109 INSERT INTO challenges (challenger_id, challengee_id, status)  

-

110 VALUES (%s, %s, 'pending') RETURNING id; 

-

111 """, (challenger_id, challengee_id)) 

-

112 

-

113 challenge_id = cur.fetchone()[0] 

-

114 conn.commit() 

-

115 print(f"Challenge created with ID: {challenge_id}") 

-

116 return {'success': 'Challenge created successfully', 'challenge_id': challenge_id} 

-

117 

-

118 except (Exception, psycopg2.DatabaseError) as error: 

-

119 print(error) 

-

120 return {'error': 'Database error occurred'} 

-

121 finally: 

-

122 if conn is not None: 

-

123 conn.close() 

-

124 

-

125#----------------------------------------------------------------------- 

-

126 

-

127# Accept a challenge 

-

128def accept_challenge(challenge_id): 

-

129 status = "database error" # Default status in case of error 

-

130 conn = None 

-

131 try: 

-

132 conn = psycopg2.connect(DATABASE_URL) 

-

133 cur = conn.cursor() 

-

134 cur.execute(""" 

-

135 UPDATE challenges  

-

136 SET status = 'accepted',  

-

137 versusList = %s 

-

138 WHERE id = %s; 

-

139 """, (create_random_versus(), challenge_id)) 

-

140 conn.commit() 

-

141 cur.close() 

-

142 status = "accepted" # Update status on success 

-

143 except (Exception, psycopg2.DatabaseError) as error: 

-

144 print(error) 

-

145 # Optionally, handle different types of exceptions differently 

-

146 finally: 

-

147 if conn is not None: 

-

148 conn.close() 

-

149 return status 

-

150 

-

151 

-

152#----------------------------------------------------------------------- 

-

153 

-

154# Decline a challenge 

-

155def decline_challenge(challenge_id): 

-

156 status = "database error" # Default status in case of error 

-

157 conn = None 

-

158 try: 

-

159 conn = psycopg2.connect(DATABASE_URL) 

-

160 cur = conn.cursor() 

-

161 cur.execute("UPDATE challenges SET status = 'declined' WHERE id = %s;", (challenge_id,)) 

-

162 conn.commit() 

-

163 cur.close() 

-

164 status = "declined" # Update status on success 

-

165 except (Exception, psycopg2.DatabaseError) as error: 

-

166 print(error) 

-

167 finally: 

-

168 if conn is not None: 

-

169 conn.close() 

-

170 return status 

-

171 

-

172 

-

173def reset_challenges_id_sequence(): 

-

174 conn = None 

-

175 try: 

-

176 conn = psycopg2.connect(DATABASE_URL) 

-

177 cur = conn.cursor() 

-

178 # Assuming the sequence name is 'challenges_id_seq' 

-

179 cur.execute("ALTER SEQUENCE challenges_id_seq RESTART WITH 1;") 

-

180 conn.commit() # Commit the change to make it permanent 

-

181 print("Challenges id sequence reset.") 

-

182 cur.execute("ALTER SEQUENCE matches_id_seq RESTART WITH 1;") 

-

183 conn.commit() # Commit the change to make it permanent 

-

184 print("Matches id sequence reset.") 

-

185 except (Exception, psycopg2.DatabaseError) as error: 

-

186 print(f"Error resetting challenges id sequence: {error}") 

-

187 finally: 

-

188 if conn is not None: 

-

189 conn.close() 

-

190 

-

191def get_user_challenges(user_id): 

-

192 conn = psycopg2.connect(DATABASE_URL) # Ensure DATABASE_URL is properly configured 

-

193 cur = conn.cursor() 

-

194 # Query for both challenges initiated by the user and challenges where the user is the challengee, 

-

195 # including whether each side has finished the challenge. 

-

196 cur.execute(""" 

-

197 SELECT challenges.id, challenger_id, challengee_id, status, challenger_finished, challengee_finished 

-

198 FROM challenges 

-

199 WHERE (challenges.challenger_id = %s OR challenges.challengee_id = %s); 

-

200 """, (user_id, user_id)) 

-

201 challenges = cur.fetchall() 

-

202 cur.close() 

-

203 conn.close() 

-

204 

-

205 # Initialize dictionaries to hold the two types of challenges 

-

206 user_challenges = {'initiated': [], 'received': []} 

-

207 

-

208 # Iterate through the results and categorize each challenge 

-

209 for challenge in challenges: 

-

210 # Add challenger_finished and challengee_finished to the dictionary 

-

211 if versus_database.get_winner(challenge[0]) is not None: 

-

212 challenge_dict = { 

-

213 "id": challenge[0], 

-

214 "challenger_id": challenge[1], 

-

215 "challengee_id": challenge[2], 

-

216 "status": challenge[3], 

-

217 "challenger_finished": challenge[4], 

-

218 "challengee_finished": challenge[5], 

-

219 "winner_id": versus_database.get_winner(challenge[0]) 

-

220 } 

-

221 else: 

-

222 challenge_dict = { 

-

223 "id": challenge[0], 

-

224 "challenger_id": challenge[1], 

-

225 "challengee_id": challenge[2], 

-

226 "status": challenge[3], 

-

227 "challenger_finished": challenge[4], 

-

228 "challengee_finished": challenge[5], 

-

229 "winner_id": None 

-

230 } 

-

231 if challenge[1] == user_id: # User is the challenger 

-

232 user_challenges['initiated'].append(challenge_dict) 

-

233 else: # User is the challengee 

-

234 user_challenges['received'].append(challenge_dict) 

-

235 

-

236 return user_challenges 

-

237 

-

238def update_finish_status(challenge_id, user_id): 

-

239 conn = None 

-

240 try: 

-

241 conn = psycopg2.connect(DATABASE_URL) 

-

242 cur = conn.cursor() 

-

243 

-

244 # First, determine if the user is the challenger or the challengee for this challenge 

-

245 cur.execute(''' 

-

246 SELECT challenger_id, challengee_id  

-

247 FROM challenges  

-

248 WHERE id = %s; 

-

249 ''', (challenge_id,)) 

-

250 

-

251 result = cur.fetchone() 

-

252 if result is None: 

-

253 print("Challenge not found.") 

-

254 return 

-

255 

-

256 challenger_id, challengee_id = result 

-

257 

-

258 # Depending on whether the user is the challenger or the challengee, 

-

259 # update the corresponding finished column in the matches table 

-

260 if user_id == challenger_id: 

-

261 cur.execute(''' 

-

262 UPDATE challenges  

-

263 SET challenger_finished = TRUE  

-

264 WHERE id = %s; 

-

265 ''', (challenge_id,)) 

-

266 elif user_id == challengee_id: 

-

267 cur.execute(''' 

-

268 UPDATE challenges 

-

269 SET challengee_finished = TRUE  

-

270 WHERE id = %s; 

-

271 ''', (challenge_id,)) 

-

272 else: 

-

273 print("User is not part of this challenge.") 

-

274 return 

-

275 

-

276 conn.commit() 

-

277 print("Finish status updated successfully.") 

-

278 return {"status": "success"} 

-

279 

-

280 except (Exception, psycopg2.DatabaseError) as error: 

-

281 print(f"Error: {error}") 

-

282 finally: 

-

283 if conn is not None: 

-

284 conn.close() 

-

285 

-

286def check_finish_status(challenge_id): 

-

287 conn = None 

-

288 status = {"status": "unfinished"} # Default status 

-

289 try: 

-

290 conn = psycopg2.connect(DATABASE_URL) 

-

291 cur = conn.cursor() 

-

292 

-

293 # Query to check the finish status for both challenger and challengee 

-

294 cur.execute(''' 

-

295 SELECT challenger_finished, challengee_finished 

-

296 FROM challenges 

-

297 WHERE id = %s; 

-

298 ''', (challenge_id,)) 

-

299 

-

300 result = cur.fetchone() 

-

301 if result: 

-

302 challenger_finished, challengee_finished = result 

-

303 if challenger_finished and challengee_finished: 

-

304 status = {"status": "finished"} 

-

305 else: 

-

306 print("No match found with the given challenge_id.") 

-

307 

-

308 except (Exception, psycopg2.DatabaseError) as error: 

-

309 print(f"Error checking finish status: {error}") 

-

310 finally: 

-

311 if conn is not None: 

-

312 conn.close() 

-

313 

-

314 return status 

-

315 

-

316def get_challenge_participants(challenge_id): 

-

317 conn = None 

-

318 try: 

-

319 conn = psycopg2.connect(DATABASE_URL) 

-

320 cur = conn.cursor() 

-

321 

-

322 # SQL query to select challenger_id and challengee_id from the challenges table 

-

323 cur.execute(''' 

-

324 SELECT challenger_id, challengee_id 

-

325 FROM challenges 

-

326 WHERE id = %s; 

-

327 ''', (challenge_id,)) 

-

328 

-

329 result = cur.fetchone() 

-

330 if result: 

-

331 # Unpack the result 

-

332 challenger_id, challengee_id = result 

-

333 participants = { 

-

334 "challenger_id": challenger_id, 

-

335 "challengee_id": challengee_id 

-

336 } 

-

337 return participants 

-

338 else: 

-

339 print("No challenge found with the given ID.") 

-

340 return None 

-

341 

-

342 except (Exception, psycopg2.DatabaseError) as error: 

-

343 print(f"Database error: {error}") 

-

344 return None 

-

345 finally: 

-

346 if conn is not None: 

-

347 conn.close() 

-

348 

-

349#----------------------------------------------------------------------- 

-

350 

-

351def get_challenge_results(challenge_id): 

-

352 conn = None 

-

353 try: 

-

354 conn = psycopg2.connect(DATABASE_URL) 

-

355 cur = conn.cursor() 

-

356 

-

357 # Query to get challenger and challengee points for the given challenge ID 

-

358 cur.execute(''' 

-

359 SELECT challenger_id, challengee_id, challenger_points, challengee_points, challenger_pic_points, challengee_pic_points 

-

360 FROM challenges 

-

361 WHERE id = %s; 

-

362 ''', (challenge_id,)) 

-

363 

-

364 result = cur.fetchone() 

-

365 if result is None: 

-

366 print("Challenge not found.") 

-

367 return 

-

368 

-

369 challenger_id, challengee_id, challenger_points, challengee_points, challenger_pic_points, challengee_pic_points = result 

-

370 

-

371 # Determine the winner or if it's a tie 

-

372 if challenger_points > challengee_points: 

-

373 winner = challenger_id 

-

374 elif challengee_points > challenger_points: 

-

375 winner = challengee_id 

-

376 else: 

-

377 winner = "Tie" 

-

378 

-

379 # Return a dictionary with the results 

-

380 return { 

-

381 "winner": winner, 

-

382 "challenger_id": challenger_id, 

-

383 "challengee_id": challengee_id, 

-

384 "challenger_points": challenger_points, 

-

385 "challengee_points": challengee_points, 

-

386 "challenge_id": challenge_id, 

-

387 "challenger_pic_points": challenger_pic_points, 

-

388 "challengee_pic_points": challengee_pic_points, 

-

389 } 

-

390 

-

391 except (Exception, psycopg2.DatabaseError) as error: 

-

392 print(f"Error: {error}") 

-

393 return {"error": str(error)} 

-

394 finally: 

-

395 if conn is not None: 

-

396 conn.close() 

-

397 

-

398def create_random_versus(): 

-

399 row_count = database.get_table_size('pictures') 

-

400 

-

401 # Generate 5 unique pseudo-random integers from 1 to row_count 

-

402 random_indices = random.sample(range(1, row_count + 1), 5) 

-

403 

-

404 return random_indices 

-

405 

-

406def get_random_versus(challenge_id): 

-

407 conn = None 

-

408 try: 

-

409 conn = psycopg2.connect(DATABASE_URL) 

-

410 cur = conn.cursor() 

-

411 

-

412 # Query to get the versusList for the given challenge ID 

-

413 cur.execute(''' 

-

414 SELECT versusList 

-

415 FROM challenges 

-

416 WHERE id = %s; 

-

417 ''', (challenge_id,)) 

-

418 

-

419 result = cur.fetchone() 

-

420 if result is None: 

-

421 print("Challenge not found.") 

-

422 return 

-

423 

-

424 versusList = result[0] 

-

425 return versusList 

-

426 

-

427 except (Exception, psycopg2.DatabaseError) as error: 

-

428 print(f"Error: {error}") 

-

429 return 

-

430 finally: 

-

431 if conn is not None: 

-

432 conn.close() 

-

433 

-

434def update_playbutton_status(challenge_id, user_id): 

-

435 conn = None 

-

436 try: 

-

437 conn = psycopg2.connect(DATABASE_URL) 

-

438 cur = conn.cursor() 

-

439 

-

440 # First, determine if the user is the challenger or the challengee for this challenge 

-

441 cur.execute(''' 

-

442 SELECT challenger_id, challengee_id 

-

443 FROM challenges 

-

444 WHERE id = %s; 

-

445 ''', (challenge_id,)) 

-

446 

-

447 result = cur.fetchone() 

-

448 if result is None: 

-

449 print("Challenge not found.") 

-

450 return 

-

451 

-

452 challenger_id, challengee_id = result 

-

453 

-

454 # Depending on whether the user is the challenger or the challengee, 

-

455 # update the corresponding finished column in the matches table 

-

456 if user_id == challenger_id: 

-

457 cur.execute(''' 

-

458 UPDATE challenges 

-

459 SET playger_button_status = TRUE 

-

460 WHERE id = %s; 

-

461 ''', (challenge_id,)) 

-

462 elif user_id == challengee_id: 

-

463 cur.execute(''' 

-

464 UPDATE challenges 

-

465 SET playgee_button_status = TRUE 

-

466 WHERE id = %s; 

-

467 ''', (challenge_id,)) 

-

468 else: 

-

469 print("User is not part of this challenge.") 

-

470 return 

-

471 

-

472 conn.commit() 

-

473 print("Play button status updated successfully.") 

-

474 

-

475 except (Exception, psycopg2.DatabaseError) as error: 

-

476 print(f"Error: {error}") 

-

477 finally: 

-

478 if conn is not None: 

-

479 conn.close() 

-

480 

-

481def get_playbutton_status(challenge_id, user_id): 

-

482 conn = None 

-

483 try: 

-

484 conn = psycopg2.connect(DATABASE_URL) 

-

485 cur = conn.cursor() 

-

486 

-

487 # First, determine if the user is the challenger or the challengee for this challenge 

-

488 cur.execute(''' 

-

489 SELECT challenger_id, challengee_id 

-

490 FROM challenges 

-

491 WHERE id = %s; 

-

492 ''', (challenge_id,)) 

-

493 

-

494 result = cur.fetchone() 

-

495 if result is None: 

-

496 print("Challenge not found.") 

-

497 return 

-

498 

-

499 challenger_id, challengee_id = result 

-

500 

-

501 # Depending on whether the user is the challenger or the challengee, 

-

502 # update the corresponding finished column in the matches table 

-

503 if user_id == challenger_id: 

-

504 cur.execute(''' 

-

505 SELECT playger_button_status 

-

506 FROM challenges 

-

507 WHERE id = %s; 

-

508 ''', (challenge_id,)) 

-

509 elif user_id == challengee_id: 

-

510 cur.execute(''' 

-

511 SELECT playgee_button_status 

-

512 FROM challenges 

-

513 WHERE id = %s; 

-

514 ''', (challenge_id,)) 

-

515 else: 

-

516 print("User is not part of this challenge.") 

-

517 return 

-

518 

-

519 result = cur.fetchone() 

-

520 if result is not None: 

-

521 return result[0] 

-

522 else: 

-

523 print("No results found.") 

-

524 return None 

-

525 

-

526 except (Exception, psycopg2.DatabaseError) as error: 

-

527 print(f"Error: {error}") 

-

528 finally: 

-

529 if conn is not None: 

-

530 conn.close() 

-

531 

-

532def main(): 

-

533 #clear_challenges_table() 

-

534 #reset_challenges_id_sequence() 

-

535 print() 

-

536 create_challenge('a', 'ed8205') 

-

537 update_finish_status(1, 'a') 

-

538 

-

539if __name__=="__main__": 

-

540 main() 

-
- - - diff --git a/htmlcov/class_index.html b/htmlcov/class_index.html deleted file mode 100644 index cf33d297..00000000 --- a/htmlcov/class_index.html +++ /dev/null @@ -1,211 +0,0 @@ - - - - - Coverage report - - - - - -
-
-

Coverage report: - 95% -

- -
- -
- - -
-
-

- Files - Functions - Classes -

-

- coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Fileclassstatementsmissingexcludedcoverage
admin.py(no class)6400100%
auth.py(no class)1000100%
challenges_database.py(no class)241096%
cloud.py(no class)61083%
daily_user_database.py(no class)211095%
database.py(no class)111091%
distance_func.py(no class)71086%
matches_database.py(no class)81088%
pictures_database.py(no class)171094%
points.py(no class)91089%
runserver.py(no class)600100%
user_database.py(no class)141093%
versus_database.py(no class)121092%
Total 20910095%
-

- No items found using the specified filter. -

-
- - - diff --git a/htmlcov/cloud_py.html b/htmlcov/cloud_py.html deleted file mode 100644 index 921d5f78..00000000 --- a/htmlcov/cloud_py.html +++ /dev/null @@ -1,152 +0,0 @@ - - - - - Coverage for cloud.py: 23% - - - - - -
-
-

- Coverage for cloud.py: - 23% -

- -

- 22 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1#----------------------------------------------------------------------- 

-

2# cloud.py 

-

3#----------------------------------------------------------------------- 

-

4 

-

5import cloudinary.api 

-

6import json 

-

7 

-

8#----------------------------------------------------------------------- 

-

9 

-

10# extracts the url, latitude, longitude, and place metadata from 

-

11# each image in the cloudinary folder 

-

12def image_data(resource): 

-

13 url = resource['url'] 

-

14 custom_metadata = resource.get('context', {}).get('custom', {}) 

-

15 latitude = float(custom_metadata.get('Latitude')) 

-

16 longitude = float(custom_metadata.get('Longitude')) 

-

17 place = custom_metadata.get('Place') 

-

18 return url, latitude, longitude, place 

-

19 

-

20#----------------------------------------------------------------------- 

-

21 

-

22def main(): 

-

23 

-

24 # configures and connects to cloudinary account 

-

25 cloudinary.config( 

-

26 cloud_name = 'dmiaxw4rr', 

-

27 api_key = '678414952824331', 

-

28 api_secret = 'wt-aWFLd0n-CelO5kN8h1NCYFzY' 

-

29 ) 

-

30 

-

31 # name of folder to extract resources from 

-

32 folder_name = 'TigerSpot/Checked' 

-

33 

-

34 # extracts all resources from folder 

-

35 resources = cloudinary.api.resources( 

-

36 type = 'upload', 

-

37 prefix = folder_name, 

-

38 max_results = 500, 

-

39 context = True 

-

40 ) 

-

41 

-

42 # extracts and writes all image data to picturedata.txt 

-

43 with open('picturedata.txt', 'w') as f: 

-

44 for resource in resources.get('resources', []): 

-

45 url, latitude, longitude, place = image_data(resource) 

-

46 f.write(f"{place}\n") 

-

47 f.write(f"{latitude}, {longitude}\n") 

-

48 f.write(url + '\n\n') 

-

49 

-

50 print("TigerSpot's image data saved to picturedata.txt") 

-

51 

-

52if __name__=="__main__": 

-

53 main() 

-

54 

-

55 

-
- - - diff --git a/htmlcov/coverage_html_cb_da166b87.js b/htmlcov/coverage_html_cb_da166b87.js deleted file mode 100644 index 0a859a53..00000000 --- a/htmlcov/coverage_html_cb_da166b87.js +++ /dev/null @@ -1,717 +0,0 @@ -// Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 -// For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt - -// Coverage.py HTML report browser code. -/*jslint browser: true, sloppy: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */ -/*global coverage: true, document, window, $ */ - -coverage = {}; - -// General helpers -function debounce(callback, wait) { - let timeoutId = null; - return function(...args) { - clearTimeout(timeoutId); - timeoutId = setTimeout(() => { - callback.apply(this, args); - }, wait); - }; -}; - -function checkVisible(element) { - const rect = element.getBoundingClientRect(); - const viewBottom = Math.max(document.documentElement.clientHeight, window.innerHeight); - const viewTop = 30; - return !(rect.bottom < viewTop || rect.top >= viewBottom); -} - -function on_click(sel, fn) { - const elt = document.querySelector(sel); - if (elt) { - elt.addEventListener("click", fn); - } -} - -// Helpers for table sorting -function getCellValue(row, column = 0) { - const cell = row.cells[column] // nosemgrep: eslint.detect-object-injection - if (cell.childElementCount == 1) { - var child = cell.firstElementChild; - if (child.tagName === "A") { - child = child.firstElementChild; - } - if (child instanceof HTMLDataElement && child.value) { - return child.value; - } - } - return cell.innerText || cell.textContent; -} - -function rowComparator(rowA, rowB, column = 0) { - let valueA = getCellValue(rowA, column); - let valueB = getCellValue(rowB, column); - if (!isNaN(valueA) && !isNaN(valueB)) { - return valueA - valueB; - } - return valueA.localeCompare(valueB, undefined, {numeric: true}); -} - -function sortColumn(th) { - // Get the current sorting direction of the selected header, - // clear state on other headers and then set the new sorting direction. - const currentSortOrder = th.getAttribute("aria-sort"); - [...th.parentElement.cells].forEach(header => header.setAttribute("aria-sort", "none")); - var direction; - if (currentSortOrder === "none") { - direction = th.dataset.defaultSortOrder || "ascending"; - } - else if (currentSortOrder === "ascending") { - direction = "descending"; - } - else { - direction = "ascending"; - } - th.setAttribute("aria-sort", direction); - - const column = [...th.parentElement.cells].indexOf(th) - - // Sort all rows and afterwards append them in order to move them in the DOM. - Array.from(th.closest("table").querySelectorAll("tbody tr")) - .sort((rowA, rowB) => rowComparator(rowA, rowB, column) * (direction === "ascending" ? 1 : -1)) - .forEach(tr => tr.parentElement.appendChild(tr)); - - // Save the sort order for next time. - if (th.id !== "region") { - let th_id = "file"; // Sort by file if we don't have a column id - let current_direction = direction; - const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE); - if (stored_list) { - ({th_id, direction} = JSON.parse(stored_list)) - } - localStorage.setItem(coverage.INDEX_SORT_STORAGE, JSON.stringify({ - "th_id": th.id, - "direction": current_direction - })); - if (th.id !== th_id || document.getElementById("region")) { - // Sort column has changed, unset sorting by function or class. - localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({ - "by_region": false, - "region_direction": current_direction - })); - } - } - else { - // Sort column has changed to by function or class, remember that. - localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({ - "by_region": true, - "region_direction": direction - })); - } -} - -// Find all the elements with data-shortcut attribute, and use them to assign a shortcut key. -coverage.assign_shortkeys = function () { - document.querySelectorAll("[data-shortcut]").forEach(element => { - document.addEventListener("keypress", event => { - if (event.target.tagName.toLowerCase() === "input") { - return; // ignore keypress from search filter - } - if (event.key === element.dataset.shortcut) { - element.click(); - } - }); - }); -}; - -// Create the events for the filter box. -coverage.wire_up_filter = function () { - // Cache elements. - const table = document.querySelector("table.index"); - const table_body_rows = table.querySelectorAll("tbody tr"); - const no_rows = document.getElementById("no_rows"); - - // Observe filter keyevents. - const filter_handler = (event => { - // Keep running total of each metric, first index contains number of shown rows - const totals = new Array(table.rows[0].cells.length).fill(0); - // Accumulate the percentage as fraction - totals[totals.length - 1] = { "numer": 0, "denom": 0 }; // nosemgrep: eslint.detect-object-injection - - var text = document.getElementById("filter").value; - const casefold = (text === text.toLowerCase()); - const hide100 = document.getElementById("hide100").checked; - - // Hide / show elements. - table_body_rows.forEach(row => { - var show = false; - // Check the text filter. - for (let column = 0; column < totals.length; column++) { - cell = row.cells[column]; - if (cell.classList.contains("name")) { - var celltext = cell.textContent; - if (casefold) { - celltext = celltext.toLowerCase(); - } - if (celltext.includes(text)) { - show = true; - } - } - } - - // Check the "hide covered" filter. - if (show && hide100) { - const [numer, denom] = row.cells[row.cells.length - 1].dataset.ratio.split(" "); - show = (numer !== denom); - } - - if (!show) { - // hide - row.classList.add("hidden"); - return; - } - - // show - row.classList.remove("hidden"); - totals[0]++; - - for (let column = 0; column < totals.length; column++) { - // Accumulate dynamic totals - cell = row.cells[column] // nosemgrep: eslint.detect-object-injection - if (cell.classList.contains("name")) { - continue; - } - if (column === totals.length - 1) { - // Last column contains percentage - const [numer, denom] = cell.dataset.ratio.split(" "); - totals[column]["numer"] += parseInt(numer, 10); // nosemgrep: eslint.detect-object-injection - totals[column]["denom"] += parseInt(denom, 10); // nosemgrep: eslint.detect-object-injection - } - else { - totals[column] += parseInt(cell.textContent, 10); // nosemgrep: eslint.detect-object-injection - } - } - }); - - // Show placeholder if no rows will be displayed. - if (!totals[0]) { - // Show placeholder, hide table. - no_rows.style.display = "block"; - table.style.display = "none"; - return; - } - - // Hide placeholder, show table. - no_rows.style.display = null; - table.style.display = null; - - const footer = table.tFoot.rows[0]; - // Calculate new dynamic sum values based on visible rows. - for (let column = 0; column < totals.length; column++) { - // Get footer cell element. - const cell = footer.cells[column]; // nosemgrep: eslint.detect-object-injection - if (cell.classList.contains("name")) { - continue; - } - - // Set value into dynamic footer cell element. - if (column === totals.length - 1) { - // Percentage column uses the numerator and denominator, - // and adapts to the number of decimal places. - const match = /\.([0-9]+)/.exec(cell.textContent); - const places = match ? match[1].length : 0; - const { numer, denom } = totals[column]; // nosemgrep: eslint.detect-object-injection - cell.dataset.ratio = `${numer} ${denom}`; - // Check denom to prevent NaN if filtered files contain no statements - cell.textContent = denom - ? `${(numer * 100 / denom).toFixed(places)}%` - : `${(100).toFixed(places)}%`; - } - else { - cell.textContent = totals[column]; // nosemgrep: eslint.detect-object-injection - } - } - }); - - document.getElementById("filter").addEventListener("input", debounce(filter_handler)); - document.getElementById("hide100").addEventListener("input", debounce(filter_handler)); - - // Trigger change event on setup, to force filter on page refresh - // (filter value may still be present). - document.getElementById("filter").dispatchEvent(new Event("input")); - document.getElementById("hide100").dispatchEvent(new Event("input")); -}; - -// Set up the click-to-sort columns. -coverage.wire_up_sorting = function () { - document.querySelectorAll("[data-sortable] th[aria-sort]").forEach( - th => th.addEventListener("click", e => sortColumn(e.target)) - ); - - // Look for a localStorage item containing previous sort settings: - let th_id = "file", direction = "ascending"; - const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE); - if (stored_list) { - ({th_id, direction} = JSON.parse(stored_list)); - } - let by_region = false, region_direction = "ascending"; - const sorted_by_region = localStorage.getItem(coverage.SORTED_BY_REGION); - if (sorted_by_region) { - ({ - by_region, - region_direction - } = JSON.parse(sorted_by_region)); - } - - const region_id = "region"; - if (by_region && document.getElementById(region_id)) { - direction = region_direction; - } - // If we are in a page that has a column with id of "region", sort on - // it if the last sort was by function or class. - let th; - if (document.getElementById(region_id)) { - th = document.getElementById(by_region ? region_id : th_id); - } - else { - th = document.getElementById(th_id); - } - th.setAttribute("aria-sort", direction === "ascending" ? "descending" : "ascending"); - th.click() -}; - -coverage.INDEX_SORT_STORAGE = "COVERAGE_INDEX_SORT_2"; -coverage.SORTED_BY_REGION = "COVERAGE_SORT_REGION"; - -// Loaded on index.html -coverage.index_ready = function () { - coverage.assign_shortkeys(); - coverage.wire_up_filter(); - coverage.wire_up_sorting(); - - on_click(".button_prev_file", coverage.to_prev_file); - on_click(".button_next_file", coverage.to_next_file); - - on_click(".button_show_hide_help", coverage.show_hide_help); -}; - -// -- pyfile stuff -- - -coverage.LINE_FILTERS_STORAGE = "COVERAGE_LINE_FILTERS"; - -coverage.pyfile_ready = function () { - // If we're directed to a particular line number, highlight the line. - var frag = location.hash; - if (frag.length > 2 && frag[1] === "t") { - document.querySelector(frag).closest(".n").classList.add("highlight"); - coverage.set_sel(parseInt(frag.substr(2), 10)); - } - else { - coverage.set_sel(0); - } - - on_click(".button_toggle_run", coverage.toggle_lines); - on_click(".button_toggle_mis", coverage.toggle_lines); - on_click(".button_toggle_exc", coverage.toggle_lines); - on_click(".button_toggle_par", coverage.toggle_lines); - - on_click(".button_next_chunk", coverage.to_next_chunk_nicely); - on_click(".button_prev_chunk", coverage.to_prev_chunk_nicely); - on_click(".button_top_of_page", coverage.to_top); - on_click(".button_first_chunk", coverage.to_first_chunk); - - on_click(".button_prev_file", coverage.to_prev_file); - on_click(".button_next_file", coverage.to_next_file); - on_click(".button_to_index", coverage.to_index); - - on_click(".button_show_hide_help", coverage.show_hide_help); - - coverage.filters = undefined; - try { - coverage.filters = localStorage.getItem(coverage.LINE_FILTERS_STORAGE); - } catch(err) {} - - if (coverage.filters) { - coverage.filters = JSON.parse(coverage.filters); - } - else { - coverage.filters = {run: false, exc: true, mis: true, par: true}; - } - - for (cls in coverage.filters) { - coverage.set_line_visibilty(cls, coverage.filters[cls]); // nosemgrep: eslint.detect-object-injection - } - - coverage.assign_shortkeys(); - coverage.init_scroll_markers(); - coverage.wire_up_sticky_header(); - - document.querySelectorAll("[id^=ctxs]").forEach( - cbox => cbox.addEventListener("click", coverage.expand_contexts) - ); - - // Rebuild scroll markers when the window height changes. - window.addEventListener("resize", coverage.build_scroll_markers); -}; - -coverage.toggle_lines = function (event) { - const btn = event.target.closest("button"); - const category = btn.value - const show = !btn.classList.contains("show_" + category); - coverage.set_line_visibilty(category, show); - coverage.build_scroll_markers(); - coverage.filters[category] = show; - try { - localStorage.setItem(coverage.LINE_FILTERS_STORAGE, JSON.stringify(coverage.filters)); - } catch(err) {} -}; - -coverage.set_line_visibilty = function (category, should_show) { - const cls = "show_" + category; - const btn = document.querySelector(".button_toggle_" + category); - if (btn) { - if (should_show) { - document.querySelectorAll("#source ." + category).forEach(e => e.classList.add(cls)); - btn.classList.add(cls); - } - else { - document.querySelectorAll("#source ." + category).forEach(e => e.classList.remove(cls)); - btn.classList.remove(cls); - } - } -}; - -// Return the nth line div. -coverage.line_elt = function (n) { - return document.getElementById("t" + n)?.closest("p"); -}; - -// Set the selection. b and e are line numbers. -coverage.set_sel = function (b, e) { - // The first line selected. - coverage.sel_begin = b; - // The next line not selected. - coverage.sel_end = (e === undefined) ? b+1 : e; -}; - -coverage.to_top = function () { - coverage.set_sel(0, 1); - coverage.scroll_window(0); -}; - -coverage.to_first_chunk = function () { - coverage.set_sel(0, 1); - coverage.to_next_chunk(); -}; - -coverage.to_prev_file = function () { - window.location = document.getElementById("prevFileLink").href; -} - -coverage.to_next_file = function () { - window.location = document.getElementById("nextFileLink").href; -} - -coverage.to_index = function () { - location.href = document.getElementById("indexLink").href; -} - -coverage.show_hide_help = function () { - const helpCheck = document.getElementById("help_panel_state") - helpCheck.checked = !helpCheck.checked; -} - -// Return a string indicating what kind of chunk this line belongs to, -// or null if not a chunk. -coverage.chunk_indicator = function (line_elt) { - const classes = line_elt?.className; - if (!classes) { - return null; - } - const match = classes.match(/\bshow_\w+\b/); - if (!match) { - return null; - } - return match[0]; -}; - -coverage.to_next_chunk = function () { - const c = coverage; - - // Find the start of the next colored chunk. - var probe = c.sel_end; - var chunk_indicator, probe_line; - while (true) { - probe_line = c.line_elt(probe); - if (!probe_line) { - return; - } - chunk_indicator = c.chunk_indicator(probe_line); - if (chunk_indicator) { - break; - } - probe++; - } - - // There's a next chunk, `probe` points to it. - var begin = probe; - - // Find the end of this chunk. - var next_indicator = chunk_indicator; - while (next_indicator === chunk_indicator) { - probe++; - probe_line = c.line_elt(probe); - next_indicator = c.chunk_indicator(probe_line); - } - c.set_sel(begin, probe); - c.show_selection(); -}; - -coverage.to_prev_chunk = function () { - const c = coverage; - - // Find the end of the prev colored chunk. - var probe = c.sel_begin-1; - var probe_line = c.line_elt(probe); - if (!probe_line) { - return; - } - var chunk_indicator = c.chunk_indicator(probe_line); - while (probe > 1 && !chunk_indicator) { - probe--; - probe_line = c.line_elt(probe); - if (!probe_line) { - return; - } - chunk_indicator = c.chunk_indicator(probe_line); - } - - // There's a prev chunk, `probe` points to its last line. - var end = probe+1; - - // Find the beginning of this chunk. - var prev_indicator = chunk_indicator; - while (prev_indicator === chunk_indicator) { - probe--; - if (probe <= 0) { - return; - } - probe_line = c.line_elt(probe); - prev_indicator = c.chunk_indicator(probe_line); - } - c.set_sel(probe+1, end); - c.show_selection(); -}; - -// Returns 0, 1, or 2: how many of the two ends of the selection are on -// the screen right now? -coverage.selection_ends_on_screen = function () { - if (coverage.sel_begin === 0) { - return 0; - } - - const begin = coverage.line_elt(coverage.sel_begin); - const end = coverage.line_elt(coverage.sel_end-1); - - return ( - (checkVisible(begin) ? 1 : 0) - + (checkVisible(end) ? 1 : 0) - ); -}; - -coverage.to_next_chunk_nicely = function () { - if (coverage.selection_ends_on_screen() === 0) { - // The selection is entirely off the screen: - // Set the top line on the screen as selection. - - // This will select the top-left of the viewport - // As this is most likely the span with the line number we take the parent - const line = document.elementFromPoint(0, 0).parentElement; - if (line.parentElement !== document.getElementById("source")) { - // The element is not a source line but the header or similar - coverage.select_line_or_chunk(1); - } - else { - // We extract the line number from the id - coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10)); - } - } - coverage.to_next_chunk(); -}; - -coverage.to_prev_chunk_nicely = function () { - if (coverage.selection_ends_on_screen() === 0) { - // The selection is entirely off the screen: - // Set the lowest line on the screen as selection. - - // This will select the bottom-left of the viewport - // As this is most likely the span with the line number we take the parent - const line = document.elementFromPoint(document.documentElement.clientHeight-1, 0).parentElement; - if (line.parentElement !== document.getElementById("source")) { - // The element is not a source line but the header or similar - coverage.select_line_or_chunk(coverage.lines_len); - } - else { - // We extract the line number from the id - coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10)); - } - } - coverage.to_prev_chunk(); -}; - -// Select line number lineno, or if it is in a colored chunk, select the -// entire chunk -coverage.select_line_or_chunk = function (lineno) { - var c = coverage; - var probe_line = c.line_elt(lineno); - if (!probe_line) { - return; - } - var the_indicator = c.chunk_indicator(probe_line); - if (the_indicator) { - // The line is in a highlighted chunk. - // Search backward for the first line. - var probe = lineno; - var indicator = the_indicator; - while (probe > 0 && indicator === the_indicator) { - probe--; - probe_line = c.line_elt(probe); - if (!probe_line) { - break; - } - indicator = c.chunk_indicator(probe_line); - } - var begin = probe + 1; - - // Search forward for the last line. - probe = lineno; - indicator = the_indicator; - while (indicator === the_indicator) { - probe++; - probe_line = c.line_elt(probe); - indicator = c.chunk_indicator(probe_line); - } - - coverage.set_sel(begin, probe); - } - else { - coverage.set_sel(lineno); - } -}; - -coverage.show_selection = function () { - // Highlight the lines in the chunk - document.querySelectorAll("#source .highlight").forEach(e => e.classList.remove("highlight")); - for (let probe = coverage.sel_begin; probe < coverage.sel_end; probe++) { - coverage.line_elt(probe).querySelector(".n").classList.add("highlight"); - } - - coverage.scroll_to_selection(); -}; - -coverage.scroll_to_selection = function () { - // Scroll the page if the chunk isn't fully visible. - if (coverage.selection_ends_on_screen() < 2) { - const element = coverage.line_elt(coverage.sel_begin); - coverage.scroll_window(element.offsetTop - 60); - } -}; - -coverage.scroll_window = function (to_pos) { - window.scroll({top: to_pos, behavior: "smooth"}); -}; - -coverage.init_scroll_markers = function () { - // Init some variables - coverage.lines_len = document.querySelectorAll("#source > p").length; - - // Build html - coverage.build_scroll_markers(); -}; - -coverage.build_scroll_markers = function () { - const temp_scroll_marker = document.getElementById("scroll_marker") - if (temp_scroll_marker) temp_scroll_marker.remove(); - // Don't build markers if the window has no scroll bar. - if (document.body.scrollHeight <= window.innerHeight) { - return; - } - - const marker_scale = window.innerHeight / document.body.scrollHeight; - const line_height = Math.min(Math.max(3, window.innerHeight / coverage.lines_len), 10); - - let previous_line = -99, last_mark, last_top; - - const scroll_marker = document.createElement("div"); - scroll_marker.id = "scroll_marker"; - document.getElementById("source").querySelectorAll( - "p.show_run, p.show_mis, p.show_exc, p.show_exc, p.show_par" - ).forEach(element => { - const line_top = Math.floor(element.offsetTop * marker_scale); - const line_number = parseInt(element.querySelector(".n a").id.substr(1)); - - if (line_number === previous_line + 1) { - // If this solid missed block just make previous mark higher. - last_mark.style.height = `${line_top + line_height - last_top}px`; - } - else { - // Add colored line in scroll_marker block. - last_mark = document.createElement("div"); - last_mark.id = `m${line_number}`; - last_mark.classList.add("marker"); - last_mark.style.height = `${line_height}px`; - last_mark.style.top = `${line_top}px`; - scroll_marker.append(last_mark); - last_top = line_top; - } - - previous_line = line_number; - }); - - // Append last to prevent layout calculation - document.body.append(scroll_marker); -}; - -coverage.wire_up_sticky_header = function () { - const header = document.querySelector("header"); - const header_bottom = ( - header.querySelector(".content h2").getBoundingClientRect().top - - header.getBoundingClientRect().top - ); - - function updateHeader() { - if (window.scrollY > header_bottom) { - header.classList.add("sticky"); - } - else { - header.classList.remove("sticky"); - } - } - - window.addEventListener("scroll", updateHeader); - updateHeader(); -}; - -coverage.expand_contexts = function (e) { - var ctxs = e.target.parentNode.querySelector(".ctxs"); - - if (!ctxs.classList.contains("expanded")) { - var ctxs_text = ctxs.textContent; - var width = Number(ctxs_text[0]); - ctxs.textContent = ""; - for (var i = 1; i < ctxs_text.length; i += width) { - key = ctxs_text.substring(i, i + width).trim(); - ctxs.appendChild(document.createTextNode(contexts[key])); - ctxs.appendChild(document.createElement("br")); - } - ctxs.classList.add("expanded"); - } -}; - -document.addEventListener("DOMContentLoaded", () => { - if (document.body.classList.contains("indexfile")) { - coverage.index_ready(); - } - else { - coverage.pyfile_ready(); - } -}); diff --git a/htmlcov/daily_user_database_py.html b/htmlcov/daily_user_database_py.html deleted file mode 100644 index 3f054bb8..00000000 --- a/htmlcov/daily_user_database_py.html +++ /dev/null @@ -1,474 +0,0 @@ - - - - - Coverage for daily_user_database.py: 11% - - - - - -
-
-

- Coverage for daily_user_database.py: - 11% -

- -

- 183 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1#----------------------------------------------------------------------- 

-

2# daily_user_database.py 

-

3#----------------------------------------------------------------------- 

-

4 

-

5import psycopg2 

-

6import database 

-

7 

-

8#----------------------------------------------------------------------- 

-

9 

-

10DATABASE_URL = 'postgres://tigerspot_user:9WtP1U9PRdh1VLlP4VdwnT0BFSdbrPWk@dpg-cnrjs7q1hbls73e04390-a.ohio-postgres.render.com/tigerspot' 

-

11 

-

12#----------------------------------------------------------------------- 

-

13 

-

14# Creates usersDaily table with columns username, points, distance, 

-

15# played, last_played, last_versus, and current streak. 

-

16 

-

17def create_daily_user_table(): 

-

18 

-

19 try: 

-

20 with psycopg2.connect(DATABASE_URL) as conn: 

-

21 with conn.cursor() as cur: 

-

22 cur.execute('''CREATE TABLE IF NOT EXISTS usersDaily ( 

-

23 username varchar(255), 

-

24 points int, 

-

25 distance int, 

-

26 played boolean, 

-

27 last_played date, 

-

28 last_versus date, 

-

29 current_streak int);''') 

-

30 conn.commit() 

-

31 

-

32 except (Exception, psycopg2.DatabaseError) as error: 

-

33 print(error) 

-

34 return "database error" 

-

35 

-

36#----------------------------------------------------------------------- 

-

37 

-

38# Inserts username into usersDaily table. 

-

39 

-

40def insert_player_daily(username): 

-

41 

-

42 try: 

-

43 with psycopg2.connect(DATABASE_URL) as conn: 

-

44 with conn.cursor() as cur: 

-

45 

-

46 cur.execute("SELECT points FROM usersDaily WHERE username=%s;", (username,)) 

-

47 result = cur.fetchone() 

-

48 

-

49 if result is None: 

-

50 cur.execute("INSERT INTO usersDaily (username, points, distance, played, last_played, last_versus, current_streak) VALUES (%s, %s, %s, %s, NULL, NULL, %s);", (username, 0, 0, False, 0)) 

-

51 

-

52 conn.commit() 

-

53 

-

54 return "success" 

-

55 

-

56 except (Exception, psycopg2.DatabaseError) as error: 

-

57 print(error) 

-

58 return "database error" 

-

59 

-

60 

-

61#----------------------------------------------------------------------- 

-

62 

-

63# Updates username's daily stats with new points and distance. 

-

64# Updates that username has played at current date and updates streaks. 

-

65 

-

66def update_player_daily(username, points, distance): 

-

67 

-

68 try: 

-

69 with psycopg2.connect(DATABASE_URL) as conn: 

-

70 with conn.cursor() as cur: 

-

71 

-

72 cur.execute("SET TIME ZONE 'America/New_York';") 

-

73 

-

74 cur.execute('''UPDATE usersDaily 

-

75 SET  

-

76 points=%s, 

-

77 distance=%s, 

-

78 played=%s, 

-

79 current_streak = CASE 

-

80 WHEN last_played IS NULL THEN 1  

-

81 WHEN last_played::date = (CURRENT_DATE - INTERVAL '1 day')::date THEN current_streak + 1  

-

82 ELSE 1 

-

83 END,  

-

84 last_played= CURRENT_DATE 

-

85 WHERE username=%s;''', (points, distance, True, username)) 

-

86 conn.commit() 

-

87 

-

88 return "success" 

-

89 

-

90 except (Exception, psycopg2.DatabaseError) as error: 

-

91 print(error) 

-

92 return "database error" 

-

93 

-

94#----------------------------------------------------------------------- 

-

95 

-

96# Updates username's last_versus to current date. 

-

97 

-

98def update_player_versus(username): 

-

99 

-

100 try: 

-

101 with psycopg2.connect(DATABASE_URL) as conn: 

-

102 with conn.cursor() as cur: 

-

103 

-

104 cur.execute("SET TIME ZONE 'America/New_York';") 

-

105 

-

106 cur.execute('''UPDATE usersDaily 

-

107 SET  

-

108 last_versus= CURRENT_DATE 

-

109 WHERE username=%s;''', (username, )) 

-

110 conn.commit() 

-

111 print(f"UPDATED VERSUS DATE IN DAILY") 

-

112 

-

113 return "success" 

-

114 

-

115 except (Exception, psycopg2.DatabaseError) as error: 

-

116 print(error) 

-

117 return "database error" 

-

118 

-

119#----------------------------------------------------------------------- 

-

120 

-

121# Returns whether username has played for the day or not. 

-

122 

-

123def player_played(username): 

-

124 

-

125 try: 

-

126 with psycopg2.connect(DATABASE_URL) as conn: 

-

127 with conn.cursor() as cur: 

-

128 

-

129 cur.execute("SELECT played FROM usersDaily WHERE username=%s;", (username, )) 

-

130 result = cur.fetchall()[0][0] 

-

131 

-

132 return result 

-

133 

-

134 except (Exception, psycopg2.DatabaseError) as error: 

-

135 print(error) 

-

136 return "database error" 

-

137 

-

138 

-

139#----------------------------------------------------------------------- 

-

140 

-

141# Resets the user's daily points, distance, and if they have played. 

-

142 

-

143def reset_player(username): 

-

144 

-

145 try: 

-

146 with psycopg2.connect(DATABASE_URL) as conn: 

-

147 with conn.cursor() as cur: 

-

148 cur.execute("UPDATE usersDaily SET played=%s, points=%s, distance=%s WHERE username=%s;", (False, 0, 0, username)) 

-

149 print(f"Player {username} has been reset for the daily round") 

-

150 conn.commit() 

-

151 

-

152 return "success" 

-

153 

-

154 except (Exception, psycopg2.DatabaseError) as error: 

-

155 print(error) 

-

156 return "database error" 

-

157 

-

158#----------------------------------------------------------------------- 

-

159 

-

160# Resets all players' daily points, distance, and if they have played.  

-

161 

-

162def reset_players(): 

-

163 

-

164 try: 

-

165 with psycopg2.connect(DATABASE_URL) as conn: 

-

166 with conn.cursor() as cur: 

-

167 cur.execute("UPDATE usersDaily SET played=%s, points=%s, distance=%s, last_played=NULL, current_streak = %s;", (False, 0, 0, 0)) 

-

168 conn.commit() 

-

169 

-

170 return "success" 

-

171 

-

172 except (Exception, psycopg2.DatabaseError) as error: 

-

173 print(error) 

-

174 return "database error" 

-

175 

-

176#----------------------------------------------------------------------- 

-

177 

-

178# Returns the date when the username last played. 

-

179 

-

180def get_last_played_date(username): 

-

181 

-

182 try: 

-

183 with psycopg2.connect(DATABASE_URL) as conn: 

-

184 with conn.cursor() as cur: 

-

185 cur.execute('''SELECT last_played FROM usersDaily WHERE username=%s;''', (username,)) 

-

186 date = cur.fetchone() 

-

187 

-

188 if date is None: 

-

189 return 0 

-

190 

-

191 return date[0] 

-

192 

-

193 except (Exception, psycopg2.DatabaseError) as error: 

-

194 print(error) 

-

195 return "database error" 

-

196 

-

197#----------------------------------------------------------------------- 

-

198 

-

199# Returns the date when the username last used the versus mode. 

-

200 

-

201def get_last_versus_date(username): 

-

202 

-

203 try: 

-

204 with psycopg2.connect(DATABASE_URL) as conn: 

-

205 with conn.cursor() as cur: 

-

206 cur.execute('''SELECT last_versus FROM usersDaily WHERE username=%s;''', (username,)) 

-

207 date = cur.fetchone() 

-

208 

-

209 if date is None: 

-

210 return 0 

-

211 

-

212 return date[0] 

-

213 

-

214 except (Exception, psycopg2.DatabaseError) as error: 

-

215 print(error) 

-

216 return "database error" 

-

217 

-

218#----------------------------------------------------------------------- 

-

219 

-

220# Returns username's streak. 

-

221 

-

222def get_streak(username): 

-

223 

-

224 try: 

-

225 with psycopg2.connect(DATABASE_URL) as conn: 

-

226 with conn.cursor() as cur: 

-

227 cur.execute('''SELECT current_streak FROM usersDaily WHERE username=%s;''', (username,)) 

-

228 streak = cur.fetchone() 

-

229 

-

230 if streak is None: 

-

231 return 0 

-

232 

-

233 return streak[0] 

-

234 

-

235 except (Exception, psycopg2.DatabaseError) as error: 

-

236 print(error) 

-

237 return "database error" 

-

238 

-

239#----------------------------------------------------------------------- 

-

240 

-

241# Returns username's daily points. 

-

242 

-

243def get_daily_points(username): 

-

244 

-

245 try: 

-

246 with psycopg2.connect(DATABASE_URL) as conn: 

-

247 with conn.cursor() as cur: 

-

248 cur.execute('''SELECT points FROM usersDaily WHERE username=%s;''', (username,)) 

-

249 points = cur.fetchone() 

-

250 

-

251 if points is None: 

-

252 return 0 

-

253 

-

254 return points[0] 

-

255 

-

256 except (Exception, psycopg2.DatabaseError) as error: 

-

257 print(error) 

-

258 return "database error" 

-

259 

-

260#----------------------------------------------------------------------- 

-

261 

-

262# Returns username's guess distance.  

-

263 

-

264def get_daily_distance(username): 

-

265 

-

266 try: 

-

267 with psycopg2.connect(DATABASE_URL) as conn: 

-

268 with conn.cursor() as cur: 

-

269 cur.execute('''SELECT distance FROM usersDaily WHERE username=%s;''', (username,)) 

-

270 distance = cur.fetchone() 

-

271 

-

272 if distance is None: 

-

273 return 0 

-

274 

-

275 return distance[0] 

-

276 

-

277 except (Exception, psycopg2.DatabaseError) as error: 

-

278 print(error) 

-

279 return "database error" 

-

280 

-

281#----------------------------------------------------------------------- 

-

282 

-

283# Returns a dictionary of the usernames and points of the the top 10 

-

284# scoring players for the day. 

-

285 

-

286def get_daily_top_players(): 

-

287 

-

288 try: 

-

289 with psycopg2.connect(DATABASE_URL) as conn: 

-

290 with conn.cursor() as cur: 

-

291 daily_top_players = [] 

-

292 cur.execute("SET TIME ZONE 'America/New_York';") 

-

293 cur.execute("SELECT username, points FROM usersDaily WHERE last_played = CURRENT_DATE ORDER BY points DESC, username ASC LIMIT 10;") 

-

294 table = cur.fetchall() 

-

295 for row in table: 

-

296 username, points = row 

-

297 player_stats = {'username': username, 'points': points} 

-

298 daily_top_players.append(player_stats) 

-

299 

-

300 return daily_top_players 

-

301 

-

302 except (Exception, psycopg2.DatabaseError) as error: 

-

303 print(error) 

-

304 return "database error" 

-

305 

-

306#----------------------------------------------------------------------- 

-

307 

-

308# Returns username's daily rank among all players who played for the day. 

-

309 

-

310def get_daily_rank(username): 

-

311 

-

312 try: 

-

313 with psycopg2.connect(DATABASE_URL) as conn: 

-

314 with conn.cursor() as cur: 

-

315 cur.execute("SET TIME ZONE 'America/New_York';") 

-

316 cur.execute("SELECT username, points, DENSE_RANK() OVER (ORDER BY points DESC, username ASC) as rank FROM usersDaily WHERE last_played = CURRENT_DATE;") 

-

317 players = cur.fetchall() 

-

318 

-

319 for player in players: 

-

320 if player[0] == username: 

-

321 return player[2] 

-

322 return "Play Today's Game!" 

-

323 

-

324 except (Exception, psycopg2.DatabaseError) as error: 

-

325 print(error) 

-

326 return "database error" 

-

327 

-

328#----------------------------------------------------------------------- 

-

329 

-

330# Removes username from the usersDaily table. 

-

331 

-

332def remove_daily_user(username): 

-

333 try: 

-

334 with psycopg2.connect(DATABASE_URL) as conn: 

-

335 with conn.cursor() as cur: 

-

336 

-

337 cur.execute("DELETE FROM usersDaily WHERE username=%s;", (username,)) 

-

338 conn.commit() 

-

339 

-

340 return "success" 

-

341 

-

342 except (Exception, psycopg2.DatabaseError) as error: 

-

343 print(error) 

-

344 return "database error" 

-

345 

-

346#----------------------------------------------------------------------- 

-

347 

-

348def main(): 

-

349 

-

350 #database.drop_table("usersDaily") 

-

351 # update_player_daily('wn4759', 100, 30) 

-

352 #reset_player('cl7359') 

-

353 #reset_player('jy3107') 

-

354 #reset_player('fl9971') 

-

355 #print(get_last_played_date('fl9971')) 

-

356 #reset_player('wn4759') 

-

357 #reset_player('ed8205') 

-

358 # remove_daily_user('fl9971') 

-

359 #reset_player('jy1365') 

-

360 #create_daily_user_table() 

-

361 date = get_last_played_date('fl9971') 

-

362 # print(date) 

-

363 # streak = get_streak('fl9971') 

-

364 # print(streak) 

-

365 # date1 = get_last_played_date('cl7359') 

-

366 # print(date1) 

-

367 

-

368 # print(get_last_versus_date('wn4759')) 

-

369 #update_player_versus('wn4759') 

-

370 

-

371 #remove_daily_user('wn4759') 

-

372 

-

373#----------------------------------------------------------------------- 

-

374 

-

375if __name__=="__main__": 

-

376 

-

377 main() 

-
- - - diff --git a/htmlcov/database_py.html b/htmlcov/database_py.html deleted file mode 100644 index a2670f0a..00000000 --- a/htmlcov/database_py.html +++ /dev/null @@ -1,206 +0,0 @@ - - - - - Coverage for database.py: 12% - - - - - -
-
-

- Coverage for database.py: - 12% -

- -

- 81 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1#----------------------------------------------------------------------- 

-

2# database.py 

-

3# This file is for general actions with tables 

-

4# Tables in Tiger Spot: pictures, users, usersDaily, challenges, matches 

-

5#----------------------------------------------------------------------- 

-

6import psycopg2 

-

7#----------------------------------------------------------------------- 

-

8 

-

9DATABASE_URL = 'postgres://tigerspot_user:9WtP1U9PRdh1VLlP4VdwnT0BFSdbrPWk@dpg-cnrjs7q1hbls73e04390-a.ohio-postgres.render.com/tigerspot' 

-

10 

-

11#----------------------------------------------------------------------- 

-

12#drops a specified table 

-

13def drop_table(table): 

-

14 try: 

-

15 with psycopg2.connect(DATABASE_URL) as conn: 

-

16 with conn.cursor() as cur: 

-

17 cur.execute("DROP TABLE %s;" % (table)) 

-

18 conn.commit() 

-

19 print(f"{table} has been dropped") 

-

20 except (Exception, psycopg2.DatabaseError) as error: 

-

21 print(error) 

-

22 return "database error" 

-

23 

-

24#updates a specific row in a table 

-

25#id_type can be pictureID or challenge_id for example 

-

26def update(table, col, value, id_type, id_num): 

-

27 try: 

-

28 with psycopg2.connect(DATABASE_URL) as conn: 

-

29 with conn.cursor() as cur: 

-

30 cur.execute("UPDATE %s SET %s = %s WHERE %s = %s;" % (table, col, value, id_type, id_num)) 

-

31 print(f"Updated with value as {value}") 

-

32 conn.commit() 

-

33 except (Exception, psycopg2.DatabaseError) as error: 

-

34 print(error) 

-

35 return "database error" 

-

36 

-

37#returns all the values from a specified column in a table in the form of an array of tuples 

-

38def query(column, table): 

-

39 try: 

-

40 with psycopg2.connect(DATABASE_URL) as conn: 

-

41 with conn.cursor() as cur: 

-

42 cur.execute("SELECT %s FROM %s" % (column, table)) 

-

43 rows = cur.fetchall() 

-

44 print(f"Returning values in column '{column}' from table '{table}'") 

-

45 return rows 

-

46 except (Exception, psycopg2.DatabaseError) as error: 

-

47 print(error) 

-

48 return "database error" 

-

49 

-

50#Returns the number of rows in a table 

-

51def get_table_size(table): 

-

52 try: 

-

53 with psycopg2.connect(DATABASE_URL) as conn: 

-

54 with conn.cursor() as cur: 

-

55 cur.execute("SELECT COUNT(*) FROM %s;" % (table)) 

-

56 print(f"Returning number of rows in table '{table}'") 

-

57 result = cur.fetchone() 

-

58 pic_num = result[0] 

-

59 return pic_num 

-

60 except (Exception, psycopg2.DatabaseError) as error: 

-

61 print(error) 

-

62 return "database error" 

-

63 

-

64#prints out all rows in the users, usersDaily, pictures, challenges, and matches tables 

-

65def show_rows(): 

-

66 print("Showing all rows in users, usersDaily, pictures, challenges, and matches tables") 

-

67 print() 

-

68 print("USERS TABLE") 

-

69 print(query("*", "users")) 

-

70 print() 

-

71 print("DAILY USERS TABLE") 

-

72 print(query("*", "usersDaily")) 

-

73 print() 

-

74 print("PICTURES TABLE") 

-

75 print(query("*", "pictures")) 

-

76 print() 

-

77 print("CHALLENGES TABLE") 

-

78 print(query("*", "challenges")) 

-

79 print() 

-

80 print("MATCHES TABLE") 

-

81 print(query("*", "matches")) 

-

82 print() 

-

83 

-

84#----------------------------------------------------------------------- 

-

85#tests the above functions that do not commit changes to the tables 

-

86def testing(): 

-

87 print('-----Testing query()-----') 

-

88 print(query('pictureID', 'pictures')) 

-

89 print(query('place', 'pictures')) 

-

90 print() 

-

91 print('-----Testing get_table_size()-----') 

-

92 print(get_table_size('pictures')) 

-

93 print(get_table_size('users')) 

-

94 print(get_table_size('usersDaily')) 

-

95 print(get_table_size('challenges')) 

-

96 print(get_table_size('matches')) 

-

97 print() 

-

98 print('-----Testing show_rows()-----') 

-

99 show_rows() 

-

100 

-

101def main(): 

-

102 testing() 

-

103 

-

104if __name__=="__main__": 

-

105 main() 

-

106 

-

107 

-

108 

-

109 

-
- - - diff --git a/htmlcov/distance_func_py.html b/htmlcov/distance_func_py.html deleted file mode 100644 index 727199c9..00000000 --- a/htmlcov/distance_func_py.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - - Coverage for distance_func.py: 38% - - - - - -
-
-

- Coverage for distance_func.py: - 38% -

- -

- 16 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1#----------------------------------------------------------------------- 

-

2# distance_func.py 

-

3# This file contains functions relating distance calculation 

-

4#----------------------------------------------------------------------- 

-

5import psycopg2 

-

6from geopy.distance import geodesic 

-

7 

-

8DATABASE_URL = 'postgres://tigerspot_user:9WtP1U9PRdh1VLlP4VdwnT0BFSdbrPWk@dpg-cnrjs7q1hbls73e04390-a.ohio-postgres.render.com/tigerspot' 

-

9#----------------------------------------------------------------------- 

-

10 

-

11#Using the geopy library, we calculate the distance between two coordinates using the Haversine formula 

-

12#Measuring in meters 

-

13def calc_distance(lat1, lon1, coor2): 

-

14 coor1 = (lat1, lon1) 

-

15 distance = geodesic(coor1, coor2).meters 

-

16 return distance 

-

17 

-

18def main(): 

-

19 #testing that calc_distance() calculates correct distance 

-

20 expected_distance = 751 #estimation using calculator 

-

21 calculated_distance = calc_distance(40.3487 , -74.6593, (40.3421, -74.6612)) 

-

22 print("Expected distance:", expected_distance) 

-

23 print("Calculated distance:", calculated_distance) 

-

24 

-

25 if(abs(expected_distance - calculated_distance) > 2): 

-

26 print("Error with distance calculation") 

-

27 

-

28 

-

29if __name__=="__main__": 

-

30 main() 

-
- - - diff --git a/htmlcov/favicon_32_cb_58284776.png b/htmlcov/favicon_32_cb_58284776.png deleted file mode 100644 index 8649f047..00000000 Binary files a/htmlcov/favicon_32_cb_58284776.png and /dev/null differ diff --git a/htmlcov/function_index.html b/htmlcov/function_index.html deleted file mode 100644 index 4cc637fc..00000000 --- a/htmlcov/function_index.html +++ /dev/null @@ -1,1051 +0,0 @@ - - - - - Coverage report - - - - - -
-
-

Coverage report: - 15% -

- -
- -
- - -
-
-

- Files - Functions - Classes -

-

- coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Filefunctionstatementsmissingexcludedcoverage
admin.pydatabase_check3300%
admin.pyreset_versus7700%
admin.pysam3300%
admin.pylogoutapp1100%
admin.pylogoutcas1100%
admin.pyindex3300%
admin.pymenu202000%
admin.pyrequests191900%
admin.pygame191900%
admin.pysubmit292900%
admin.pyrules4400%
admin.pyteam4400%
admin.pyleaderboard131300%
admin.pytotalleaderboard131300%
admin.pyversus_func8800%
admin.pycreate_challenge_route131300%
admin.pyaccept_challenge_route101000%
admin.pydecline_challenge_route101000%
admin.pyplay_button161600%
admin.pystart_challenge121200%
admin.pyend_challenge111100%
admin.pysubmit2606000%
admin.pyversus_stats7700%
admin.py(no function)6400100%
auth.pystrip_ticket5500%
auth.pyvalidate111100%
auth.pyauthenticate131300%
auth.pylogoutapp4400%
auth.pylogoutcas2200%
auth.py(no function)1000100%
challenges_database.pycreate_challenges_table6600%
challenges_database.pyclear_challenges_table202000%
challenges_database.pyclear_user_challenges151500%
challenges_database.pycreate_challenge181800%
challenges_database.pyaccept_challenge141400%
challenges_database.pydecline_challenge141400%
challenges_database.pyreset_challenges_id_sequence141400%
challenges_database.pyget_user_challenges151500%
challenges_database.pyupdate_finish_status232300%
challenges_database.pycheck_finish_status171700%
challenges_database.pyget_challenge_participants171700%
challenges_database.pyget_challenge_results212100%
challenges_database.pycreate_random_versus3300%
challenges_database.pyget_random_versus161600%
challenges_database.pyupdate_playbutton_status222200%
challenges_database.pyget_playbutton_status252500%
challenges_database.pymain3300%
challenges_database.py(no function)241096%
cloud.pyimage_data6600%
cloud.pymain101000%
cloud.py(no function)61083%
daily_user_database.pycreate_daily_user_table8800%
daily_user_database.pyinsert_player_daily121200%
daily_user_database.pyupdate_player_daily101000%
daily_user_database.pyupdate_player_versus111100%
daily_user_database.pyplayer_played9900%
daily_user_database.pyreset_player101000%
daily_user_database.pyreset_players9900%
daily_user_database.pyget_last_played_date111100%
daily_user_database.pyget_last_versus_date111100%
daily_user_database.pyget_streak111100%
daily_user_database.pyget_daily_points111100%
daily_user_database.pyget_daily_distance111100%
daily_user_database.pyget_daily_top_players151500%
daily_user_database.pyget_daily_rank131300%
daily_user_database.pyremove_daily_user9900%
daily_user_database.pymain1100%
daily_user_database.py(no function)211095%
database.pydrop_table9900%
database.pyupdate9900%
database.pyquery101000%
database.pyget_table_size111100%
database.pyshow_rows171700%
database.pytesting131300%
database.pymain1100%
database.py(no function)111091%
distance_func.pycalc_distance3300%
distance_func.pymain6600%
distance_func.py(no function)71086%
matches_database.pycreate_matches_table6600%
matches_database.pyclear_matches_table111100%
matches_database.pycomplete_match141400%
matches_database.pymain1100%
matches_database.py(no function)81088%
pictures_database.pycreate_pic_table212100%
pictures_database.pyinsert_picture9900%
pictures_database.pyget_current_date4400%
pictures_database.pypic_of_day4400%
pictures_database.pyget_pic_info101000%
pictures_database.pymain101000%
pictures_database.py(no function)171094%
points.pycalculate_today_points9900%
points.pycalculate_total_points2200%
points.pytest_point_distribution1100%
points.pymain101000%
points.py(no function)91089%
runserver.pymain126050%
runserver.py(no function)600100%
user_database.pycreate_user_table8800%
user_database.pyinsert_player121200%
user_database.pyreset_player_total_points131300%
user_database.pyupdate_player9900%
user_database.pyget_points9900%
user_database.pyget_rank121200%
user_database.pyget_top_players141400%
user_database.pyremove_from_user_table9900%
user_database.pyget_players101000%
user_database.pymain1100%
user_database.py(no function)141093%
versus_database.pyupdate_versus_points232300%
versus_database.pycalculate_versus9900%
versus_database.pyget_winner131300%
versus_database.pyupdate_versus_pic_status232300%
versus_database.pyget_versus_pic_status252500%
versus_database.pystore_versus_pic_points232300%
versus_database.pystore_versus_pic_points232300%
versus_database.pymain1100%
versus_database.py(no function)121092%
Total 14111206015%
-

- No items found using the specified filter. -

-
- - - diff --git a/htmlcov/index.html b/htmlcov/index.html deleted file mode 100644 index d7b68afb..00000000 --- a/htmlcov/index.html +++ /dev/null @@ -1,195 +0,0 @@ - - - - - Coverage report - - - - - -
-
-

Coverage report: - 15% -

- -
- -
- - -
-
-

- Files - Functions - Classes -

-

- coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Filestatementsmissingexcludedcoverage
admin.py350286018%
auth.py4535022%
challenges_database.py28726408%
cloud.py2217023%
daily_user_database.py183163011%
database.py8171012%
distance_func.py1610038%
matches_database.py4033018%
pictures_database.py7559021%
points.py3123026%
runserver.py186067%
user_database.py11198012%
versus_database.py15214107%
Total14111206015%
-

- No items found using the specified filter. -

-
- - - diff --git a/htmlcov/keybd_closed_cb_ce680311.png b/htmlcov/keybd_closed_cb_ce680311.png deleted file mode 100644 index ba119c47..00000000 Binary files a/htmlcov/keybd_closed_cb_ce680311.png and /dev/null differ diff --git a/htmlcov/matches_database_py.html b/htmlcov/matches_database_py.html deleted file mode 100644 index 865a8bd0..00000000 --- a/htmlcov/matches_database_py.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - - Coverage for matches_database.py: 18% - - - - - -
-
-

- Coverage for matches_database.py: - 18% -

- -

- 40 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1import psycopg2 

-

2 

-

3DATABASE_URL = 'postgres://tigerspot_user:9WtP1U9PRdh1VLlP4VdwnT0BFSdbrPWk@dpg-cnrjs7q1hbls73e04390-a.ohio-postgres.render.com/tigerspot' 

-

4 

-

5 

-

6#dont run again 

-

7def create_matches_table(): 

-

8 conn = psycopg2.connect(DATABASE_URL) 

-

9 cur = conn.cursor() 

-

10 cur.execute('''CREATE TABLE IF NOT EXISTS matches ( 

-

11 id SERIAL PRIMARY KEY, 

-

12 challenge_id INTEGER, 

-

13 winner_id VARCHAR(255), 

-

14 challenger_score INTEGER, 

-

15 challengee_score INTEGER);''') 

-

16 conn.commit() 

-

17 cur.close() 

-

18 conn.close() 

-

19 

-

20#----------------------------------------------------------------------- 

-

21 

-

22def clear_matches_table(): 

-

23 conn = None 

-

24 try: 

-

25 conn = psycopg2.connect(DATABASE_URL) 

-

26 cur = conn.cursor() 

-

27 # Deletes all records from the matches table 

-

28 cur.execute("DELETE FROM matches;") 

-

29 conn.commit() # Commit the transaction to make changes permanent 

-

30 print("Matches table cleared.") 

-

31 except (Exception, psycopg2.DatabaseError) as error: 

-

32 print(f"Error clearing matches table: {error}") 

-

33 finally: 

-

34 if conn is not None: 

-

35 conn.close() 

-

36 

-

37 

-

38# Complete a match 

-

39def complete_match(challenge_id, winner_id, challenger_score, challengee_score): 

-

40 conn = None 

-

41 try: 

-

42 conn = psycopg2.connect(DATABASE_URL) 

-

43 cur = conn.cursor() 

-

44 cur.execute("UPDATE challenges SET status = 'completed' WHERE id = %s;", (challenge_id,)) 

-

45 cur.execute("INSERT INTO matches (challenge_id, winner_id, challenger_score, challengee_score) VALUES (%s, %s, %s, %s) RETURNING id;", (challenge_id, winner_id, challenger_score, challengee_score)) 

-

46 match_id = cur.fetchone()[0] 

-

47 conn.commit() 

-

48 cur.close() 

-

49 print(f"Match completed with ID: {match_id}") 

-

50 except (Exception, psycopg2.DatabaseError) as error: 

-

51 print(error) 

-

52 finally: 

-

53 if conn is not None: 

-

54 conn.close() 

-

55 

-

56def main(): 

-

57 #clear_matches_table() 

-

58 print() 

-

59 

-

60if __name__=="__main__": 

-

61 main() 

-
- - - diff --git a/htmlcov/pictures_database_py.html b/htmlcov/pictures_database_py.html deleted file mode 100644 index d83c3d5d..00000000 --- a/htmlcov/pictures_database_py.html +++ /dev/null @@ -1,248 +0,0 @@ - - - - - Coverage for pictures_database.py: 21% - - - - - -
-
-

- Coverage for pictures_database.py: - 21% -

- -

- 75 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1#----------------------------------------------------------------------- 

-

2# pictures_database.py 

-

3#----------------------------------------------------------------------- 

-

4 

-

5import psycopg2 

-

6import datetime 

-

7import cloudinary 

-

8import cloudinary.api 

-

9import cloud 

-

10import database 

-

11import pytz 

-

12import daily_user_database 

-

13 

-

14#----------------------------------------------------------------------- 

-

15 

-

16DATABASE_URL = 'postgres://tigerspot_user:9WtP1U9PRdh1VLlP4VdwnT0BFSdbrPWk@dpg-cnrjs7q1hbls73e04390-a.ohio-postgres.render.com/tigerspot' 

-

17 

-

18#----------------------------------------------------------------------- 

-

19 

-

20# Creates pictures database table 

-

21def create_pic_table(): 

-

22 

-

23 try: 

-

24 with psycopg2.connect(DATABASE_URL) as conn: 

-

25 with conn.cursor() as cur: 

-

26 

-

27 cur.execute('''CREATE TABLE IF NOT EXISTS pictures ( 

-

28 pictureID int, 

-

29 coordinates float[2], 

-

30 link varchar(255), 

-

31 place varchar(255));''') 

-

32 

-

33 # configures and connects to cloudinary account 

-

34 cloudinary.config( 

-

35 cloud_name = 'dmiaxw4rr', 

-

36 api_key = '678414952824331', 

-

37 api_secret = 'wt-aWFLd0n-CelO5kN8h1NCYFzY' 

-

38 ) 

-

39 

-

40 # name of folder to extract resources from 

-

41 folder_name = 'TigerSpot/Checked' 

-

42 

-

43 # extracts all resources from folder 

-

44 resources = cloudinary.api.resources( 

-

45 type = 'upload', 

-

46 prefix = folder_name, 

-

47 max_results = 500, 

-

48 context = True 

-

49 ) 

-

50 

-

51 pictureID = 0 

-

52 

-

53 # loops through folder and retrieves image url, coordinates, place, and sets pictureid per resource 

-

54 for resource in resources.get('resources', []): 

-

55 link, latitude, longitude, place = cloud.image_data(resource) 

-

56 coordinates = [latitude, longitude] 

-

57 cur.execute("SELECT * FROM pictures WHERE link = %s", (link,)) 

-

58 exists = cur.fetchone() 

-

59 if not exists: 

-

60 pictureID += 1 

-

61 cur.execute('''INSERT INTO pictures (pictureID, coordinates, link, place)  

-

62 VALUES (%s, %s, %s, %s);''', (pictureID, coordinates, link, place)) 

-

63 

-

64 conn.commit() 

-

65 print("Pictures database table created successfully.") 

-

66 

-

67 except (Exception, psycopg2.DatabaseError) as error: 

-

68 print(error) 

-

69 return "database error" 

-

70 

-

71# Inserts a new row into pictures database table 

-

72def insert_picture(pictureID, coordinates, link, place): 

-

73 

-

74 try: 

-

75 with psycopg2.connect(DATABASE_URL) as conn: 

-

76 with conn.cursor() as cur: 

-

77 

-

78 cur.execute('''INSERT INTO pictures (pictureID, coordinates, link)  

-

79 VALUES (%s, %s, %s);''', (pictureID, coordinates, link, place)) 

-

80 conn.commit() 

-

81 print("Row inserted successfully.") 

-

82 

-

83 except (Exception, psycopg2.DatabaseError) as error: 

-

84 print(error) 

-

85 return "database error" 

-

86 

-

87#----------------------------------------------------------------------- 

-

88 

-

89# Returns the date based on eastern time zone 

-

90def get_current_date(): 

-

91 eastern = pytz.timezone('America/New_York') 

-

92 eastern_timezone = datetime.datetime.now(eastern) 

-

93 eastern_date = eastern_timezone.date() 

-

94 

-

95 return eastern_date 

-

96 

-

97#----------------------------------------------------------------------- 

-

98 

-

99# Checks the current date and returns associated picture id 

-

100def pic_of_day(): 

-

101 

-

102 eastern_date = get_current_date() 

-

103 day_of_year = eastern_date.timetuple().tm_yday 

-

104 picture_id = (day_of_year - 1) % database.get_table_size("pictures") + 1 

-

105 

-

106 return picture_id 

-

107 

-

108# Returns specified information of picture using its id 

-

109def get_pic_info(col, id): 

-

110 

-

111 try: 

-

112 with psycopg2.connect(DATABASE_URL) as conn: 

-

113 with conn.cursor() as cur: 

-

114 

-

115 cur.execute(f"SELECT {col} FROM pictures WHERE pictureID = {id}") 

-

116 rows = cur.fetchall() 

-

117 row = rows[0][0] 

-

118 

-

119 return row 

-

120 

-

121 except (Exception, psycopg2.DatabaseError) as error: 

-

122 print(error) 

-

123 return "database error" 

-

124 

-

125#----------------------------------------------------------------------- 

-

126 

-

127def main(): 

-

128 

-

129 # create_pic_table() 

-

130 

-

131 current_date = get_current_date() 

-

132 today_id = pic_of_day() 

-

133 pic_place = get_pic_info("place", 1) 

-

134 pic_coords = get_pic_info("coordinates", 1) 

-

135 pic_url = get_pic_info("link", 1) 

-

136 

-

137 print(f"Current date: {current_date}") 

-

138 

-

139 print(f"Picture ID Today: {today_id}") 

-

140 

-

141 # Effron Music Building 

-

142 print(f"Place: {pic_place}") 

-

143 

-

144 # 40.342396, -74.659527 

-

145 print(f"Coordinates: {pic_coords}") 

-

146 

-

147 # http://res.cloudinary.com/dmiaxw4rr/image/upload/v1712640742/TigerSpot/Checked/91271FD2-F874-4AAE-B589-F6FD7BB0920B_1_201_a_r2hcfr.jpg 

-

148 print(f"URL: {pic_url}") 

-

149 

-

150if __name__=="__main__": 

-

151 main() 

-
- - - diff --git a/htmlcov/points_py.html b/htmlcov/points_py.html deleted file mode 100644 index 3f7b20fe..00000000 --- a/htmlcov/points_py.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - Coverage for points.py: 26% - - - - - -
-
-

- Coverage for points.py: - 26% -

- -

- 31 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1#----------------------------------------------------------------------- 

-

2# points.py 

-

3#----------------------------------------------------------------------- 

-

4 

-

5import user_database 

-

6import daily_user_database 

-

7import math 

-

8 

-

9#----------------------------------------------------------------------- 

-

10 

-

11# Returns points based on distance from actual coordinates 

-

12def calculate_today_points(distance): 

-

13 if distance < 3: 

-

14 points = 1500 

-

15 elif distance < 6: 

-

16 points = 1250 

-

17 elif distance < 10: 

-

18 points = 1000 

-

19 else: 

-

20 distance -= 10 

-

21 points = max(0, 1 - distance / 100) * 1000 

-

22 return points 

-

23 

-

24# Returns a player's updated cummulative points after their daily guess 

-

25def calculate_total_points(username, today_points): 

-

26 points = today_points + user_database.get_points(username) 

-

27 return points 

-

28 

-

29#----------------------------------------------------------------------- 

-

30 

-

31def test_point_distribution(distance): 

-

32 print(f"If distance is {distance}, then points is", calculate_today_points(distance)) 

-

33 

-

34#----------------------------------------------------------------------- 

-

35 

-

36def main(): 

-

37 

-

38 test_point_distribution(0) # 1500 

-

39 test_point_distribution(3) # 1250 

-

40 test_point_distribution(6) # 1000 

-

41 test_point_distribution(10) # ~1000 

-

42 test_point_distribution(100) # ~100 

-

43 test_point_distribution(110) # 0 

-

44 

-

45 cummulative_points = calculate_total_points('wn4759', 0) 

-

46 print(cummulative_points) 

-

47 cummulative_points = calculate_total_points('wn4759', 1000) 

-

48 print(cummulative_points) 

-

49 

-

50if __name__=="__main__": 

-

51 main() 

-
- - - diff --git a/htmlcov/runserver_py.html b/htmlcov/runserver_py.html deleted file mode 100644 index 3971e438..00000000 --- a/htmlcov/runserver_py.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - - Coverage for runserver.py: 67% - - - - - -
-
-

- Coverage for runserver.py: - 67% -

- -

- 18 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1#----------------------------------------------------------------------- 

-

2# runserver.py 

-

3# Runs Tiger Spot application 

-

4#----------------------------------------------------------------------- 

-

5import sys 

-

6import argparse 

-

7import admin 

-

8#----------------------------------------------------------------------- 

-

9 

-

10# Runs the server on the specified port, which in turn runs application 

-

11# When executed with -h as a command-line argument, displays a help message that describes the program's behavior 

-

12def main(): 

-

13 parser = argparse.ArgumentParser( 

-

14 description="Tiger Spot" 

-

15 ) 

-

16 parser.add_argument( 

-

17 "port", type=int, help="the port at which the server should \ 

-

18 listen" 

-

19 ) 

-

20 

-

21 try: 

-

22 args = parser.parse_args() 

-

23 except argparse.ArgumentError as e: 

-

24 print(e, file=sys.stderr) 

-

25 sys.exit(2) 

-

26 

-

27 try: 

-

28 admin.app.run(host='0.0.0.0', port=args.port, debug=True) 

-

29 

-

30 except Exception as ex: 

-

31 print(ex, file=sys.stderr) 

-

32 sys.exit(1) 

-

33 

-

34if __name__ == '__main__': 

-

35 main() 

-
- - - diff --git a/htmlcov/status.json b/htmlcov/status.json deleted file mode 100644 index eefdd1f4..00000000 --- a/htmlcov/status.json +++ /dev/null @@ -1 +0,0 @@ -{"note":"This file is an internal implementation detail to speed up HTML report generation. Its format can change at any time. You might be looking for the JSON report: https://coverage.rtfd.io/cmd.html#cmd-json","format":5,"version":"7.5.1","globals":"514d7c62fb5b0b961049ce2394c20dc9","files":{"admin_py":{"hash":"3d0e37bffe533d1bfe9a99e64a315ec5","index":{"url":"admin_py.html","file":"admin.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":350,"n_excluded":0,"n_missing":286,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"auth_py":{"hash":"fcc3d69163f12612bc74613c6bf2d60d","index":{"url":"auth_py.html","file":"auth.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":45,"n_excluded":0,"n_missing":35,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"challenges_database_py":{"hash":"17a2bfd5d75dc6f69e0c531093b5d00a","index":{"url":"challenges_database_py.html","file":"challenges_database.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":287,"n_excluded":0,"n_missing":264,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"cloud_py":{"hash":"14dad6e82426ff505725cfa7fd07d114","index":{"url":"cloud_py.html","file":"cloud.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":22,"n_excluded":0,"n_missing":17,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"daily_user_database_py":{"hash":"3962241d377af63852e8b3b820340695","index":{"url":"daily_user_database_py.html","file":"daily_user_database.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":183,"n_excluded":0,"n_missing":163,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"database_py":{"hash":"9be93ea77afe594430e7c26c3f9bf177","index":{"url":"database_py.html","file":"database.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":81,"n_excluded":0,"n_missing":71,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"distance_func_py":{"hash":"4629ec0499c8df6aec6d4f255fb13d16","index":{"url":"distance_func_py.html","file":"distance_func.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":16,"n_excluded":0,"n_missing":10,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"matches_database_py":{"hash":"4797a31aeedd5894b2f70361c816bef3","index":{"url":"matches_database_py.html","file":"matches_database.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":40,"n_excluded":0,"n_missing":33,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"pictures_database_py":{"hash":"ac90dfbc76057d8a8dc41459a3bb4e89","index":{"url":"pictures_database_py.html","file":"pictures_database.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":75,"n_excluded":0,"n_missing":59,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"points_py":{"hash":"ef76bf948fc130f6c9043f7c36bd627a","index":{"url":"points_py.html","file":"points.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":31,"n_excluded":0,"n_missing":23,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"runserver_py":{"hash":"94dec3143d5516ad46dbaecc358667a4","index":{"url":"runserver_py.html","file":"runserver.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":18,"n_excluded":0,"n_missing":6,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"user_database_py":{"hash":"fd4798c911808934f4ff1436b0c639f0","index":{"url":"user_database_py.html","file":"user_database.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":111,"n_excluded":0,"n_missing":98,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"versus_database_py":{"hash":"73fde436e0f94ea454ba652803fde9d1","index":{"url":"versus_database_py.html","file":"versus_database.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":152,"n_excluded":0,"n_missing":141,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}}}} \ No newline at end of file diff --git a/htmlcov/style_cb_8e611ae1.css b/htmlcov/style_cb_8e611ae1.css deleted file mode 100644 index 3cdaf05a..00000000 --- a/htmlcov/style_cb_8e611ae1.css +++ /dev/null @@ -1,337 +0,0 @@ -@charset "UTF-8"; -/* Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 */ -/* For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt */ -/* Don't edit this .css file. Edit the .scss file instead! */ -html, body, h1, h2, h3, p, table, td, th { margin: 0; padding: 0; border: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; } - -body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 1em; background: #fff; color: #000; } - -@media (prefers-color-scheme: dark) { body { background: #1e1e1e; } } - -@media (prefers-color-scheme: dark) { body { color: #eee; } } - -html > body { font-size: 16px; } - -a:active, a:focus { outline: 2px dashed #007acc; } - -p { font-size: .875em; line-height: 1.4em; } - -table { border-collapse: collapse; } - -td { vertical-align: top; } - -table tr.hidden { display: none !important; } - -p#no_rows { display: none; font-size: 1.15em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } - -a.nav { text-decoration: none; color: inherit; } - -a.nav:hover { text-decoration: underline; color: inherit; } - -.hidden { display: none; } - -header { background: #f8f8f8; width: 100%; z-index: 2; border-bottom: 1px solid #ccc; } - -@media (prefers-color-scheme: dark) { header { background: black; } } - -@media (prefers-color-scheme: dark) { header { border-color: #333; } } - -header .content { padding: 1rem 3.5rem; } - -header h2 { margin-top: .5em; font-size: 1em; } - -header h2 a.button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; } - -@media (prefers-color-scheme: dark) { header h2 a.button { background: #333; } } - -@media (prefers-color-scheme: dark) { header h2 a.button { border-color: #444; } } - -header h2 a.button.current { border: 2px solid; background: #fff; border-color: #999; cursor: default; } - -@media (prefers-color-scheme: dark) { header h2 a.button.current { background: #1e1e1e; } } - -@media (prefers-color-scheme: dark) { header h2 a.button.current { border-color: #777; } } - -header p.text { margin: .5em 0 -.5em; color: #666; font-style: italic; } - -@media (prefers-color-scheme: dark) { header p.text { color: #aaa; } } - -header.sticky { position: fixed; left: 0; right: 0; height: 2.5em; } - -header.sticky .text { display: none; } - -header.sticky h1, header.sticky h2 { font-size: 1em; margin-top: 0; display: inline-block; } - -header.sticky .content { padding: 0.5rem 3.5rem; } - -header.sticky .content p { font-size: 1em; } - -header.sticky ~ #source { padding-top: 6.5em; } - -main { position: relative; z-index: 1; } - -footer { margin: 1rem 3.5rem; } - -footer .content { padding: 0; color: #666; font-style: italic; } - -@media (prefers-color-scheme: dark) { footer .content { color: #aaa; } } - -#index { margin: 1rem 0 0 3.5rem; } - -h1 { font-size: 1.25em; display: inline-block; } - -#filter_container { float: right; margin: 0 2em 0 0; line-height: 1.66em; } - -#filter_container #filter { width: 10em; padding: 0.2em 0.5em; border: 2px solid #ccc; background: #fff; color: #000; } - -@media (prefers-color-scheme: dark) { #filter_container #filter { border-color: #444; } } - -@media (prefers-color-scheme: dark) { #filter_container #filter { background: #1e1e1e; } } - -@media (prefers-color-scheme: dark) { #filter_container #filter { color: #eee; } } - -#filter_container #filter:focus { border-color: #007acc; } - -#filter_container :disabled ~ label { color: #ccc; } - -@media (prefers-color-scheme: dark) { #filter_container :disabled ~ label { color: #444; } } - -#filter_container label { font-size: .875em; color: #666; } - -@media (prefers-color-scheme: dark) { #filter_container label { color: #aaa; } } - -header button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; } - -@media (prefers-color-scheme: dark) { header button { background: #333; } } - -@media (prefers-color-scheme: dark) { header button { border-color: #444; } } - -header button:active, header button:focus { outline: 2px dashed #007acc; } - -header button.run { background: #eeffee; } - -@media (prefers-color-scheme: dark) { header button.run { background: #373d29; } } - -header button.run.show_run { background: #dfd; border: 2px solid #00dd00; margin: 0 .1em; } - -@media (prefers-color-scheme: dark) { header button.run.show_run { background: #373d29; } } - -header button.mis { background: #ffeeee; } - -@media (prefers-color-scheme: dark) { header button.mis { background: #4b1818; } } - -header button.mis.show_mis { background: #fdd; border: 2px solid #ff0000; margin: 0 .1em; } - -@media (prefers-color-scheme: dark) { header button.mis.show_mis { background: #4b1818; } } - -header button.exc { background: #f7f7f7; } - -@media (prefers-color-scheme: dark) { header button.exc { background: #333; } } - -header button.exc.show_exc { background: #eee; border: 2px solid #808080; margin: 0 .1em; } - -@media (prefers-color-scheme: dark) { header button.exc.show_exc { background: #333; } } - -header button.par { background: #ffffd5; } - -@media (prefers-color-scheme: dark) { header button.par { background: #650; } } - -header button.par.show_par { background: #ffa; border: 2px solid #bbbb00; margin: 0 .1em; } - -@media (prefers-color-scheme: dark) { header button.par.show_par { background: #650; } } - -#help_panel, #source p .annotate.long { display: none; position: absolute; z-index: 999; background: #ffffcc; border: 1px solid #888; border-radius: .2em; color: #333; padding: .25em .5em; } - -#source p .annotate.long { white-space: normal; float: right; top: 1.75em; right: 1em; height: auto; } - -#help_panel_wrapper { float: right; position: relative; } - -#keyboard_icon { margin: 5px; } - -#help_panel_state { display: none; } - -#help_panel { top: 25px; right: 0; padding: .75em; border: 1px solid #883; color: #333; } - -#help_panel .keyhelp p { margin-top: .75em; } - -#help_panel .legend { font-style: italic; margin-bottom: 1em; } - -.indexfile #help_panel { width: 25em; } - -.pyfile #help_panel { width: 18em; } - -#help_panel_state:checked ~ #help_panel { display: block; } - -kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em .35em; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-weight: bold; background: #eee; border-radius: 3px; } - -#source { padding: 1em 0 1em 3.5rem; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; } - -#source p { position: relative; white-space: pre; } - -#source p * { box-sizing: border-box; } - -#source p .n { float: left; text-align: right; width: 3.5rem; box-sizing: border-box; margin-left: -3.5rem; padding-right: 1em; color: #999; user-select: none; } - -@media (prefers-color-scheme: dark) { #source p .n { color: #777; } } - -#source p .n.highlight { background: #ffdd00; } - -#source p .n a { scroll-margin-top: 6em; text-decoration: none; color: #999; } - -@media (prefers-color-scheme: dark) { #source p .n a { color: #777; } } - -#source p .n a:hover { text-decoration: underline; color: #999; } - -@media (prefers-color-scheme: dark) { #source p .n a:hover { color: #777; } } - -#source p .t { display: inline-block; width: 100%; box-sizing: border-box; margin-left: -.5em; padding-left: 0.3em; border-left: 0.2em solid #fff; } - -@media (prefers-color-scheme: dark) { #source p .t { border-color: #1e1e1e; } } - -#source p .t:hover { background: #f2f2f2; } - -@media (prefers-color-scheme: dark) { #source p .t:hover { background: #282828; } } - -#source p .t:hover ~ .r .annotate.long { display: block; } - -#source p .t .com { color: #008000; font-style: italic; line-height: 1px; } - -@media (prefers-color-scheme: dark) { #source p .t .com { color: #6a9955; } } - -#source p .t .key { font-weight: bold; line-height: 1px; } - -#source p .t .str { color: #0451a5; } - -@media (prefers-color-scheme: dark) { #source p .t .str { color: #9cdcfe; } } - -#source p.mis .t { border-left: 0.2em solid #ff0000; } - -#source p.mis.show_mis .t { background: #fdd; } - -@media (prefers-color-scheme: dark) { #source p.mis.show_mis .t { background: #4b1818; } } - -#source p.mis.show_mis .t:hover { background: #f2d2d2; } - -@media (prefers-color-scheme: dark) { #source p.mis.show_mis .t:hover { background: #532323; } } - -#source p.run .t { border-left: 0.2em solid #00dd00; } - -#source p.run.show_run .t { background: #dfd; } - -@media (prefers-color-scheme: dark) { #source p.run.show_run .t { background: #373d29; } } - -#source p.run.show_run .t:hover { background: #d2f2d2; } - -@media (prefers-color-scheme: dark) { #source p.run.show_run .t:hover { background: #404633; } } - -#source p.exc .t { border-left: 0.2em solid #808080; } - -#source p.exc.show_exc .t { background: #eee; } - -@media (prefers-color-scheme: dark) { #source p.exc.show_exc .t { background: #333; } } - -#source p.exc.show_exc .t:hover { background: #e2e2e2; } - -@media (prefers-color-scheme: dark) { #source p.exc.show_exc .t:hover { background: #3c3c3c; } } - -#source p.par .t { border-left: 0.2em solid #bbbb00; } - -#source p.par.show_par .t { background: #ffa; } - -@media (prefers-color-scheme: dark) { #source p.par.show_par .t { background: #650; } } - -#source p.par.show_par .t:hover { background: #f2f2a2; } - -@media (prefers-color-scheme: dark) { #source p.par.show_par .t:hover { background: #6d5d0c; } } - -#source p .r { position: absolute; top: 0; right: 2.5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } - -#source p .annotate { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; color: #666; padding-right: .5em; } - -@media (prefers-color-scheme: dark) { #source p .annotate { color: #ddd; } } - -#source p .annotate.short:hover ~ .long { display: block; } - -#source p .annotate.long { width: 30em; right: 2.5em; } - -#source p input { display: none; } - -#source p input ~ .r label.ctx { cursor: pointer; border-radius: .25em; } - -#source p input ~ .r label.ctx::before { content: "â–¶ "; } - -#source p input ~ .r label.ctx:hover { background: #e8f4ff; color: #666; } - -@media (prefers-color-scheme: dark) { #source p input ~ .r label.ctx:hover { background: #0f3a42; } } - -@media (prefers-color-scheme: dark) { #source p input ~ .r label.ctx:hover { color: #aaa; } } - -#source p input:checked ~ .r label.ctx { background: #d0e8ff; color: #666; border-radius: .75em .75em 0 0; padding: 0 .5em; margin: -.25em 0; } - -@media (prefers-color-scheme: dark) { #source p input:checked ~ .r label.ctx { background: #056; } } - -@media (prefers-color-scheme: dark) { #source p input:checked ~ .r label.ctx { color: #aaa; } } - -#source p input:checked ~ .r label.ctx::before { content: "â–¼ "; } - -#source p input:checked ~ .ctxs { padding: .25em .5em; overflow-y: scroll; max-height: 10.5em; } - -#source p label.ctx { color: #999; display: inline-block; padding: 0 .5em; font-size: .8333em; } - -@media (prefers-color-scheme: dark) { #source p label.ctx { color: #777; } } - -#source p .ctxs { display: block; max-height: 0; overflow-y: hidden; transition: all .2s; padding: 0 .5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; white-space: nowrap; background: #d0e8ff; border-radius: .25em; margin-right: 1.75em; text-align: right; } - -@media (prefers-color-scheme: dark) { #source p .ctxs { background: #056; } } - -#index { font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 0.875em; } - -#index table.index { margin-left: -.5em; } - -#index td, #index th { text-align: right; padding: .25em .5em; border-bottom: 1px solid #eee; } - -@media (prefers-color-scheme: dark) { #index td, #index th { border-color: #333; } } - -#index td.name, #index th.name { text-align: left; width: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; min-width: 15em; } - -#index th { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-style: italic; color: #333; cursor: pointer; } - -@media (prefers-color-scheme: dark) { #index th { color: #ddd; } } - -#index th:hover { background: #eee; } - -@media (prefers-color-scheme: dark) { #index th:hover { background: #333; } } - -#index th .arrows { color: #666; font-size: 85%; font-family: sans-serif; font-style: normal; pointer-events: none; } - -#index th[aria-sort="ascending"], #index th[aria-sort="descending"] { white-space: nowrap; background: #eee; padding-left: .5em; } - -@media (prefers-color-scheme: dark) { #index th[aria-sort="ascending"], #index th[aria-sort="descending"] { background: #333; } } - -#index th[aria-sort="ascending"] .arrows::after { content: " â–²"; } - -#index th[aria-sort="descending"] .arrows::after { content: " â–¼"; } - -#index td.name { font-size: 1.15em; } - -#index td.name a { text-decoration: none; color: inherit; } - -#index td.name .no-noun { font-style: italic; } - -#index tr.total td, #index tr.total_dynamic td { font-weight: bold; border-top: 1px solid #ccc; border-bottom: none; } - -#index tr.region:hover { background: #eee; } - -@media (prefers-color-scheme: dark) { #index tr.region:hover { background: #333; } } - -#index tr.region:hover td.name { text-decoration: underline; color: inherit; } - -#scroll_marker { position: fixed; z-index: 3; right: 0; top: 0; width: 16px; height: 100%; background: #fff; border-left: 1px solid #eee; will-change: transform; } - -@media (prefers-color-scheme: dark) { #scroll_marker { background: #1e1e1e; } } - -@media (prefers-color-scheme: dark) { #scroll_marker { border-color: #333; } } - -#scroll_marker .marker { background: #ccc; position: absolute; min-height: 3px; width: 100%; } - -@media (prefers-color-scheme: dark) { #scroll_marker .marker { background: #444; } } diff --git a/htmlcov/user_database_py.html b/htmlcov/user_database_py.html deleted file mode 100644 index 81465382..00000000 --- a/htmlcov/user_database_py.html +++ /dev/null @@ -1,301 +0,0 @@ - - - - - Coverage for user_database.py: 12% - - - - - -
-
-

- Coverage for user_database.py: - 12% -

- -

- 111 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1#----------------------------------------------------------------------- 

-

2# user_database.py 

-

3#----------------------------------------------------------------------- 

-

4 

-

5import psycopg2 

-

6 

-

7#----------------------------------------------------------------------- 

-

8 

-

9DATABASE_URL = 'postgres://tigerspot_user:9WtP1U9PRdh1VLlP4VdwnT0BFSdbrPWk@dpg-cnrjs7q1hbls73e04390-a.ohio-postgres.render.com/tigerspot' 

-

10 

-

11#----------------------------------------------------------------------- 

-

12 

-

13# Creates users table with columns username and points. 

-

14 

-

15def create_user_table(): 

-

16 

-

17 try: 

-

18 with psycopg2.connect(DATABASE_URL) as conn: 

-

19 with conn.cursor() as cur: 

-

20 cur.execute('''CREATE TABLE IF NOT EXISTS users ( 

-

21 username varchar(255), 

-

22 points int);''') 

-

23 conn.commit() 

-

24 

-

25 except (Exception, psycopg2.DatabaseError) as error: 

-

26 print(error) 

-

27 return "database error" 

-

28 

-

29#----------------------------------------------------------------------- 

-

30 

-

31# Inserts username into users table. 

-

32 

-

33def insert_player(username): 

-

34 

-

35 try: 

-

36 with psycopg2.connect(DATABASE_URL) as conn: 

-

37 with conn.cursor() as cur: 

-

38 # Check if username exists 

-

39 cur.execute("SELECT points FROM users WHERE username=%s;", (username,)) 

-

40 result = cur.fetchone() 

-

41 

-

42 if result is None: 

-

43 cur.execute("INSERT INTO users (username, points) VALUES (%s, %s);", (username, 0,)) 

-

44 conn.commit() 

-

45 

-

46 return "success" 

-

47 

-

48 except (Exception, psycopg2.DatabaseError) as error: 

-

49 print(error) 

-

50 return "database error" 

-

51 

-

52#----------------------------------------------------------------------- 

-

53 

-

54# Resets username's total points to 0. 

-

55 

-

56def reset_player_total_points(username): 

-

57 

-

58 try: 

-

59 with psycopg2.connect(DATABASE_URL) as conn: 

-

60 with conn.cursor() as cur: 

-

61 # Check if username exists 

-

62 cur.execute("SELECT points FROM users WHERE username=%s;", (username,)) 

-

63 result = cur.fetchone() 

-

64 

-

65 if result is None: 

-

66 return 

-

67 else: 

-

68 cur.execute("UPDATE users SET points=%s WHERE username=%s;", (0, username)) 

-

69 conn.commit() 

-

70 

-

71 return "success" 

-

72 

-

73 except (Exception, psycopg2.DatabaseError) as error: 

-

74 print(error) 

-

75 return "database error" 

-

76 

-

77 

-

78#----------------------------------------------------------------------- 

-

79 

-

80# Updates username's total points with points. 

-

81 

-

82def update_player(username, points): 

-

83 

-

84 try: 

-

85 with psycopg2.connect(DATABASE_URL) as conn: 

-

86 with conn.cursor() as cur: 

-

87 cur.execute("UPDATE users SET points=%s WHERE username=%s;", (points, username)) 

-

88 conn.commit() 

-

89 

-

90 return "success" 

-

91 

-

92 except (Exception, psycopg2.DatabaseError) as error: 

-

93 print(error) 

-

94 return "database error" 

-

95 

-

96#----------------------------------------------------------------------- 

-

97 

-

98# Returns username's points. 

-

99 

-

100def get_points(username): 

-

101 

-

102 try: 

-

103 with psycopg2.connect(DATABASE_URL) as conn: 

-

104 with conn.cursor() as cur: 

-

105 cur.execute('''SELECT points FROM users WHERE username=%s;''', (username,)) 

-

106 points = cur.fetchone() 

-

107 

-

108 return points[0] 

-

109 

-

110 except (Exception, psycopg2.DatabaseError) as error: 

-

111 print(error) 

-

112 return "database error" 

-

113 

-

114#----------------------------------------------------------------------- 

-

115 

-

116# Returns username's total rank among all players. 

-

117 

-

118def get_rank(username): 

-

119 

-

120 try: 

-

121 with psycopg2.connect(DATABASE_URL) as conn: 

-

122 with conn.cursor() as cur: 

-

123 cur.execute("SELECT username, points, DENSE_RANK() OVER (ORDER BY points DESC, username ASC) as rank FROM users;") 

-

124 players = cur.fetchall() 

-

125 

-

126 for player in players: 

-

127 if player[0] == username: 

-

128 return player[2] 

-

129 return "Player not found" 

-

130 

-

131 except (Exception, psycopg2.DatabaseError) as error: 

-

132 print(error) 

-

133 return "database error" 

-

134 

-

135#----------------------------------------------------------------------- 

-

136 

-

137# Returns a dictionary of the usernames and points of the the top 10 

-

138# scoring players. 

-

139 

-

140def get_top_players(): 

-

141 

-

142 try: 

-

143 with psycopg2.connect(DATABASE_URL) as conn: 

-

144 with conn.cursor() as cur: 

-

145 

-

146 top_players = [] 

-

147 cur.execute("SELECT username, points FROM users ORDER BY points DESC, username ASC LIMIT 10;") 

-

148 table = cur.fetchall() 

-

149 for row in table: 

-

150 username, points = row 

-

151 player_stats = {'username': username, 'points': points} 

-

152 top_players.append(player_stats) 

-

153 

-

154 return top_players 

-

155 

-

156 except (Exception, psycopg2.DatabaseError) as error: 

-

157 print(error) 

-

158 return "database error" 

-

159 

-

160#----------------------------------------------------------------------- 

-

161 

-

162# Removes username from the users table. 

-

163 

-

164def remove_from_user_table(username): 

-

165 

-

166 try: 

-

167 with psycopg2.connect(DATABASE_URL) as conn: 

-

168 with conn.cursor() as cur: 

-

169 cur.execute("DELETE FROM users WHERE username=%s;", (username,)) 

-

170 conn.commit() 

-

171 

-

172 return "success" 

-

173 

-

174 except (Exception, psycopg2.DatabaseError) as error: 

-

175 print(error) 

-

176 return "database error" 

-

177 

-

178#----------------------------------------------------------------------- 

-

179 

-

180# Returns all players in users table. 

-

181 

-

182def get_players(): 

-

183 

-

184 try: 

-

185 with psycopg2.connect(DATABASE_URL) as conn: 

-

186 with conn.cursor() as cur: 

-

187 cur.execute("SELECT username FROM users;") 

-

188 table = cur.fetchall() 

-

189 user_ids = [row[0] for row in table] 

-

190 return user_ids 

-

191 

-

192 except (Exception, psycopg2.DatabaseError) as error: 

-

193 print(error) 

-

194 return "database error" 

-

195 

-

196#----------------------------------------------------------------------- 

-

197 

-

198def main(): 

-

199 print(get_top_players()) 

-

200 

-

201#----------------------------------------------------------------------- 

-

202 

-

203if __name__=="__main__": 

-

204 main() 

-
- - - diff --git a/htmlcov/versus_database_py.html b/htmlcov/versus_database_py.html deleted file mode 100644 index 190f9a82..00000000 --- a/htmlcov/versus_database_py.html +++ /dev/null @@ -1,386 +0,0 @@ - - - - - Coverage for versus_database.py: 7% - - - - - -
-
-

- Coverage for versus_database.py: - 7% -

- -

- 152 statements   - - - -

-

- « prev     - ^ index     - » next -       - coverage.py v7.5.1, - created at 2024-05-04 12:59 -0400 -

- -
-
-
-

1import psycopg2 

-

2 

-

3DATABASE_URL = 'postgres://tigerspot_user:9WtP1U9PRdh1VLlP4VdwnT0BFSdbrPWk@dpg-cnrjs7q1hbls73e04390-a.ohio-postgres.render.com/tigerspot' 

-

4 

-

5 

-

6def update_versus_points(challenge_id, user_id, additional_points): 

-

7 conn = None 

-

8 try: 

-

9 conn = psycopg2.connect(DATABASE_URL) 

-

10 cur = conn.cursor() 

-

11 

-

12 # First, determine if the user is the challenger or the challengee for this challenge 

-

13 cur.execute(''' 

-

14 SELECT challenger_id, challengee_id 

-

15 FROM challenges 

-

16 WHERE id = %s; 

-

17 ''', (challenge_id,)) 

-

18 

-

19 result = cur.fetchone() 

-

20 if result is None: 

-

21 print("Challenge not found.") 

-

22 return 

-

23 

-

24 challenger_id, challengee_id = result 

-

25 

-

26 # Depending on whether the user is the challenger or the challengee, 

-

27 # increment the corresponding points column for that user in the challenges table 

-

28 if user_id == challenger_id: 

-

29 cur.execute(''' 

-

30 UPDATE challenges 

-

31 SET challenger_points = COALESCE(challenger_points, 0) + %s 

-

32 WHERE id = %s; 

-

33 ''', (additional_points, challenge_id)) 

-

34 elif user_id == challengee_id: 

-

35 cur.execute(''' 

-

36 UPDATE challenges 

-

37 SET challengee_points = COALESCE(challengee_points, 0) + %s 

-

38 WHERE id = %s; 

-

39 ''', (additional_points, challenge_id)) 

-

40 else: 

-

41 print("User is not part of this challenge.") 

-

42 return 

-

43 

-

44 conn.commit() 

-

45 print("User points incremented successfully.") 

-

46 return {"status": "success"} 

-

47 

-

48 except (Exception, psycopg2.DatabaseError) as error: 

-

49 print(f"Error: {error}") 

-

50 finally: 

-

51 if conn is not None: 

-

52 conn.close() 

-

53#----------------------------------------------------------------------- 

-

54 

-

55def calculate_versus(distance, time): 

-

56 if time < 10 and distance < 10: 

-

57 return 1000 

-

58 else: 

-

59 if distance < 0: 

-

60 raise ValueError("Distance cannot be negative") 

-

61 dis_points = max(0, 1 - distance / 110) * 900 

-

62 if time < 0 or time > 120: 

-

63 raise ValueError("Time taken must be between 0 and the maximum allowed time") 

-

64 time_points = max(0, 1 - time / 120) * 100 

-

65 

-

66 return dis_points + time_points 

-

67 

-

68def get_winner(challenge_id): 

-

69 conn = None 

-

70 try: 

-

71 conn = psycopg2.connect(DATABASE_URL) 

-

72 cur = conn.cursor() 

-

73 cur.execute("SELECT winner_id FROM matches WHERE challenge_id = %s;", (challenge_id,)) 

-

74 result = cur.fetchone() 

-

75 if result is None: 

-

76 return None 

-

77 else: 

-

78 return result[0] 

-

79 

-

80 except (Exception, psycopg2.DatabaseError) as error: 

-

81 print(f"Error: {error}") 

-

82 finally: 

-

83 if conn is not None: 

-

84 conn.close() 

-

85 

-

86def update_versus_pic_status(challenge_id, user_id, index): 

-

87 conn = None 

-

88 try: 

-

89 conn = psycopg2.connect(DATABASE_URL) 

-

90 cur = conn.cursor() 

-

91 

-

92 # First, determine if the user is the challenger or the challengee for this challenge 

-

93 cur.execute(''' 

-

94 SELECT challenger_id, challengee_id 

-

95 FROM challenges 

-

96 WHERE id = %s; 

-

97 ''', (challenge_id,)) 

-

98 

-

99 result = cur.fetchone() 

-

100 if result is None: 

-

101 print("Challenge not found.") 

-

102 return 

-

103 

-

104 challenger_id, challengee_id = result 

-

105 

-

106 # Depending on whether the user is the challenger or the challengee, 

-

107 # update the corresponding finished column in the matches table 

-

108 if user_id == challenger_id: 

-

109 cur.execute(''' 

-

110 UPDATE challenges 

-

111 SET challenger_bool[%s] = TRUE 

-

112 WHERE id = %s; 

-

113 ''', (index, challenge_id)) 

-

114 elif user_id == challengee_id: 

-

115 cur.execute(''' 

-

116 UPDATE challenges 

-

117 SET challengee_bool[%s] = TRUE 

-

118 WHERE id = %s; 

-

119 ''', (index, challenge_id)) 

-

120 else: 

-

121 print("User is not part of this challenge.") 

-

122 return 

-

123 

-

124 conn.commit() 

-

125 print("Finish status updated successfully.") 

-

126 return {"status": "success"} 

-

127 

-

128 except (Exception, psycopg2.DatabaseError) as error: 

-

129 print(f"Error: {error}") 

-

130 finally: 

-

131 if conn is not None: 

-

132 conn.close() 

-

133 

-

134def get_versus_pic_status(challenge_id, user_id, index): 

-

135 conn = None 

-

136 try: 

-

137 conn = psycopg2.connect(DATABASE_URL) 

-

138 cur = conn.cursor() 

-

139 

-

140 # First, determine if the user is the challenger or the challengee for this challenge 

-

141 cur.execute(''' 

-

142 SELECT challenger_id, challengee_id 

-

143 FROM challenges 

-

144 WHERE id = %s; 

-

145 ''', (challenge_id,)) 

-

146 

-

147 result = cur.fetchone() 

-

148 if result is None: 

-

149 print("Challenge not found.") 

-

150 return 

-

151 

-

152 challenger_id, challengee_id = result 

-

153 

-

154 # Depending on whether the user is the challenger or the challengee, 

-

155 # get the corresponding finished column in the matches table 

-

156 if user_id == challenger_id: 

-

157 cur.execute(''' 

-

158 SELECT challenger_bool[%s] 

-

159 FROM challenges 

-

160 WHERE id = %s; 

-

161 ''', (index, challenge_id)) 

-

162 elif user_id == challengee_id: 

-

163 cur.execute(''' 

-

164 SELECT challengee_bool[%s] 

-

165 FROM challenges 

-

166 WHERE id = %s; 

-

167 ''', (index, challenge_id)) 

-

168 else: 

-

169 print("User is not part of this challenge.") 

-

170 return 

-

171 

-

172 result = cur.fetchone() 

-

173 if result is None: 

-

174 print("Index not found.") 

-

175 return 

-

176 else: 

-

177 return result[0] 

-

178 

-

179 except (Exception, psycopg2.DatabaseError) as error: 

-

180 print(f"Error: {error}") 

-

181 finally: 

-

182 if conn is not None: 

-

183 conn.close() 

-

184#----------------------------------------------------------------------- 

-

185 

-

186def store_versus_pic_points(challenge_id, user_id, index, points): 

-

187 conn = None 

-

188 try: 

-

189 conn = psycopg2.connect(DATABASE_URL) 

-

190 cur = conn.cursor() 

-

191 

-

192 # First, determine if the user is the challenger or the challengee for this challenge 

-

193 cur.execute(''' 

-

194 SELECT challenger_id, challengee_id 

-

195 FROM challenges 

-

196 WHERE id = %s; 

-

197 ''', (challenge_id,)) 

-

198 

-

199 result = cur.fetchone() 

-

200 if result is None: 

-

201 print("Challenge not found.") 

-

202 return 

-

203 

-

204 challenger_id, challengee_id = result 

-

205 

-

206 # Depending on whether the user is the challenger or the challengee, 

-

207 # update the corresponding finished column in the matches table 

-

208 if user_id == challenger_id: 

-

209 cur.execute(''' 

-

210 UPDATE challenges 

-

211 SET challenger_points[%s] = %s 

-

212 WHERE id = %s; 

-

213 ''', (index, points, challenge_id)) 

-

214 elif user_id == challengee_id: 

-

215 cur.execute(''' 

-

216 UPDATE challenges 

-

217 SET challengee_points[%s] = %s 

-

218 WHERE id = %s; 

-

219 ''', (index, points, challenge_id)) 

-

220 else: 

-

221 print("User is not part of this challenge.") 

-

222 return 

-

223 

-

224 conn.commit() 

-

225 print("Points updated successfully.") 

-

226 return {"status": "success"} 

-

227 

-

228 except (Exception, psycopg2.DatabaseError) as error: 

-

229 print(f"Error: {error}") 

-

230 finally: 

-

231 if conn is not None: 

-

232 conn.close() 

-

233 

-

234#----------------------------------------------------------------------- 

-

235 

-

236def store_versus_pic_points(challenge_id, user_id, index, points): 

-

237 conn = None 

-

238 try: 

-

239 conn = psycopg2.connect(DATABASE_URL) 

-

240 cur = conn.cursor() 

-

241 

-

242 # First, determine if the user is the challenger or the challengee for this challenge 

-

243 cur.execute(''' 

-

244 SELECT challenger_id, challengee_id 

-

245 FROM challenges 

-

246 WHERE id = %s; 

-

247 ''', (challenge_id,)) 

-

248 

-

249 result = cur.fetchone() 

-

250 if result is None: 

-

251 print("Challenge not found.") 

-

252 return 

-

253 

-

254 challenger_id, challengee_id = result 

-

255 

-

256 # Depending on whether the user is the challenger or the challengee, 

-

257 # update the corresponding points column in the challenges table 

-

258 if user_id == challenger_id: 

-

259 cur.execute(''' 

-

260 UPDATE challenges 

-

261 SET challenger_pic_points[%s] = %s 

-

262 WHERE id = %s; 

-

263 ''', (index, points, challenge_id)) 

-

264 elif user_id == challengee_id: 

-

265 cur.execute(''' 

-

266 UPDATE challenges 

-

267 SET challengee_pic_points[%s] = %s 

-

268 WHERE id = %s; 

-

269 ''', (index, points, challenge_id)) 

-

270 else: 

-

271 print("User is not part of this challenge.") 

-

272 return 

-

273 

-

274 conn.commit() 

-

275 print("Versus pic points updated successfully.") 

-

276 return {"status": "success"} 

-

277 

-

278 except (Exception, psycopg2.DatabaseError) as error: 

-

279 print(f"Error: {error}") 

-

280 finally: 

-

281 if conn is not None: 

-

282 conn.close() 

-

283 

-

284#----------------------------------------------------------------------- 

-

285def main(): 

-

286 print() 

-

287 

-

288if __name__=="__main__": 

-

289 main() 

-
- - -