Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
969c014
feat: moved advent folder -> puzzles, added some comments
May 22, 2022
a185ac6
merge: merged Ryan's database changes
May 22, 2022
3c6bf1b
feat(docker): start separation of dev and prod builds, add pytest fun…
May 24, 2022
058e55d
feat(docker): added dev/prod to frontend, transition frontend to yarn
May 25, 2022
8b881a3
merge: merged pipfile.lock changes
May 25, 2022
35f53c8
fix: remove .vscode folder
May 25, 2022
1048ded
fix(makefile): restructured makefile a bit
May 25, 2022
f23884d
feat: removed .vscode folder from git
May 26, 2022
af94b47
feat(auth): get rudimentary autotesting in place, created clear_datab…
May 31, 2022
2adacb2
feat(test): added all tests for auth/register
Jun 9, 2022
511b4a1
fix(puzzle): changed blueprint in routes/puzzle.py
Jun 12, 2022
6e89290
fix merge conflict from main
Jun 12, 2022
814909b
feat(auth): refactored registration system, database connections
Jul 2, 2022
88010fe
fix(auth): minor changes to constructor
Jul 2, 2022
03fb576
feat(auth): implement email verification endpoints
Jul 3, 2022
439491b
feat(test): using fixtures
Jul 3, 2022
9262969
feat(auth): finish autotests, still needs commenting
Jul 4, 2022
3f1aa59
feat(auth): finished writing tests for the most part
Jul 4, 2022
03274db
feat(auth): complete tests for basic auth system
Jul 20, 2022
4f9fe01
merged from main
Jul 20, 2022
689900e
fix(auth): removed duplicate clear_database function
Jul 20, 2022
5800055
fix(auth): add basic lockout functionality
Aug 4, 2022
fe4f962
merge: merged in new database stuff from main
Aug 4, 2022
8252711
fix(auth): fix clear_database utility function
Aug 9, 2022
6027f1d
fix(auth): change requests to conform with DB
Aug 9, 2022
1eb635b
fix(auth): add basic lockout to /login route
Aug 9, 2022
a27c0d9
merge: merged from main
Aug 9, 2022
77c2b16
feat(auth): add function to carry over CSRF in headers
Aug 9, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 16 additions & 34 deletions backend/common/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,18 +147,6 @@ def checkInput(compName, dayNum, uid, solution):
# note: for more advanced processing, we might consider having a timeout if a user tries too many things too quickly
# but idk how to implement this too well

# Get all the information about a user given their uid
# Returns all information in the form of a dictionary
def getUserInfo(uid):
query = f"""
select * from Users where uid = {uid};
"""
cur.execute(query)

# only one entry should be returned since day number is unique
t = cur.fetchone()
return t

# Get all the information about a user's stats in a certain competition
# Returns all information in the form of a list of 'solved objects'
def getUserStatsPerComp(compName, uid):
Expand All @@ -172,23 +160,7 @@ def getUserStatsPerComp(compName, uid):
right outer join Parts p on s.pid = p.pid
join Questions q on p.qid = q.qid
join Competitions c on q.cid = c.cid
where s.uid = {uid} and c.name = '{compName}';
"""
cur.execute(query)

return cur.fetchall()

# Get only the number of stars and points for a user.
# Returns extremely simple info
def getBasicUserStatsPerComp(compName, uid):

# A right outer join returns all the results from the parts table, even if there is no solves
# Best to look up examples :D
# Use this information to deduce whether a user has solved a part or not
query = f"""
select u.username, u.github, s.numStars, s.score from Stats s
right outer join Users u
where s.uid = {uid} and c.name = '{compName}';
where i.uid = {uid} and c.name = {compName};
"""
cur.execute(query)

Expand Down Expand Up @@ -217,12 +189,22 @@ def getAllCompetitions():
def updateUsername(username, uid):
query = f"""
update Users
set username = '{username}'
set username = {username}
where uid = {uid};
"""
cur.execute(query)
conn.commit()
'''
cursor.close()
conn.close()
'''

# DO NOT EVER EXECUTE THIS FUNCTION BRUH
def dropDatabase():
query = f"""
SELECT 'DROP TABLE IF EXISTS "' || tablename || '" CASCADE;'
from
pg_tables WHERE schemaname = 'advent';
"""
cur.execute(query)
conn.commit()

def clear_database():
conn = get_connection()
cursor = conn.cursor()
56 changes: 50 additions & 6 deletions backend/common/redis.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,50 @@
import redis

# We're using Redis as a way to store codes with expiry dates - it might a bit
# overkill, but it works

cache = redis.Redis(host="redis", port=6379, db=0)
from datetime import timedelta
import redis

# We're using Redis as a way to store codes with expiry dates - it might a bit
# overkill, but it works

MINUTES_IN_DAY = 1440

cache = redis.Redis(host="redis", port=6379, db=0)

## EMAIL VERIFICATION

## LOCKOUT

def register_incorrect(id):
times = cache.get(f"attempts_{id}")

if times is None:
times = 0

cache.set(f"attempts_{id}", int(times) + 1)

def incorrect_attempts(id):
attempts = cache.get(f"attempts_{id}")

if attempts is None:
return 0
else:
return int(attempts)

def calculate_time(attempts):
if attempts < 3:
return 0

minutes = 2 ** (attempts - 3)

if minutes > MINUTES_IN_DAY:
return MINUTES_IN_DAY
else:
return minutes

def block(id, time):
cache.set(f"block_{id}", "", ex=timedelta(minutes=time))

def is_blocked(id):
token = cache.get(f"block_{id}")
return token is not None

def clear_redis():
cache.flushdb()
56 changes: 28 additions & 28 deletions backend/database/database.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import os
from psycopg2.pool import ThreadedConnectionPool
user = os.environ["POSTGRES_USER"]
password = os.environ["POSTGRES_PASSWORD"]
host = os.environ["POSTGRES_HOST"]
port = os.environ["POSTGRES_PORT"]
database = os.environ["POSTGRES_DB"]
# TABLES = ["Users", "Questions", "Parts", "Competitions", "Inputs", "Solves"]
db = ThreadedConnectionPool(
1, 20,
user=user,
password=password,
host=host,
port=port,
database=database
)
def clear_database():
conn = db.getconn()
with conn.cursor() as cursor:
cursor.execute(f"""SELECT truncate_tables();""")
conn.commit()
db.putconn(conn)
import os
from psycopg2.pool import ThreadedConnectionPool

user = os.environ["POSTGRES_USER"]
password = os.environ["POSTGRES_PASSWORD"]
host = os.environ["POSTGRES_HOST"]
port = os.environ["POSTGRES_PORT"]
database = os.environ["POSTGRES_DB"]

# TABLES = ["Users", "Questions", "Parts", "Competitions", "Inputs", "Solves"]

db = ThreadedConnectionPool(
1, 20,
user=user,
password=password,
host=host,
port=port,
database=database
)

def clear_database():
conn = db.getconn()

with conn.cursor() as cursor:
cursor.execute(f"""SELECT truncate_tables();""")
conn.commit()

db.putconn(conn)
149 changes: 93 additions & 56 deletions backend/database/user.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,93 @@
from database.database import db


def add_user(email, username, password) -> int:
"""Adds a user to the database, returning their ID."""

conn = db.getconn()

with conn.cursor() as cursor:
cursor.execute(f"INSERT INTO Users (email, username, password) VALUES ('{email}', '{username}', '{password}')")
conn.commit()

cursor.execute(f"SELECT uid FROM Users WHERE email = '{email}'")
id = cursor.fetchone()[0]

db.putconn(conn)
return id


def fetch_user(email: str):
"""Given a user's email, fetches their content from the database."""

