def profile(): logger.info("endpoint: profile") session_id = get_session_id() user_id = int(database.hget(f"web.session:{session_id}", "user_id")) if user_id != 0: avatar_hash, avatar_url, username, discriminator = ( stat.decode("utf-8") for stat in database.hmget( f"web.user:{user_id}", "avatar_hash", "avatar_url", "username", "discriminator")) placings = int(database.zscore("users:global", str(user_id))) max_streak = int(database.zscore('streak.max:global', str(user_id))) missed_birds = [[ stats[0].decode("utf-8"), int(stats[1]) ] for stats in database.zrevrangebyscore(f"incorrect.user:{user_id}", "+inf", "-inf", 0, 10, True)] return { "avatar_hash": avatar_hash, "avatar_url": avatar_url, "username": username, "discriminator": discriminator, "rank": placings, "max_streak": max_streak, "missed": missed_birds } else: logger.info("not logged in") abort(403, "Sign in to continue")
def hint_bird(): logger.info("endpoint: hint bird") session_id = get_session_id() currentBird = database.hget(f"web.session:{session_id}", "bird").decode("utf-8") if currentBird != "": # check if there is bird return {"hint": currentBird[0]} logger.info("bird is blank") flask.abort(406, "Bird is blank") return None
async def _bw_helper(url): async with aiohttp.ClientSession() as session: async with session.get(url) as response: if response.status != 200: logger.info("invalid response") flask.abort(response.status, "error fetching url") if response.content_type not in valid_content_types: logger.info("invalid content type") flask.abort(415, "invalid content type") return ( _black_and_white(BytesIO(await response.read())), response.content_type, )
def login(): logger.info("endpoint: login") redirect_uri = url_for('user.authorize', _external=True, _scheme='https') resp = make_response(oauth.discord.authorize_redirect(redirect_uri)) redirect_after = request.args.get("redirect", FRONTEND_URL, str) if relative_url_regex.fullmatch(redirect_after) is not None: resp.headers.add( 'Set-Cookie', 'redirect=' + redirect_after + '; Max-Age=180; SameSite=None; HttpOnly; Secure') else: resp.headers.add( 'Set-Cookie', 'redirect=/; Max-Age=180; SameSite=None; HttpOnly; Secure') return resp
def authorize(): logger.info("endpoint: authorize") redirect_uri = url_for('user.authorize', _external=True, _scheme='https') oauth.discord.authorize_access_token(redirect_uri=redirect_uri) resp = oauth.discord.get('users/@me') profile = resp.json() # do something with the token and profile update_web_user(profile) redirect_cookie = str(request.cookies.get("redirect")) if relative_url_regex.fullmatch(redirect_cookie) is not None: redirection = FRONTEND_URL + redirect_cookie else: redirection = FRONTEND_URL + "/" session.pop("redirect", None) return redirect(redirection)
def convert_bw(): logger.info("endpoint: convert bw") url = flask.request.args.get("url", default=None, type=str) logger.info(f"args: url: {url}") if not url: logger.info("no url") flask.abort(415, "url not specified") parsed_url = urllib.parse.urlparse(url) logger.info(f"parsed url: {parsed_url}") if parsed_url.netloc not in valid_endpoints: logger.info("invalid url") flask.abort(415, "invalid url") image, content_type = asyncio.run(_bw_helper(url)) return flask.send_file(image, mimetype=content_type)
def skip_bird(): logger.info("endpoint: skip bird") session_id = get_session_id() user_id = int(database.hget(f"web.session:{session_id}", "user_id")) currentBird = database.hget(f"web.session:{session_id}", "bird").decode("utf-8") if currentBird != "": # check if there is bird database.hset(f"web.session:{session_id}", "bird", "") database.hset(f"web.session:{session_id}", "answered", "1") if user_id != 0: streak_increment(user_id, None) # reset streak scibird = asyncio.run(get_sciname(currentBird)) url = get_wiki_url(currentBird) # sends wiki page else: logger.info("bird is blank") flask.abort(406, "Bird is blank") return {"answer": currentBird, "sciname": scibird, "wiki": url}
def bird_info(): logger.info("fetching random bird") content = {} bird = random.choice(birdList) logger.info(f"bird: {bird}") content["bird"] = bird content["sciName"] = asyncio.run(get_sciname(bird)) content["imageURL"] = urllib.parse.quote(f"/image/{bird}") content["songURL"] = urllib.parse.quote(f"/song/{bird}") logger.info(f"{bird} sent!") return content
def logout(): logger.info("endpoint: logout") redirect_after = request.args.get("redirect", FRONTEND_URL, str) if relative_url_regex.fullmatch(redirect_after) is not None: redirect_url = redirect_after else: redirect_url = FRONTEND_URL session_id = get_session_id() user_id = verify_session(session_id) if isinstance(int, user_id): logger.info("deleting user data, session data") database.delete(f"web.user:{user_id}", f"web.session:{session_id}") session.clear() else: logger.info("deleting session data") database.delete(f"web.session:{session_id}") session.clear() return redirect(redirect_url)
def handle_authlib_error(e): logger.info(f"error with oauth login: {e}") capture_exception(e) return 'An error occurred with the login', 500
def check_bird(): logger.info("endpoint: check bird") bird_guess = flask.request.args.get("guess", "", str) session_id = get_session_id() user_id = int(database.hget(f"web.session:{session_id}", "user_id")) currentBird = database.hget(f"web.session:{session_id}", "bird").decode("utf-8") if currentBird == "": # no bird logger.info("bird is blank") flask.abort(406, "Bird is blank") elif bird_guess == "": logger.info("empty guess") flask.abort(406, "Empty guess") # if there is a bird, it checks answer logger.info("currentBird: " + str(currentBird.lower().replace("-", " "))) logger.info("args: " + str(bird_guess.lower().replace("-", " "))) sciBird = asyncio.run(get_sciname(currentBird)) if spellcheck(bird_guess, currentBird) or spellcheck(bird_guess, sciBird): logger.info("correct") database.hset(f"web.session:{session_id}", "bird", "") database.hset(f"web.session:{session_id}", "answered", "1") tempScore = int(database.hget(f"web.session:{session_id}", "tempScore")) if user_id != 0: bird_setup(user_id, currentBird) score_increment(user_id, 1) session_increment(user_id, "correct", 1) streak_increment(user_id, 1) elif tempScore >= 10: logger.info("trial maxed") flask.abort(403, "Sign in to continue") else: database.hset(f"web.session:{session_id}", "tempScore", str(tempScore + 1)) url = get_wiki_url(currentBird) return { "guess": bird_guess, "answer": currentBird, "sciname": sciBird, "status": "correct", "wiki": url, } logger.info("incorrect") database.hset(f"web.session:{session_id}", "bird", "") database.hset(f"web.session:{session_id}", "answered", "1") database.zincrby("incorrect:global", 1, currentBird) if user_id != 0: bird_setup(user_id, currentBird) incorrect_increment(user_id, currentBird, 1) session_increment(user_id, "incorrect", 1) streak_increment(user_id, None) # reset streak url = get_wiki_url(currentBird) return { "guess": bird_guess, "answer": currentBird, "sciname": sciBird, "status": "incorrect", "wiki": url, }
def get_bird(): logger.info("endpoint: get bird") session_id = get_session_id() media_type = flask.request.args.get("media", "images", str) filters = Filter.parse(flask.request.args.get("addon", "", str)) if bool(flask.request.args.get("bw", 0, int)): filters.bw = True logger.info(f"args: media: {media_type}; filters: {filters};") logger.info( "bird: " + database.hget(f"web.session:{session_id}", "bird").decode("utf-8") ) tempScore = int(database.hget(f"web.session:{session_id}", "tempScore")) if tempScore >= 10: logger.info("trial maxed") flask.abort(403, "Sign in to continue") if media_type not in ("images", "songs"): logger.error(f"invalid media type {media_type}") flask.abort(406, "Invalid media type") answered = int(database.hget(f"web.session:{session_id}", "answered")) logger.info(f"answered: {answered}") # check to see if previous bird was answered if answered: # if yes, give a new bird id_list = songBirds if media_type == "songs" else birdList currentBird = random.choice(id_list) user_id = int(database.hget(f"web.session:{session_id}", "user_id")) if user_id != 0: session_increment(user_id, "total", 1) increment_bird_frequency(currentBird, user_id) prevB = database.hget(f"web.session:{session_id}", "prevB").decode("utf-8") while currentBird == prevB and len(id_list) > 1: currentBird = random.choice(id_list) database.hset(f"web.session:{session_id}", "prevB", str(currentBird)) database.hset(f"web.session:{session_id}", "bird", str(currentBird)) database.hset(f"web.session:{session_id}", "media_type", str(media_type)) logger.info("currentBird: " + str(currentBird)) database.hset(f"web.session:{session_id}", "answered", "0") file_object, ext = asyncio.run(send_bird(currentBird, media_type, filters)) else: # if no, give the same bird file_object, ext = asyncio.run( send_bird( database.hget(f"web.session:{session_id}", "bird").decode("utf-8"), database.hget(f"web.session:{session_id}", "media_type").decode( "utf-8" ), filters, ) ) logger.info(f"file_object: {file_object}") logger.info(f"extension: {ext}") return flask.send_file(file_object, attachment_filename=f"bird.{ext}")
def api_index(): logger.info("index page accessed") return "<h1>Hello!</h1><p>This is the index page for the Bird-ID internal API.<p>"
def check_bird(): logger.info("endpoint: check bird") bird_guess = request.args.get("guess", "", str) session_id = get_session_id() user_id = int(database.hget(f"web.session:{session_id}", "user_id")) currentBird = database.hget(f"web.session:{session_id}", "bird").decode("utf-8") if currentBird == "": # no bird logger.info("bird is blank") abort(406, "Bird is blank") elif bird_guess == "": logger.info("empty guess") abort(406, "Empty guess") else: # if there is a bird, it checks answer logger.info("currentBird: " + str(currentBird.lower().replace("-", " "))) logger.info("args: " + str(bird_guess.lower().replace("-", " "))) bird_setup(user_id, currentBird) sciBird = asyncio.run(get_sciname(currentBird)) if spellcheck(bird_guess, currentBird) or spellcheck( bird_guess, sciBird): logger.info("correct") database.hset(f"web.session:{session_id}", "bird", "") database.hset(f"web.session:{session_id}", "answered", "1") tempScore = int( database.hget(f"web.session:{session_id}", "tempScore")) if user_id != 0: database.zincrby("users:global", 1, str(user_id)) database.zincrby("streak:global", 1, str(user_id)) # check if streak is greater than max, if so, increases max if database.zscore("streak:global", str(user_id)) > database.zscore( "streak.max:global", str(user_id)): database.zadd( "streak.max:global", { str(user_id): database.zscore("streak:global", str(user_id)) }) elif tempScore >= 10: logger.info("trial maxed") abort(403, "Sign in to continue") else: database.hset(f"web.session:{session_id}", "tempScore", str(tempScore + 1)) url = get_wiki_url(currentBird) return { "guess": bird_guess, "answer": currentBird, "sciname": sciBird, "status": "correct", "wiki": url } else: logger.info("incorrect") database.hset(f"web.session:{session_id}", "bird", "") database.hset(f"web.session:{session_id}", "answered", "1") database.zincrby("incorrect:global", 1, currentBird) if user_id != 0: database.zadd("streak:global", {str(user_id): 0}) database.zincrby(f"incorrect.user:{user_id}", 1, currentBird) url = get_wiki_url(currentBird) return { "guess": bird_guess, "answer": currentBird, "sciname": sciBird, "status": "incorrect", "wiki": url }
def get_bird(): logger.info("endpoint: get bird") session_id = get_session_id() media_type = request.args.get("media", "images", str) addon = request.args.get("addon", "", str) bw = bool(request.args.get("bw", 0, int)) logger.info(f"args: media: {media_type}; addon: {addon}; bw: {bw};") logger.info( "bird: " + database.hget(f"web.session:{session_id}", "bird").decode("utf-8")) tempScore = int(database.hget(f"web.session:{session_id}", "tempScore")) if tempScore >= 10: logger.info("trial maxed") abort(403, "Sign in to continue") if media_type != "images" and media_type != "songs": logger.error(f"invalid media type {media_type}") abort(406, "Invalid media type") return answered = int(database.hget(f"web.session:{session_id}", "answered")) logger.info(f"answered: {answered}") # check to see if previous bird was answered if answered: # if yes, give a new bird currentBird = random.choice(birdList) prevB = database.hget(f"web.session:{session_id}", "prevB").decode("utf-8") while currentBird == prevB and len(birdList) > 1: currentBird = random.choice(birdList) database.hset(f"web.session:{session_id}", "prevB", str(currentBird)) database.hset(f"web.session:{session_id}", "bird", str(currentBird)) database.hset(f"web.session:{session_id}", "media_type", str(media_type)) logger.info("currentBird: " + str(currentBird)) database.hset(f"web.session:{session_id}", "answered", "0") file_object, ext = asyncio.run( send_bird(currentBird, media_type, addon, bw)) else: # if no, give the same bird file_object, ext = asyncio.run( send_bird( database.hget(f"web.session:{session_id}", "bird").decode("utf-8"), str(database.hget(f"web.session:{session_id}", "media_type"))[2:-1], addon, bw)) logger.info(f"file_object: {file_object}") logger.info(f"extension: {ext}") return flask.send_file(file_object, attachment_filename=f"bird.{ext}")