Skip to content

Commit 3974a7c

Browse files
Merge pull request #8 from makeopensource/develop
Allow on-site students to re-enqueue themselves via the website
2 parents 0d16525 + ea639c8 commit 3974a7c

31 files changed

Lines changed: 790 additions & 170 deletions

api/database/db_interface.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
from api.database.idb_ratings import IRatings
55
from api.database.idb_accounts import IAccounts
66
from api.database.idb_roster import IRoster
7+
from api.database.idb_sessions import ISessions
78

89

9-
class DBInterface(IQueue, IRatings, IAccounts, IRoster, ABC):
10+
class DBInterface(IQueue, IRatings, IAccounts, IRoster, ISessions, ABC):
1011

1112
# All database implements must extend this class
1213

api/database/idb_sessions.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from abc import ABC, abstractmethod
2+
3+
4+
class ISessions(ABC):
5+
6+
@abstractmethod
7+
def update_swipe_time(self, user):
8+
""" Update time user was enqueued to current time """
9+
raise NotImplementedError()
10+
11+
@abstractmethod
12+
def reset_swipe_time(self, user):
13+
""" Reset time user was enqueued """
14+
raise NotImplementedError()
15+
16+
@abstractmethod
17+
def get_swipe_time(self, user):
18+
""" Return time user was enqueued """
19+
raise NotImplementedError()
20+
21+
@abstractmethod
22+
def get_on_site(self):
23+
""" Return list of students who have swiped in <= 2 hours
24+
who are not currently in the queue
25+
"""
26+
raise NotImplementedError()
27+
28+
@abstractmethod
29+
def clear_on_site(self):
30+
""" Reset everyone's last enqueue time """
31+
raise NotImplementedError()

api/database/idb_visits.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ def end_visit(self, visit_id, reason):
3232
"""
3333
raise NotImplementedError()
3434

35+
@abstractmethod
36+
def cancel_visit(self, visit_id):
37+
""" Destroy this visit from the database if it's still in progress.
38+
Un-dequeue this student from the queue if they have been dequeued.
39+
40+
:param visit_id:
41+
:return:
42+
"""
43+
44+
45+
raise NotImplementedError()
46+
3547
@abstractmethod
3648
def get_in_progress_visits(self):
3749
""" Return all database entries for visits that have

api/database/relational_db/relational_db.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
from api.database.relational_db.relational_db_queue import RelationalDBQueue
77
from api.database.relational_db.relational_db_accounts import RelationalDBAccounts
88
from api.database.relational_db.relational_db_ratings import RelationalDBRatings
9+
from api.database.relational_db.relational_db_sessions import RelationalDBSessions
910
from api.database.relational_db.relational_db_visits import RelationalDBVisits
1011

1112

12-
class RelationalDB(DBInterface, RelationalDBAccounts, RelationalDBQueue, RelationalDBRatings, RelationalDBVisits):
13+
class RelationalDB(DBInterface, RelationalDBAccounts, RelationalDBQueue, RelationalDBRatings, RelationalDBVisits, RelationalDBSessions):
1314

1415
def __init__(self):
1516
super().__init__()
@@ -27,7 +28,8 @@ def initialize(self):
2728
last_name VARCHAR(255),
2829
ubit VARCHAR(16) UNIQUE,
2930
person_num INTEGER UNIQUE,
30-
course_role VARCHAR(16)
31+
course_role VARCHAR(16),
32+
last_swipe TEXT
3133
);
3234
"""
3335
)
@@ -39,7 +41,8 @@ def initialize(self):
3941
user_id INTEGER UNIQUE,
4042
joined TEXT DEFAULT (datetime('now', 'localtime')),
4143
priority INTEGER,
42-
enqueue_reason TEXT
44+
enqueue_reason TEXT,
45+
dequeued BOOLEAN DEFAULT false
4346
);
4447
"""
4548
)

api/database/relational_db/relational_db_accounts.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import datetime
12
import hashlib
23
import secrets
34

