Skip to content

Commit 586a56d

Browse files
Merge pull request #134 from ComputerScienceHouse/develop
Conditional v1.4.0
2 parents 6abd03b + 5c8af5a commit 586a56d

26 files changed

+262
-65
lines changed

conditional/__init__.py

+48-7
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
import os
22
import subprocess
3-
from flask import Flask
4-
from flask import redirect
3+
from flask import Flask, redirect, request, render_template, g
54
from flask_sqlalchemy import SQLAlchemy
65
from flask_migrate import Migrate
76
from csh_ldap import CSHLDAP
7+
from raven import fetch_git_sha
8+
from raven.contrib.flask import Sentry
9+
from raven.exceptions import InvalidGitRepository
810
import structlog
911

1012
app = Flask(__name__)
1113

12-
config = os.path.join(os.getcwd(), "config.py")
14+
config = os.path.join(app.config.get('ROOT_DIR', os.getcwd()), "config.py")
1315

1416
app.config.from_pyfile(config)
1517
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
1618

17-
app.config["GIT_REVISION"] = subprocess.check_output(['git',
18-
'rev-parse',
19-
'--short',
20-
'HEAD']).decode('utf-8').rstrip()
19+
try:
20+
app.config["GIT_REVISION"] = fetch_git_sha(app.config["ROOT_DIR"])[:7]
21+
except (InvalidGitRepository, KeyError):
22+
app.config["GIT_REVISION"] = "unknown"
23+
2124
db = SQLAlchemy(app)
2225
migrate = Migrate(app, db)
2326
logger = structlog.get_logger()
27+
sentry = Sentry(app)
2428

2529
ldap = CSHLDAP(app.config['LDAP_BIND_DN'],
2630
app.config['LDAP_BIND_PW'],
@@ -52,6 +56,7 @@
5256
app.register_blueprint(slideshow_bp)
5357
app.register_blueprint(cache_bp)
5458

59+
from conditional.util.ldap import ldap_get_member
5560

5661
@app.route('/<path:path>')
5762
def static_proxy(path):
@@ -63,6 +68,42 @@ def static_proxy(path):
6368
def default_route():
6469
return redirect('/dashboard')
6570

71+
@app.errorhandler(404)
72+
@app.errorhandler(500)
73+
def route_errors(error):
74+
data = dict()
75+
username = request.headers.get('x-webauth-user')
76+
77+
# Handle the case where the header isn't present
78+
if username is not None:
79+
member = ldap_get_member(username)
80+
data['username'] = member.uid
81+
data['name'] = member.cn
82+
else:
83+
data['username'] = "unknown"
84+
data['name'] = "Unknown"
85+
86+
# Figure out what kind of error was passed
87+
if isinstance(error, int):
88+
code = error
89+
elif hasattr(error, 'code'):
90+
code = error.code
91+
else:
92+
# Unhandled exception
93+
code = 500
94+
95+
# Is this a 404?
96+
if code == 404:
97+
error_desc = "Page Not Found"
98+
else:
99+
error_desc = type(error).__name__
100+
101+
return render_template('errors.html',
102+
error=error_desc,
103+
error_code=code,
104+
event_id=g.sentry_event_id,
105+
public_dsn=sentry.client.get_public_dsn('https'),
106+
**data), int(code)
66107

67108
@app.cli.command()
68109
def zoo():

conditional/blueprints/attendance.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def get_non_alumni_non_coop(internal=False):
8080
for account in active_members:
8181
if account.uid in coop_members:
8282
# Members who are on co-op don't need to go to house meeting.
83-
pass
83+
continue
8484

8585
eligible_members.append(
8686
{
@@ -91,8 +91,8 @@ def get_non_alumni_non_coop(internal=False):
9191

9292
if internal:
9393
return eligible_members
94-
else:
95-
return jsonify({'members': eligible_members}), 200
94+
95+
return jsonify({'members': eligible_members}), 200
9696

9797

9898
@attendance_bp.route('/attendance/cm_members')
@@ -314,15 +314,15 @@ def alter_house_attendance(uid, hid):
314314
member_meeting.attendance_status = "Attended"
315315
db.session.commit()
316316
return jsonify({"success": True}), 200
317-
else:
318-
freshman_meeting = FreshmanHouseMeetingAttendance.query.filter(
319-
FreshmanHouseMeetingAttendance.fid == uid,
320-
FreshmanHouseMeetingAttendance.meeting_id == hid
321-
).first()
322317

323-
freshman_meeting.attendance_status = "Attended"
324-
db.session.commit()
325-
return jsonify({"success": True}), 200
318+
freshman_meeting = FreshmanHouseMeetingAttendance.query.filter(
319+
FreshmanHouseMeetingAttendance.fid == uid,
320+
FreshmanHouseMeetingAttendance.meeting_id == hid
321+
).first()
322+
323+
freshman_meeting.attendance_status = "Attended"
324+
db.session.commit()
325+
return jsonify({"success": True}), 200
326326

327327

328328
@attendance_bp.route('/attendance/alter/hm/<uid>/<hid>', methods=['POST'])

conditional/blueprints/conditional.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -117,5 +117,5 @@ def conditional_delete(cid):
117117
db.session.flush()
118118
db.session.commit()
119119
return jsonify({"success": True}), 200
120-
else:
121-
return "Must be evals director to delete!", 401
120+
121+
return "Must be evals director to delete!", 401

conditional/blueprints/intro_evals.py

+15-10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from conditional.models.models import FreshmanCommitteeAttendance
1111
from conditional.models.models import MemberCommitteeAttendance
12+
from conditional.models.models import CommitteeMeeting
1213
from conditional.models.models import FreshmanAccount
1314
from conditional.models.models import FreshmanEvalData
1415
from conditional.models.models import FreshmanHouseMeetingAttendance
@@ -33,11 +34,13 @@ def display_intro_evals(internal=False):
3334
# get user data
3435
def get_uid_cm_count(member_id):
3536
return len([a for a in MemberCommitteeAttendance.query.filter(
36-
MemberCommitteeAttendance.uid == member_id)])
37+
MemberCommitteeAttendance.uid == member_id)
38+
if CommitteeMeeting.query.filter(CommitteeMeeting.id == a.meeting_id).approved])
3739