conn = db.getconn()

with conn.cursor() as cursor:
cursor.execute(f"SELECT * FROM Users WHERE email = '{email}'")
result = cursor.fetchone()

db.putconn(conn)
return result


def email_exists(email: str) -> bool:
"""Checks if an email exists in the users table."""

conn = db.getconn()

with conn.cursor() as cursor:
cursor.execute(f"SELECT * FROM Users WHERE email = '{email}'")
results = cursor.fetchall()

db.putconn(conn)
return results != []


def username_exists(username: str) -> bool:
"""Checks if a username is already used."""

conn = db.getconn()

with conn.cursor() as cursor:
cursor.execute(f"SELECT * FROM Users WHERE username = '{username}'")
results = cursor.fetchall()

db.putconn(conn)
return results != []
from database.database import db

# Get all the information about a user given their uid
# Returns all information in the form of a dictionary
def get_user_info(uid):
conn = db.getconn()

with conn.cursor() as cursor:
query = f"""
select * from Users where uid = {uid};
"""
cursor.execute(query)

# only one entry should be returned since day number is unique
t = cursor.fetchone()

db.putconn(conn)
return t


def add_user(email, username, password) -> int:
"""Adds a user to the database, returning their ID."""

conn = db.getconn()

with conn.cursor() as cursor:
cursor.execute("INSERT INTO Users (email, username, password) VALUES (%s, %s, %s)",
(email, username, password))
conn.commit()

cursor.execute("SELECT uid FROM Users WHERE email = %s", (email,))
id = cursor.fetchone()[0]

db.putconn(conn)
return id


def fetch_id(email: str):
"""Given a user's email, fetches their ID."""

conn = db.getconn()

with conn.cursor() as cursor:
cursor.execute("SELECT uid FROM Users WHERE email = %s", (email,))
result = cursor.fetchone()

if result is None:
db.putconn(conn)
return None

id = result[0]

db.putconn(conn)
return id


def fetch_user(email: str):
"""Given a user's email, fetches their content from the database."""

conn = db.getconn()

with conn.cursor() as cursor:
cursor.execute("SELECT * FROM Users WHERE email = %s", (email,))
result = cursor.fetchone()

db.putconn(conn)
return result


def email_exists(email: str) -> bool:
"""Checks if an email exists in the users table."""

conn = db.getconn()

with conn.cursor() as cursor:
cursor.execute("SELECT * FROM Users WHERE email = %s", (email,))
results = cursor.fetchall()

db.putconn(conn)
return results != []


def username_exists(username: str) -> bool:
"""Checks if a username is already used."""

conn = db.getconn()

with conn.cursor() as cursor:
cursor.execute("SELECT * FROM Users WHERE username = %s", (username,))
results = cursor.fetchall()

db.putconn(conn)
return results != []
Loading