@@ -86,7 +87,7 @@ def get_authenticated_user(self, auth_token):
8687
with self.cursor() as cursor:
8788
user = cursor.execute(
8889
"""
89-
SELECT preferred_name, last_name, ubit, person_num, course_role, users.user_id
90+
SELECT preferred_name, last_name, ubit, person_num, course_role, users.user_id, last_swipe
9091
FROM users
9192
INNER JOIN auth ON users.user_id = auth.user_id
9293
WHERE auth_token = ?
@@ -98,13 +99,28 @@ def get_authenticated_user(self, auth_token):
9899
if not user:
99100
return None
100101

102+
enqueue_time = user[6]
103+
104+
if enqueue_time is None:
105+
on_site = False
106+
else:
107+
# YYYY-MM-DD HH:MM:SS
108+
time_format = "%Y-%m-%d %H:%M:%S"
109+
110+
now = datetime.datetime.now()
111+
enqueue_time = datetime.datetime.strptime(enqueue_time, time_format)
112+
seconds = (now - enqueue_time).seconds
113+
114+
on_site = seconds <= 7200
115+
101116
return {
102117
"preferred_name": user[0],
103118
"last_name": user[1],
104119
"ubit": user[2],
105120
"person_num": user[3],
106121
"course_role": user[4],
107122
"user_id": user[5],
123+
"on_site": on_site
108124
}
109125

110126
def sign_up(self, username, pw) -> str | None:

api/database/relational_db/relational_db_queue.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def dequeue_student(self):
4444
ORDER BY priority DESC, joined
4545
"""
4646
).fetchone()
47-
cursor.execute("DELETE FROM queue WHERE user_id = ?", (user[0],))
47+
cursor.execute("UPDATE queue SET dequeued = true WHERE user_id = ?", (user[0],))
4848

