Skip to content

Commit

Permalink
Merge Version 3.5.0 (#208)
Browse files Browse the repository at this point in the history
  • Loading branch information
mxmeinhold authored Aug 22, 2020
2 parents 1ff8d94 + 3a4d8e2 commit 35fb475
Show file tree
Hide file tree
Showing 34 changed files with 1,391 additions and 750 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ ENV/
# JetBrains
.idea/

# vscode
.vscode

# Configurations
config.py

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

# csvs
*.csv
10 changes: 9 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
language: python
python:
- "3.7"
services:
- "docker"

install:
- "pip install -r requirements.txt"
- "curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.35.3/install.sh | bash"
- "nvm install"
- "nvm use"
- "npm install -g gulp"
- "npm install"
script:
- "pylint --load-plugins pylint_quotes packet/routes packet"
- "gulp lint"
- "docker build -t packet ."
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ fail blocking you from merging. To make your life easier just run it before maki

To run pylint use this command:
```bash
pylint packet
pylint --load-plugins pylint_quotes packet/routes packet
```

All python files should have a top-level docstring explaining the contents of the file and complex functions should
Expand Down
3 changes: 3 additions & 0 deletions frontend/scss/components/code.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pre{
white-space: pre-wrap;
}
1 change: 1 addition & 0 deletions frontend/scss/packet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ $csh-pink: #b0197e;
@import "components/buttons";
@import "components/signatures";
@import "components/badges";
@import "components/code";
6 changes: 5 additions & 1 deletion frontend/scss/partials/_global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,8 @@ tr {

.eval-user-img {
border-radius: 50%;
}
}

select.form-control:not([size]):not([multiple]) {
height: calc(3rem + 2px);
}
3 changes: 2 additions & 1 deletion gulpfile.js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ requireDir('./tasks', {recurse: true});

// Default task
gulp.task('default', gulp.parallel('css', 'js'));
gulp.task('production', gulp.parallel('css', 'js', 'generate-favicon', 'pylint'));
gulp.task('production', gulp.parallel('css', 'js', 'generate-favicon'));
gulp.task('lint', gulp.parallel('pylint'));
2 changes: 1 addition & 1 deletion gulpfile.js/tasks/pylint.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const gulp = require('gulp');
const exec = require('child_process').exec;

let pylintTask = (cb) => {
exec('pylint packet', function (err, stdout, stderr) {
exec('pylint --load-plugins pylint_quotes packet/routes packet', function (err, stdout, stderr) {
console.log(stdout);
console.log(stderr);
cb(err);
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"title": "CSH Packet",
"name": "csh-packet",
"version": "3.4.0",
"version": "3.5.0",
"description": "A web app implementation of the CSH introductory packet.",
"bugs": {
"url": "https://github.com/ComputerScienceHouse/packet/issues",
Expand All @@ -20,10 +20,10 @@
"devDependencies": {
"gulp": "^4.0.2",
"gulp-clean-css": "^4.2.0",
"gulp-minify": "^3.1.0",
"gulp-real-favicon": "^0.3.2",
"gulp-rename": "^1.4.0",
"gulp-sass": "^4.0.2",
"gulp-minify": "^3.1.0",
"require-dir": "^1.2.0"
}
}
1 change: 1 addition & 0 deletions packet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@

if app.config['REALM'] == 'csh':
from .routes import upperclassmen
from .routes import admin
else:
from .routes import freshmen

Expand Down
140 changes: 6 additions & 134 deletions packet/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,13 @@
import sys

from secrets import token_hex
from datetime import datetime, time, timedelta
from datetime import datetime, time
import csv
import click

from packet.mail import send_start_packet_mail
from packet.notifications import packet_starting_notification, packets_starting_notification
from . import app, db
from .models import Freshman, Packet, FreshSignature, UpperSignature, MiscSignature
from .ldap import ldap_get_eboard_role, ldap_get_active_rtps, ldap_get_3das, ldap_get_webmasters, \
ldap_get_drink_admins, ldap_get_constitutional_maintainers, ldap_is_intromember, ldap_get_active_members, \
ldap_is_on_coop
from .models import Packet, FreshSignature, UpperSignature, MiscSignature
from .utils import sync_freshman, create_new_packets, sync_with_ldap


@app.cli.command('create-secret')
Expand Down Expand Up @@ -66,40 +62,7 @@ def sync_freshmen(freshmen_csv):
freshmen_in_csv = parse_csv(freshmen_csv)

print('Syncing contents with the DB...')
freshmen_in_db = {freshman.rit_username: freshman for freshman in Freshman.query.all()}

for csv_freshman in freshmen_in_csv.values():
if csv_freshman.rit_username not in freshmen_in_db:
# This is a new freshman so add them to the DB
freshmen_in_db[csv_freshman.rit_username] = Freshman(rit_username=csv_freshman.rit_username,
name=csv_freshman.name, onfloor=csv_freshman.onfloor)
db.session.add(freshmen_in_db[csv_freshman.rit_username])
else:
# This freshman is already in the DB so just update them
freshmen_in_db[csv_freshman.rit_username].onfloor = csv_freshman.onfloor
freshmen_in_db[csv_freshman.rit_username].name = csv_freshman.name

# Update all freshmen entries that represent people who are no longer freshmen
for freshman in filter(lambda freshman: freshman.rit_username not in freshmen_in_csv, freshmen_in_db.values()):
freshman.onfloor = False

# Update the freshmen signatures of each open or future packet
for packet in Packet.query.filter(Packet.end > datetime.now()).all():
# Handle the freshmen that are no longer onfloor
for fresh_sig in filter(lambda fresh_sig: not fresh_sig.freshman.onfloor, packet.fresh_signatures):
FreshSignature.query.filter_by(packet_id=fresh_sig.packet_id,
freshman_username=fresh_sig.freshman_username).delete()

# Add any new onfloor freshmen
# pylint: disable=cell-var-from-loop
current_fresh_sigs = set(map(lambda fresh_sig: fresh_sig.freshman_username, packet.fresh_signatures))
for csv_freshman in filter(lambda csv_freshman: csv_freshman.rit_username not in current_fresh_sigs and
csv_freshman.onfloor and
csv_freshman.rit_username != packet.freshman_username,
freshmen_in_csv.values()):
db.session.add(FreshSignature(packet=packet, freshman=freshmen_in_db[csv_freshman.rit_username]))

db.session.commit()
sync_freshman(freshmen_in_csv)
print('Done!')


Expand All @@ -115,46 +78,8 @@ def create_packets(freshmen_csv):

# Collect the necessary data
base_date = input_date('Input the first day of packet season')
start = datetime.combine(base_date, packet_start_time)
end = datetime.combine(base_date, packet_end_time) + timedelta(days=14)

print('Fetching data from LDAP...')
all_upper = list(filter(
lambda member: not ldap_is_intromember(member) and not ldap_is_on_coop(member), ldap_get_active_members()))

rtp = ldap_get_active_rtps()
three_da = ldap_get_3das()
webmaster = ldap_get_webmasters()
c_m = ldap_get_constitutional_maintainers()
drink = ldap_get_drink_admins()

# Packet starting notifications
packets_starting_notification(start)

# Create the new packets and the signatures for each freshman in the given CSV
freshmen_in_csv = parse_csv(freshmen_csv)
print('Creating DB entries and sending emails...')
for freshman in Freshman.query.filter(Freshman.rit_username.in_(freshmen_in_csv)).all():
packet = Packet(freshman=freshman, start=start, end=end)
db.session.add(packet)
send_start_packet_mail(packet)
packet_starting_notification(packet)

for member in all_upper:
sig = UpperSignature(packet=packet, member=member.uid)
sig.eboard = ldap_get_eboard_role(member)
sig.active_rtp = member.uid in rtp
sig.three_da = member.uid in three_da
sig.webmaster = member.uid in webmaster
sig.c_m = member.uid in c_m
sig.drink_admin = member.uid in drink
db.session.add(sig)

for onfloor_freshman in Freshman.query.filter_by(onfloor=True).filter(Freshman.rit_username !=
freshman.rit_username).all():
db.session.add(FreshSignature(packet=packet, freshman=onfloor_freshman))

db.session.commit()
create_new_packets(base_date, freshmen_in_csv)
print('Done!')


Expand All @@ -163,60 +88,7 @@ def ldap_sync():
"""
Updates the upper and misc sigs in the DB to match ldap.
"""
print('Fetching data from LDAP...')
all_upper = {member.uid: member for member in filter(
lambda member: not ldap_is_intromember(member) and not ldap_is_on_coop(member), ldap_get_active_members())}

rtp = ldap_get_active_rtps()
three_da = ldap_get_3das()
webmaster = ldap_get_webmasters()
c_m = ldap_get_constitutional_maintainers()
drink = ldap_get_drink_admins()

print('Applying updates to the DB...')
for packet in Packet.query.filter(Packet.end > datetime.now()).all():
# Update the role state of all UpperSignatures
for sig in filter(lambda sig: sig.member in all_upper, packet.upper_signatures):
sig.eboard = ldap_get_eboard_role(all_upper[sig.member])
sig.active_rtp = sig.member in rtp
sig.three_da = sig.member in three_da
sig.webmaster = sig.member in webmaster
sig.c_m = sig.member in c_m
sig.drink_admin = sig.member in drink

# Migrate UpperSignatures that are from accounts that are not active anymore
for sig in filter(lambda sig: sig.member not in all_upper, packet.upper_signatures):
UpperSignature.query.filter_by(packet_id=packet.id, member=sig.member).delete()
if sig.signed:
sig = MiscSignature(packet=packet, member=sig.member)
db.session.add(sig)

# Migrate MiscSignatures that are from accounts that are now active members
for sig in filter(lambda sig: sig.member in all_upper, packet.misc_signatures):
MiscSignature.query.filter_by(packet_id=packet.id, member=sig.member).delete()
sig = UpperSignature(packet=packet, member=sig.member, signed=True)
sig.eboard = ldap_get_eboard_role(all_upper[sig.member])
sig.active_rtp = sig.member in rtp
sig.three_da = sig.member in three_da
sig.webmaster = sig.member in webmaster
sig.c_m = sig.member in c_m
sig.drink_admin = sig.member in drink
db.session.add(sig)

# Create UpperSignatures for any new active members
# pylint: disable=cell-var-from-loop
upper_sigs = set(map(lambda sig: sig.member, packet.upper_signatures))
for member in filter(lambda member: member not in upper_sigs, all_upper):
sig = UpperSignature(packet=packet, member=member)
sig.eboard = ldap_get_eboard_role(all_upper[sig.member])
sig.active_rtp = sig.member in rtp
sig.three_da = sig.member in three_da
sig.webmaster = sig.member in webmaster
sig.c_m = sig.member in c_m
sig.drink_admin = sig.member in drink
db.session.add(sig)

db.session.commit()
sync_with_ldap()
print('Done!')


Expand Down
4 changes: 2 additions & 2 deletions packet/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def get_roles(sig):


# pylint: disable=bare-except
@lru_cache(maxsize=128)
@lru_cache(maxsize=256)
def get_rit_name(username):
try:
freshman = Freshman.query.filter_by(rit_username=username).first()
Expand All @@ -53,7 +53,7 @@ def get_rit_name(username):


# pylint: disable=bare-except
@lru_cache(maxsize=128)
@lru_cache(maxsize=256)
def get_rit_image(username):
if username:
addresses = [username + '@rit.edu', username + '@g.rit.edu']
Expand Down
10 changes: 9 additions & 1 deletion packet/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,23 @@ def ldap_get_eboard_role(member):

return return_val

# Status checkers

# Status checkers
def ldap_is_eboard(member):
"""
:param member: A CSHMember instance
"""
return _ldap_is_member_of_group(member, 'eboard')


def ldap_is_evals(member):
return _ldap_is_member_of_group(member, 'eboard-evaluations')


def ldap_is_rtp(member):
return _ldap_is_member_of_group(member, 'rtp')


def ldap_is_intromember(member):
"""
:param member: A CSHMember instance
Expand Down
7 changes: 7 additions & 0 deletions packet/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ def by_username(cls, username: str):
"""
return cls.query.filter_by(rit_username=username).first()

@classmethod
def get_all(cls):
"""
Helper method to get all freshmen easily
"""
return cls.query.all()


class Packet(db.Model):
__tablename__ = 'packet'
Expand Down
43 changes: 43 additions & 0 deletions packet/routes/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from flask import render_template

from packet import app
from packet.models import Packet, Freshman
from packet.routes.shared import packet_sort_key
from packet.utils import before_request, packet_auth, admin_auth
from packet.log_utils import log_cache, log_time


@app.route('/admin/packets')
@log_cache
@packet_auth
@admin_auth
@before_request
@log_time
def admin_packets(info=None):
open_packets = Packet.open_packets()

# Pre-calculate and store the return values of did_sign(), signatures_received(), and signatures_required()
for packet in open_packets:
packet.did_sign_result = packet.did_sign(info['uid'], app.config['REALM'] == 'csh')
packet.signatures_received_result = packet.signatures_received()
packet.signatures_required_result = packet.signatures_required()

open_packets.sort(key=packet_sort_key, reverse=True)

return render_template('admin_packets.html',
open_packets=open_packets,
info=info)


@app.route('/admin/freshmen')
@log_cache
@packet_auth
@admin_auth
@before_request
@log_time
def admin_freshmen(info=None):
all_freshmen = Freshman.get_all()

return render_template('admin_freshmen.html',
all_freshmen=all_freshmen,
info=info)
Loading

0 comments on commit 35fb475

Please sign in to comment.