Skip to content

Commit b562c5e

Browse files
authored
Merge pull request #206 from devinmatte/admin_ui
Admin UI
2 parents b9c3a6d + 4a900d9 commit b562c5e

File tree

18 files changed

+484
-96
lines changed

18 files changed

+484
-96
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ ENV/
103103
# JetBrains
104104
.idea/
105105

106+
# vscode
107+
.vscode
108+
106109
# Configurations
107110
config.py
108111

@@ -128,3 +131,5 @@ packet/static/safari-pinned-tab.svg
128131
packet/static/site.webmanifest
129132
faviconData.json
130133

134+
# csvs
135+
*.csv

packet/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080

8181
if app.config['REALM'] == 'csh':
8282
from .routes import upperclassmen
83+
from .routes import admin
8384
else:
8485
from .routes import freshmen
8586

packet/commands.py

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from .ldap import ldap_get_eboard_role, ldap_get_active_rtps, ldap_get_3das, ldap_get_webmasters, \
1717
ldap_get_drink_admins, ldap_get_constitutional_maintainers, ldap_is_intromember, ldap_get_active_members, \
1818
ldap_is_on_coop
19+
from .utils import sync_freshman
1920

2021

2122
@app.cli.command('create-secret')
@@ -66,40 +67,7 @@ def sync_freshmen(freshmen_csv):
6667
freshmen_in_csv = parse_csv(freshmen_csv)
6768

6869
print('Syncing contents with the DB...')
69-
freshmen_in_db = {freshman.rit_username: freshman for freshman in Freshman.query.all()}
70-
71-
for csv_freshman in freshmen_in_csv.values():
72-
if csv_freshman.rit_username not in freshmen_in_db:
73-
# This is a new freshman so add them to the DB
74-
freshmen_in_db[csv_freshman.rit_username] = Freshman(rit_username=csv_freshman.rit_username,
75-
name=csv_freshman.name, onfloor=csv_freshman.onfloor)
76-
db.session.add(freshmen_in_db[csv_freshman.rit_username])
77-
else:
78-
# This freshman is already in the DB so just update them
79-
freshmen_in_db[csv_freshman.rit_username].onfloor = csv_freshman.onfloor
80-
freshmen_in_db[csv_freshman.rit_username].name = csv_freshman.name
81-
82-
# Update all freshmen entries that represent people who are no longer freshmen
83-
for freshman in filter(lambda freshman: freshman.rit_username not in freshmen_in_csv, freshmen_in_db.values()):
84-
freshman.onfloor = False
85-
86-
# Update the freshmen signatures of each open or future packet
87-
for packet in Packet.query.filter(Packet.end > datetime.now()).all():
88-
# Handle the freshmen that are no longer onfloor
89-
for fresh_sig in filter(lambda fresh_sig: not fresh_sig.freshman.onfloor, packet.fresh_signatures):
90-
FreshSignature.query.filter_by(packet_id=fresh_sig.packet_id,
91-
freshman_username=fresh_sig.freshman_username).delete()
92-
93-
# Add any new onfloor freshmen
94-
# pylint: disable=cell-var-from-loop
95-
current_fresh_sigs = set(map(lambda fresh_sig: fresh_sig.freshman_username, packet.fresh_signatures))
96-
for csv_freshman in filter(lambda csv_freshman: csv_freshman.rit_username not in current_fresh_sigs and
97-
csv_freshman.onfloor and
98-
csv_freshman.rit_username != packet.freshman_username,
99-
freshmen_in_csv.values()):
100-
db.session.add(FreshSignature(packet=packet, freshman=freshmen_in_db[csv_freshman.rit_username]))
101-
102-
db.session.commit()
70+
sync_freshman(freshmen_in_csv)
10371
print('Done!')
10472

10573

packet/context_processors.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def get_roles(sig):
4343

4444

4545
# pylint: disable=bare-except
46-
@lru_cache(maxsize=128)
46+
@lru_cache(maxsize=256)
4747
def get_rit_name(username):
4848
try:
4949
freshman = Freshman.query.filter_by(rit_username=username).first()
@@ -53,7 +53,7 @@ def get_rit_name(username):
5353

5454