3840
def get_fid_cm_count(member_id):
3941
return len([a for a in FreshmanCommitteeAttendance.query.filter(
40-
FreshmanCommitteeAttendance.fid == member_id)])
42+
FreshmanCommitteeAttendance.fid == member_id)
43+
if CommitteeMeeting.query.filter(CommitteeMeeting.id == a.meeting_id).approved])
4144

4245
user_name = None
4346
if not internal:
@@ -88,7 +91,8 @@ def get_fid_cm_count(member_id):
8891
[s.name for s in TechnicalSeminar.query.filter(
8992
TechnicalSeminar.id.in_(
9093
[a.seminar_id for a in FreshmanSeminarAttendance.query.filter(
91-
FreshmanSeminarAttendance.fid == fid.id)]
94+
FreshmanSeminarAttendance.fid == fid.id)
95+
if TechnicalSeminar.query.filter(TechnicalSeminar.id == a.seminar_id).approved]
9296
))
9397
],
9498
'social_events': '',
@@ -141,7 +145,8 @@ def get_fid_cm_count(member_id):
141145
[s.name for s in TechnicalSeminar.query.filter(
142146
TechnicalSeminar.id.in_(
143147
[a.seminar_id for a in MemberSeminarAttendance.query.filter(
144-
MemberSeminarAttendance.uid == uid)]
148+
MemberSeminarAttendance.uid == uid)
149+
if TechnicalSeminar.query.filter(TechnicalSeminar.id == a.seminar_id).approved]
145150
))
146151
],
147152
'social_events': freshman_data.social_events,
@@ -160,9 +165,9 @@ def get_fid_cm_count(member_id):
160165

161166
if internal:
162167
return ie_members
163-
else:
164-
# return names in 'first last (username)' format
165-
return render_template(request,
166-
'intro_evals.html',
167-
username=user_name,
168-
members=ie_members)
168+
169+
# return names in 'first last (username)' format
170+
return render_template(request,
171+
'intro_evals.html',
172+
username=user_name,
173+
members=ie_members)

