Skip to content

Commit 93bb364

Browse files
authored
Merge pull request #77 from ComputerScienceHouse/develop
Version 3.0.3
2 parents 482aaff + 89de12c commit 93bb364

File tree

15 files changed

+247
-108
lines changed

15 files changed

+247
-108
lines changed

README.md

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,48 @@
1-
*Coming soon to a repo near you*
1+
CSH Web Packet
2+
==============
3+
4+
[![Python 3.6](https://img.shields.io/badge/python-3.6-blue.svg)](https://www.python.org/downloads/release/python-360/)
5+
[![Build Status](https://travis-ci.org/ComputerScienceHouse/packet.svg?branch=develop)](https://travis-ci.org/ComputerScienceHouse/packet)
6+
7+
Web Packet is used by CSH to facilitate the evaluations of our members and keep track of packet signatures on the web
8+
9+
Authorization
10+
-------------
11+
12+
Authentication happens via pyOIDC with CSH SSO, authenticating as the user who is viewing the page.
13+
We have two different realms, and the site changes depending which realm is in use.
14+
15+
The server uses heavy caching via lru_cache to speed up the results as much as possible
16+
17+
Setup
18+
------
19+
20+
For local development setup follow these steps:
21+
22+
1. ```pip install -r requirements.txt```
23+
2. `Create config.py` or set environment variables
24+
- Several of these variables require keys and information, please reach out to an RTP for testing information
25+
3. Run `wsgi.py`
26+
27+
28+
Commands
29+
--------
30+
31+
The flask CLI provides all the methods needed to setup a packet and a packet season
32+
33+
```
34+
create-packets Creates a new packet season for each of the freshmen in the given CSV.
35+
create-secret Generates a securely random token.
36+
db Perform database migrations.
37+
ldap-sync Updates the upper and misc sigs in the DB to match ldap.
38+
sync-freshmen Updates the freshmen entries in the DB to match the given CSV.
39+
fetch-results Fetches and prints the results from a given packet season.
40+
```
41+
42+
Code Standards
43+
------------
44+
45+
Use Pylint to ensure your code follows standards. Commits will be pylinted by Travis CI, if your
46+
build fails you must fix whatever it tells you is wrong before it will be merged.
47+
48+
To check locally, run ```pylint packet```

frontend/scss/partials/_base.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ body {
1212
display: flex;
1313
justify-content: space-between;
1414
}
15+
16+
.right-align {
17+
float: right;
18+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"title": "CSH Packet",
33
"name": "csh-packet",
4-
"version": "3.0.2",
4+
"version": "3.0.3",
55
"description": "A webpacket for CSH",
66
"bugs": {
77
"url": "https://github.com/ComputerScienceHouse/packet/issues",

packet/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "3.0.2"
1+
__version__ = "3.0.3"

packet/commands.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ def create_secret():
1919
print("Here's your random secure token:")
2020
print(token_hex())
2121

22+
packet_start_time = time(hour=19)
23+
packet_end_time = time(hour=21)
24+
2225
class CSVFreshman:
2326
def __init__(self, row):
2427
self.name = row[0]
@@ -98,8 +101,8 @@ def create_packets(freshmen_csv):
98101
except ValueError:
99102
pass
100103

101-
start = datetime.combine(base_date, time(hour=19))
102-
end = datetime.combine(base_date, time(hour=23, minute=59)) + timedelta(days=14)
104+
start = datetime.combine(base_date, packet_start_time)
105+
end = datetime.combine(base_date, packet_end_time) + timedelta(days=14)
103106

104107
print("Fetching data from LDAP...")
105108
eboard = set(member.uid for member in ldap_get_eboard())
@@ -158,3 +161,45 @@ def ldap_sync():
158161

159162
db.session.commit()
160163
print("Done!")
164+
165+
@app.cli.command("fetch-results")
166+
def fetch_results():
167+
"""
168+
Fetches and prints the results from a given packet season.
169+
"""
170+
end_date = None
171+
while end_date is None:
172+
try:
173+
date_str = input("Enter the last day of the packet season you'd like to retrieve results from " +
174+
"(format: MM/DD/YYYY): ")
175+
end_date = datetime.strptime(date_str, "%m/%d/%Y").date()
176+
except ValueError:
177+
pass
178+
179+
end_date = datetime.combine(end_date, packet_end_time)
180+
181+
for packet in Packet.query.filter_by(end=end_date).all():
182+
print()
183+
184+
print("{} ({}):".format(packet.freshman.name, packet.freshman.rit_username))
185+
186+
received = packet.signatures_received()
187+
required = packet.signatures_required()
188+
189+
upper_ratio = sum((received["eboard"], received["upperclassmen"], received["miscellaneous"])) / \
190+
sum((required["eboard"], required["upperclassmen"], required["misc"]))
191+
print("\tUpperclassmen score: {}%".format(round(upper_ratio * 100, 2)))
192+
193+
total_ratio = sum(received.values()) / sum(required.values())
194+
print("\tTotal score: {}%".format(round(total_ratio * 100, 2)))
195+
196+
print()
197+
198+
print("\tEboard: {}/{}".format(received["eboard"], required["eboard"]))
199+
print("\tUpperclassmen: {}/{}".format(received["upperclassmen"], required["upperclassmen"]))
200+
print("\tFreshmen: {}/{}".format(received["freshmen"], required["freshmen"]))
201+
print("\tMisc: {}/{}".format(len(packet.misc_signatures), required["misc"]))
202+
203+
print()
204+
205+
print("\tTotal missed:", sum(required.values()) - sum(received.values()))

packet/ldap.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ def _ldap_get_group_members(group):
88
return _ldap.get_group(group).get_members()
99

1010

11-
@lru_cache(maxsize=2048)
1211
def _ldap_is_member_of_group(member, group):
1312
group_list = member.get("memberOf")
1413
for group_dn in group_list:

packet/member.py

Lines changed: 0 additions & 11 deletions
This file was deleted.

packet/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def is_open(self):
5151

5252
@lru_cache(maxsize=1024)
5353
def signatures_required(self):
54-
eboard = UpperSignature.query.filter_by(eboard=True).count()
54+
eboard = UpperSignature.query.with_parent(self).filter_by(eboard=True).count()
5555
return {'eboard': eboard,
5656
'upperclassmen': len(self.upper_signatures) - eboard,
5757
'freshmen': len(self.fresh_signatures),

packet/packet.py

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,10 @@
66

77

88
def sign(signer_username, freshman_username):
9-
if signer_username == freshman_username:
10-
return False
11-
12-
freshman_signed = Freshman.query.filter_by(rit_username=freshman_username).first()
13-
if freshman_signed is None:
14-
return False
15-
packet = freshman_signed.current_packet()
16-
if packet is None or not packet.is_open():
9+
if not valid_signature(signer_username, freshman_username):
1710
return False
1811

12+
packet = get_freshman(freshman_username).current_packet()
1913
upper_signature = UpperSignature.query.filter(UpperSignature.member == signer_username,
2014
UpperSignature.packet == packet).first()
2115
fresh_signature = FreshSignature.query.filter(FreshSignature.freshman_username == signer_username,
@@ -27,25 +21,22 @@ def sign(signer_username, freshman_username):
2721
upper_signature.signed = True
2822
elif fresh_signature:
2923
# Make sure only on floor freshmen can sign packets
30-
freshman_signer = Freshman.query.filter_by(rit_username=signer_username).first()
24+
freshman_signer = get_freshman(signer_username)
3125
if freshman_signer and not freshman_signer.onfloor:
3226
return False
3327
fresh_signature.signed = True
3428
else:
3529
db.session.add(MiscSignature(packet=packet, member=signer_username))
3630
db.session.commit()
3731

38-
# Clear functions that read signatures cache
39-
get_number_signed.cache_clear()
40-
get_signatures.cache_clear()
41-
get_upperclassmen_percent.cache_clear()
32+
clear_cache()
4233

4334
return True
4435

4536

4637
@lru_cache(maxsize=2048)
4738
def get_signatures(freshman_username):
48-
packet = Freshman.query.filter_by(rit_username=freshman_username).first().current_packet()
39+
packet = get_current_packet(freshman_username)
4940
eboard = UpperSignature.query.filter_by(packet_id=packet.id, eboard=True).order_by(UpperSignature.signed.desc())
5041
upper_signatures = UpperSignature.query.filter_by(packet_id=packet.id, eboard=False).order_by(
5142
UpperSignature.signed.desc())
@@ -57,14 +48,40 @@ def get_signatures(freshman_username):
5748
'misc': misc_signatures}
5849

5950

51+
@lru_cache(maxsize=2048)
52+
def valid_signature(signer_username, freshman_username):
53+
if signer_username == freshman_username:
54+
return False
55+
56+
freshman_signed = get_freshman(freshman_username)
57+
if freshman_signed is None:
58+
return False
59+
60+
packet = freshman_signed.current_packet()
61+
if packet is None or not packet.is_open():
62+
return False
63+
64+
return True
65+
66+
67+
@lru_cache(maxsize=512)
68+
def get_freshman(freshman_username):
69+
return Freshman.query.filter_by(rit_username=freshman_username).first()
70+
71+
72+
@lru_cache(maxsize=512)
73+
def get_current_packet(freshman_username):
74+
return get_freshman(freshman_username).current_packet()
75+
76+
6077
@lru_cache(maxsize=2048)
6178
def get_number_signed(freshman_username):
62-
return Freshman.query.filter_by(rit_username=freshman_username).first().current_packet().signatures_received()
79+
return get_current_packet(freshman_username).signatures_received()
6380

6481

65-
@lru_cache(maxsize=4096)
82+
@lru_cache(maxsize=2048)
6683
def get_number_required(freshman_username):
67-
return Freshman.query.filter_by(rit_username=freshman_username).first().current_packet().signatures_required()
84+
return get_current_packet(freshman_username).signatures_required()
6885

6986

7087
@lru_cache(maxsize=2048)
@@ -78,3 +95,27 @@ def get_upperclassmen_percent(uid):
7895
upperclassmen_signature = sum(upperclassmen_signature.values())
7996

8097
return upperclassmen_signature / upperclassmen_required * 100
98+
99+
100+
@lru_cache(maxsize=512)
101+
def signed_packets(member):
102+
# Checks whether or not member is a freshman
103+
if get_freshman(member) is not None:
104+
return FreshSignature.query.filter_by(freshman_username=member, signed=True).all()
105+
# Checks whether or not member is an upperclassman
106+
if UpperSignature.query.filter_by(member=member).first() is not None:
107+
return UpperSignature.query.filter_by(member=member, signed=True).all()
108+
return MiscSignature.query.filter_by(member=member).all()
109+
110+
111+
def clear_cache():
112+
"""
113+
Clear cache of all frequently changing data
114+
"""
115+
get_number_signed.cache_clear()
116+
get_signatures.cache_clear()
117+
get_number_required.cache_clear()
118+
get_upperclassmen_percent.cache_clear()
119+
get_freshman.cache_clear()
120+
get_current_packet.cache_clear()
121+
signed_packets.cache_clear()

packet/routes/freshmen.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from flask import redirect, render_template, request
22

33
from packet import auth, app, db
4-
from packet.models import Packet
4+
from packet.packet import get_current_packet
55
from packet.utils import before_request
66

77

@@ -16,7 +16,7 @@ def index(info=None):
1616
@auth.oidc_auth
1717
@before_request
1818
def essays(info=None):
19-
packet = Packet.query.filter_by(freshman_username=info['uid']).first()
19+
packet = get_current_packet(info['uid'])
2020
return render_template("essays.html", info=info, packet=packet)
2121

2222

@@ -25,7 +25,7 @@ def essays(info=None):
2525
@before_request
2626
def submit_essay(info=None):
2727
formdata = request.form
28-
packet = Packet.query.filter_by(freshman_username=info['uid']).first()
28+
packet = get_current_packet(info['uid'])
2929

3030
packet.info_eboard = formdata['info_eboard']
3131
packet.info_events = formdata['info_events']

0 commit comments

Comments
 (0)