5555
# pylint: disable=bare-except
56-
@lru_cache(maxsize=128)
56+
@lru_cache(maxsize=256)
5757
def get_rit_image(username):
5858
if username:
5959
addresses = [username + '@rit.edu', username + '@g.rit.edu']

packet/ldap.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,23 @@ def ldap_get_eboard_role(member):
149149

150150
return return_val
151151

152-
# Status checkers
153152

153+
# Status checkers
154154
def ldap_is_eboard(member):
155155
"""
156156
:param member: A CSHMember instance
157157
"""
158158
return _ldap_is_member_of_group(member, 'eboard')
159159

160160

161+
def ldap_is_evals(member):
162+
return _ldap_is_member_of_group(member, 'eboard-evaluations')
163+
164+
165+
def ldap_is_rtp(member):
166+
return _ldap_is_member_of_group(member, 'rtp')
167+
168+
161169
def ldap_is_intromember(member):
162170
"""
163171
:param member: A CSHMember instance

packet/models.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ def by_username(cls, username: str):
4949
"""
5050
return cls.query.filter_by(rit_username=username).first()
5151

52+
@classmethod
53+
def get_all(cls):
54+
"""
55+
Helper method to get all freshmen easily
56+
"""
57+
return cls.query.all()
58+
5259

5360
class Packet(db.Model):
5461
__tablename__ = 'packet'

packet/routes/admin.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from flask import render_template
2+
3+
from packet import app
4+
from packet.models import Packet, Freshman
5+
from packet.routes.shared import packet_sort_key
6+
from packet.utils import before_request, packet_auth, admin_auth
7+
from packet.log_utils import log_cache, log_time
8+
9+
10+
@app.route('/admin/packets')
11+
@log_cache
12+
@packet_auth
13+
@admin_auth
14+
@before_request
15+
@log_time
16+
def admin_packets(info=None):
17+
open_packets = Packet.open_packets()
18+
19+
# Pre-calculate and store the return values of did_sign(), signatures_received(), and signatures_required()
20+
for packet in open_packets:
21+
packet.did_sign_result = packet.did_sign(info['uid'], app.config['REALM'] == 'csh')
22+
packet.signatures_received_result = packet.signatures_received()
23+
packet.signatures_required_result = packet.signatures_required()
24+
25+
open_packets.sort(key=packet_sort_key, reverse=True)
26+
27+
return render_template('admin_packets.html',
28+
open_packets=open_packets,
29+
info=info)
30+
31+
32+
@app.route('/admin/freshmen')
33+
@log_cache
34+
@packet_auth
35+
@admin_auth
36+
@before_request
37+
@log_time
38+
def admin_freshmen(info=None):
39+
all_freshmen = Freshman.get_all()
40+
41+
return render_template('admin_freshmen.html',
42+
all_freshmen=all_freshmen,
43+
info=info)

packet/routes/api.py

Lines changed: 27 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,22 @@
1212
from packet.ldap import ldap_get_eboard_role, ldap_get_active_rtps, ldap_get_3das, ldap_get_webmasters, \
1313
ldap_get_drink_admins, ldap_get_constitutional_maintainers, ldap_is_intromember, ldap_get_active_members, \
1414
ldap_is_on_coop, _ldap_is_member_of_group, ldap_get_member
15+
from packet.log_utils import log_time
1516
from packet.mail import send_report_mail, send_start_packet_mail
16-
from packet.utils import before_request, packet_auth, notify_slack
17+
from packet.utils import before_request, packet_auth, notify_slack, sync_freshman as sync_freshman_list
1718
from packet.models import Packet, MiscSignature, NotificationSubscription, Freshman, FreshSignature, UpperSignature
1819
from packet.notifications import packet_signed_notification, packet_100_percent_notification, \
19-
packet_starting_notification, packets_starting_notification
20+
packet_starting_notification, packets_starting_notification
2021
import packet.stats as stats
2122

2223

24+
class POSTFreshman:
25+
def __init__(self, freshman):
26+
self.name = freshman['name'].strip()
27+
self.rit_username = freshman['rit_username'].strip()
28+
self.onfloor = freshman['onfloor'].strip() == 'TRUE'
29+
30+
2331
@app.route('/api/v1/freshmen', methods=['POST'])
2432
@packet_auth
2533
def sync_freshman():
@@ -40,47 +48,14 @@ def sync_freshman():
4048
if not _ldap_is_member_of_group(ldap_get_member(username), 'eboard-evaluations'):
4149
return 'Forbidden: not Evaluations Director', 403
4250