conditional/blueprints/intro_evals_form.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from conditional.models.models import FreshmanEvalData
77
from conditional.models.models import EvalSettings
88
from conditional.util.ldap import ldap_is_intromember
9+
from conditional.util.ldap import ldap_get_member
910
from conditional.util.flask import render_template
1011

1112
from conditional import db
@@ -23,8 +24,8 @@ def display_intro_evals_form():
2324

2425
# get user data
2526
user_name = request.headers.get('x-webauth-user')
26-
27-
if not ldap_is_intromember(user_name):
27+
account = ldap_get_member(user_name)
28+
if not ldap_is_intromember(account):
2829
return redirect("/dashboard")
2930
eval_data = FreshmanEvalData.query.filter(
3031
FreshmanEvalData.uid == user_name).first()

conditional/blueprints/major_project_submission.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -121,5 +121,5 @@ def major_project_delete(pid):
121121
db.session.flush()
122122
db.session.commit()
123123
return jsonify({"success": True}), 200
124-
else:
125-
return "Must be project owner to delete!", 401
124+
125+
return "Must be project owner to delete!", 401

conditional/blueprints/member_management.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -373,13 +373,13 @@ def get_hm_date(hm_id):
373373
'missed_hm': hms_missed,
374374
'user': 'eval'
375375
}), 200
376-
else:
377-
return jsonify(
378-
{
379-
'name': account.cn,
380-
'active_member': ldap_is_active(account),
381-
'user': 'financial'
382-
}), 200
376+
377+
return jsonify(
378+
{
379+
'name': account.cn,
380+
'active_member': ldap_is_active(account),
381+
'user': 'financial'
382+
}), 200
383383

384384

385385
@member_management_bp.route('/manage/user/<fid>', methods=['DELETE'])

conditional/blueprints/spring_evals.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from conditional.util.ldap import ldap_get_active_members
77

88
from conditional.models.models import MemberCommitteeAttendance
9+
from conditional.models.models import CommitteeMeeting
910
from conditional.models.models import MemberHouseMeetingAttendance
1011
from conditional.models.models import MajorProject
1112
from conditional.models.models import HouseMeeting
@@ -28,7 +29,8 @@ def display_spring_evals(internal=False):
2829

2930
def get_cm_count(member_id):
3031
return len([a for a in MemberCommitteeAttendance.query.filter(
31-
MemberCommitteeAttendance.uid == member_id)])
32+
MemberCommitteeAttendance.uid == member_id)
33+
if CommitteeMeeting.query.filter(CommitteeMeeting.id == a.meeting_id).approved])
3234

3335
user_name = None
3436
if not internal:
@@ -87,6 +89,14 @@ def get_cm_count(member_id):
8789
MajorProject.uid == uid)]
8890
}
8991
member['major_projects_len'] = len(member['major_projects'])
92+
member['major_project_passed'] = [
93+
{
94+
'name': p.name,
95+
'status': p.status,
96+
'description': p.description
97+
} for p in MajorProject.query.filter(MajorProject.uid == uid)
98+
if p.status == "Passed"]
99+
member['major_projects_passed_len'] = len(member['major_projects_passed'])
90100
member['major_project_passed'] = False
91101
for mp in member['major_projects']:
92102
if mp['status'] == "Passed":
@@ -103,8 +113,8 @@ def get_cm_count(member_id):
103113
# return names in 'first last (username)' format
104114
if internal:
105115
return sp_members
106-
else:
107-
return render_template(request,
108-
'spring_evals.html',
109-
username=user_name,
110-
members=sp_members)
116+
117+
return render_template(request,
118+
'spring_evals.html',
119+
username=user_name,
120+
members=sp_members)

conditional/templates/base.html