4949
return {
5050
"user_id": user[0],
@@ -68,7 +68,7 @@ def dequeue_specified_student(self, student_id):
6868
if user is None:
6969
return None
7070

71-
cursor.execute("DELETE FROM queue WHERE user_id = ?", (user[0],))
71+
cursor.execute("UPDATE queue SET dequeued = true WHERE user_id = ?", (user[0],))
7272

7373
return {
7474
"user_id": user[0],
@@ -85,6 +85,7 @@ def get_queue(self):
8585
"""
8686
SELECT users.user_id, preferred_name, ubit, person_num
8787
FROM queue INNER JOIN users ON queue.user_id = users.user_id
88+
WHERE dequeued = false
8889
ORDER BY priority DESC, joined
8990
"""
9091
)
@@ -106,7 +107,7 @@ def get_queue(self):
106107
def clear_queue(self):
107108
with self.cursor() as cursor:
108109
cursor.execute(
109-
"DELETE FROM queue"
110+
"DELETE FROM queue WHERE dequeued = false"
110111
)
111112

112113
def remove_student(self, student):
@@ -116,6 +117,8 @@ def remove_student(self, student):
116117
if queue_info is None:
117118
return None
118119

120+
with self.cursor() as cursor:
121+
119122
cursor.execute("DELETE FROM queue WHERE user_id = ?", (student, ))
120123

121124
return {"user_id": queue_info[0], "joined": queue_info[1]}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from api.database.idb_sessions import ISessions
2+
3+
4+
class RelationalDBSessions(ISessions):
5+
6+
def update_swipe_time(self, user):
7+
with self.cursor() as cursor:
8+
cursor.execute("""
9+
UPDATE users
10+
SET last_swipe = datetime('now', 'localtime')
11+
WHERE user_id = ?
12+
""", (user,))
13+
14+
def reset_swipe_time(self, user):
15+
with self.cursor() as cursor:
16+
cursor.execute("""
17+
UPDATE users
18+
SET last_swipe = NULL
19+
WHERE user_id = ?
20+
""", (user, ))
21+
22+
def get_swipe_time(self, user):
23+
with self.cursor() as cursor:
24+
time = cursor.execute("""
25+
SELECT last_swipe FROM users
26+
WHERE last_swipe > datetime('now', 'localtime', '-2 hours') AND user_id = ?
27+
""", (user,)).fetchone()
28+
29+
if time is None:
30+
return None
31+
32+
return time[0]
33+
34+
def get_on_site(self):
35+
with self.cursor() as cursor:
36+
users = cursor.execute(
37+
"""
38+
SELECT users.user_id, preferred_name, ubit, person_num
39+
FROM users
40+
LEFT JOIN queue ON users.user_id = queue.user_id
41+
WHERE last_swipe > datetime('now', 'localtime', '-2 hours')
42+
AND queue.user_id IS NULL
43+
"""
44+
)
45+
users_l = list()
46+
for user in users:
47+
users_l.append(
48+
{
49+
"id": user[0],
50+
"preferred_name": user[1],
51+
"ubit": user[2],
52+
"pn": user[3],
53+
}
54+
)
55+
return users_l
56+
57+
def clear_on_site(self):
58+
with self.cursor as cursor:
59+
cursor.execute("""
60+
UPDATE users SET last_swipe = NULL
61+
""")

api/database/relational_db/relational_db_visits.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,36 @@ def end_visit(self, visit_id, reason):
2525
now = str(datetime.datetime.now().isoformat(' ', timespec="seconds"))
2626

2727
with self.cursor() as cursor:
28+
29+
student = cursor.execute("SELECT (student_id) from visits WHERE visit_id = ?", (visit_id, )).fetchone()
30+
31+
if student is None:
32+
return
33+
34+
student = student[0]
35+
2836
cursor.execute("""
2937
UPDATE visits
3038
SET session_end = ?, session_end_reason = ?
3139
WHERE visit_id = ? AND session_end is null
3240
""", (now, reason, visit_id))
3341

42+
self.remove_student(student)
43+
44+
def cancel_visit(self, visit_id):
45+
with self.cursor() as cursor:
46+
47+
student = cursor.execute("SELECT (student_id) from visits WHERE visit_id = ?", (visit_id,)).fetchone()
48+
49+
if student is None:
50+
return
51+
52+
student = student[0]
53+
54+
cursor.execute("DELETE from visits WHERE visit_id = ?", (visit_id,))
55+
56+
cursor.execute("UPDATE queue SET dequeued = false WHERE user_id = ?", (student, ))
57+
3458

3559
def get_in_progress_visits(self):
3660
with self.cursor() as cursor:

api/queue/controller.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import datetime
2+
13
from api.database.db import db
24

35

@@ -13,6 +15,7 @@ def add_to_queue_by_card_swipe(swipe_data):
1315
student = db.lookup_person_number(pn)
1416
if student is not None:
1517
add_to_queue(student)
18+
db.update_swipe_time(student["user_id"])
1619
return True
1720
return False
1821

@@ -24,6 +27,7 @@ def add_to_queue_by_ta_override(identifier, front=False):
2427
add_to_front_of_queue(student)
2528
else:
2629
add_to_queue(student)
30+
db.update_swipe_time(student["user_id"])
2731
return True
2832
return False
2933

@@ -46,3 +50,66 @@ def remove_from_queue_without_visit(student, reason):
4650
db.end_visit(visit, reason)
4751
return True
4852

53+
def self_add_to_queue(student):
54+
if is_active(student):
55+
db.enqueue_student(student)
56+
return True
57+
return False
58+
59+
def is_active(student):
60+
# YYYY-MM-DD HH:MM:SS
61+
time_format = "%Y-%m-%d %H:%M:%S"
62+
63+
now = datetime.datetime.now()
64+
enqueue_time = db.get_swipe_time(student)
65+
66+
if enqueue_time is None:
67+
return False
68+
69+
enqueue_time = datetime.datetime.strptime(enqueue_time, time_format)
70+
71+
seconds = (now - enqueue_time).seconds
72+
73+
if seconds > 7200:
74+
return False
75+
76+
return True
77+
78+
def get_students_visit(student):
79+
in_progress = db.get_in_progress_visits()
80+
in_progress = list(filter(lambda v: v["student_id"] == student, in_progress))
81+
82+
if len(in_progress) == 0:
83+
return None
84+
85+
86+
visit = in_progress[0]
87+
ta = db.lookup_identifier(visit["ta_id"])
88+
89+
return {
90+
"ta_name": ta["preferred_name"]
91+
}
92+
93+
94+
def get_tas_visit(ta):
95+
96+
in_progress = db.get_in_progress_visits()
97+
in_progress = list(filter(lambda v: v["ta_id"] == ta, in_progress))
98+
99+
if len(in_progress) == 0:
100+
return None
101+
102+
visit = in_progress[0]
103+
student = db.lookup_identifier(visit["student_id"])
104+
105+
return {
106+
"id": visit["student_id"],
107+
"username": student["ubit"],
108+
"pn": student["person_num"],
109+
"preferred_name": student["preferred_name"],
110+
"visitID": visit["visit_id"],
111+
"visit_reason": visit["student_visit_reason"]
112+
}
113+
114+
115+

0 commit comments

Comments
 (0)