43-
freshmen = request.json
44-
results = list()
45-
46-
packets = Packet.query.filter(Packet.end > datetime.now()).all()
47-
48-
for freshman in freshmen:
49-
rit_username = freshman['rit_username']
50-
name = freshman['name']
51-
onfloor = freshman['onfloor']
52-
53-
frosh = Freshman.query.filter_by(rit_username=rit_username).first()
54-
if frosh:
55-
if onfloor and not frosh.onfloor:
56-
# Add new onfloor signature
57-
for packet in packets:
58-
db.session.add(FreshSignature(packet=packet, freshman=frosh))
59-
elif not onfloor and frosh.onfloor:
60-
# Remove outdated onfloor signature
61-
for packet in packets:
62-
FreshSignature.query.filter_by(packet_id=packet.id, freshman_username=frosh.rit_username).delete()
63-
64-
frosh.name = name
65-
frosh.onfloor = onfloor
66-
67-
results.append(f"'{name} ({rit_username})' updated")
68-
else:
69-
frosh = Freshman(rit_username=rit_username, name=name, onfloor=onfloor)
70-
db.session.add(frosh)
71-
if onfloor:
72-
# Add onfloor signature
73-
for packet in packets:
74-
db.session.add(FreshSignature(packet=packet, freshman=frosh))
75-
76-
results.append(f"Freshman '{name} ({rit_username})' created")
77-
78-
db.session.commit()
79-
return dumps(results), 200
51+
freshmen_in_post = {freshman.rit_username: freshman for freshman in map(POSTFreshman, request.json)}
52+
sync_freshman_list(freshmen_in_post)
53+
return dumps('Done'), 200
8054

8155

8256
@app.route('/api/v1/packets', methods=['POST'])
8357
@packet_auth
58+
@log_time
8459
def create_packet():
8560
"""
8661
Create a new packet.
@@ -163,7 +138,7 @@ def get_packets_by_user(username: str) -> dict:
163138
return {packet.id: {
164139
'start': packet.start,
165140
'end': packet.end,
166-
} for packet in frosh.packets}
141+
} for packet in frosh.packets}
167142

168143

169144
@app.route('/api/v1/packets/<username>/newest', methods=['GET'])
@@ -177,13 +152,13 @@ def get_newest_packet_by_user(username: str) -> dict:
177152
packet = frosh.packets[-1]
178153

179154
return {
180-
packet.id: {
181-
'start': packet.start,
182-
'end': packet.end,
183-
'required': vars(packet.signatures_required()),
184-
'received': vars(packet.signatures_received()),
185-
}
186-
}
155+
packet.id: {
156+
'start': packet.start,
157+
'end': packet.end,
158+
'required': vars(packet.signatures_required()),
159+
'received': vars(packet.signatures_received()),
160+
}
161+
}
187162

188163

189164
@app.route('/api/v1/packet/<packet_id>', methods=['GET'])
@@ -196,9 +171,10 @@ def get_packet_by_id(packet_id: int) -> dict:
196171
packet = Packet.by_id(packet_id)
197172

198173
return {
199-
'required': vars(packet.signatures_required()),
200-
'received': vars(packet.signatures_received()),
201-
}
174+
'required': vars(packet.signatures_required()),
175+
'received': vars(packet.signatures_received()),
176+
}
177+
202178

203179
@app.route('/api/v1/sign/<packet_id>/', methods=['POST'])
204180
@packet_auth
@@ -264,6 +240,7 @@ def packet_stats(packet_id):
264240
def upperclassman_stats(uid):
265241
return stats.upperclassman_stats(uid)
266242

243+
267244
def commit_sig(packet, was_100, uid):
268245
packet_signed_notification(packet, uid)
269246
db.session.commit()

packet/routes/shared.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
@app.route('/logout/')
1414
@auth.oidc_logout
1515
def logout():
16-
return redirect('http://csh.rit.edu')
16+
return redirect('https://csh.rit.edu')
1717

1818

1919
@app.route('/packet/<packet_id>/')

0 commit comments

Comments
 (0)