+8-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,14 @@
2323
{% block body %}
2424
{% endblock %}
2525
{% else %}
26-
<div class="container main">
27-
<div class="alert alert-danger" role="alert"><span class="glyphicon glyphicon-remove-sign"></span> Site Lockdown: Evaluations in progress. Please check back later.</div>
26+
<div class="container main error-page align-center">
27+
<div class="col-xs-12">
28+
<img src="/static/images/material_lock.svg" alt="Attention!">
29+
<h1>Congratulations or I'm Sorry...</h1>
30+
<h2>We cannot reveal the results of your evaluation!</h2>
31+
<h3>Evaluations underway:</h3>
32+
<p>Conditional is in Lockdown</p>
33+
</div>
2834
</div>
2935
{% endif %}
3036

conditional/templates/errors.html

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{% extends "nav.html" %}
2+
{% block title %}Error {{ error_code }}{% endblock %}
3+
{% block body %}
4+
<div class="container main error-page align-center">
5+
<div class="col-xs-12">
6+
<img src="/static/images/material_attention.svg" alt="Attention!">
7+
<h1>Congratulations or I'm Sorry...</h1>
8+
<h2>Something has gone terribly wrong!</h2>
9+
<h3>{{ error }}</h3>
10+
{% if event_id %}
11+
<p>The error identifier is: {{ event_id }}</p>
12+
{% endif %}
13+
</div>
14+
{% if event_id %}
15+
<button type="button" class="btn btn-primary" data-module="errorReport" data-event="{{ event_id }}">Report this Error</button>
16+
{% endif %}
17+
</div>
18+
19+
{% endblock %}

conditional/templates/intro_evals.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ <h6 class="eval-uid">{{ m['uid'] }}</h6>
4545
<div class="text-center">
4646
{% if m['signatures_missed'] == 0 %}
4747
<div class="eval-info-label">
48-
<span class="glyphicon glyphicon-ok-sign green eval-info-status"></span>Sigantures Missed
48+
<span class="glyphicon glyphicon-ok-sign green eval-info-status"></span>Signatures Missed
4949
<span class="eval-info-number">{{ m['signatures_missed'] }}</span>
5050
</div>
5151
{% elif m['signatures_missed'] > 0 %}
5252
<div class="eval-info-label">
53-
<span class="glyphicon glyphicon-remove-sign red eval-info-status"></span>Sigantures Missed
53+
<span class="glyphicon glyphicon-remove-sign red eval-info-status"></span>Signatures Missed
5454
<span class="eval-info-number">{{ m['signatures_missed'] }}</span>
5555
</div>
5656
{% else %}

conditional/templates/major_project_submission.html

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@ <h3 class="page-title">Major Project Form</h3>
1111
<div class="panel-body">
1212
<div class="form-group label-floating is-empty">
1313
<label class="control-label" for="name">Project Name</label>
14-
<input class="form-control" id="name" name="name" type="text" maxlength="64">
14+
<input class="form-control" id="name" name="name" type="text" maxlength="64"
15+
placeholder="A clever name for your project, sometimes people will come up with an acronym.">
1516
</div>
1617
</div>
1718
</div>
1819
<div class="panel panel-default">
1920
<div class="panel-body" style="padding-top:20px;">
2021
<div class="form-group label-floating is-empty">
2122
<label class="control-label" for="description">Description</label>
22-
<textarea name="description" class="form-control" rows="3" id="description"></textarea>
23+
<textarea name="description" class="form-control" rows="3" id="description"
24+
placeholder="A 'two liner' description of what your project is. If you have source materials like a GitHub repo publicly available, it's also useful to include links to them."></textarea>
2325
</div>
2426
</div>
2527
</div>
@@ -79,7 +81,7 @@ <h5 style="padding:15px 20px;float:right"><span class="glyphicon glyphicon-hourg
7981
{% endif %}
8082
</div>
8183
<button class="btn-expand-panel" role="button" data-toggle="collapse" href="#evalsCollapse-{{p['id']}}" aria-expanded="false" aria-controls="evalsCollapse-{{p['id']}}"><span class="glyphicon glyphicon glyphicon-menu-down"></span></button>
82-
<div class="collapse" id="evalsCollapse-{{p['id']}}">
84+
<div class="collapse major-project-desc" id="evalsCollapse-{{p['id']}}">
8385
{{p['description']}}
8486
</div>
8587
</div>

0 commit comments

Comments
 (0)