Skip to content

Commit 297c766

Browse files
committed
Implement Become Active and Export All Active functionality
1 parent 8e62520 commit 297c766

File tree

9 files changed

+175
-15
lines changed

9 files changed

+175
-15
lines changed

conditional/blueprints/member_management.py

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import csv
22
import io
3+
import re
34

45
from datetime import datetime
56

67
import structlog
78

8-
from flask import Blueprint, request, jsonify, abort
9+
from flask import Blueprint, request, jsonify, abort, make_response
910

1011
from conditional.models.models import FreshmanAccount
1112
from conditional.models.models import FreshmanEvalData
@@ -88,9 +89,11 @@ def display_member_management():
8889
if settings:
8990
lockdown = settings.site_lockdown
9091
intro_form = settings.intro_form_active
92+
accept_dues_until = settings.accept_dues_until
9193
else:
9294
lockdown = False
9395
intro_form = False
96+
accept_dues_until = datetime.now()
9497

9598
return render_template(request, "member_management.html",
9699
username=username,
@@ -102,6 +105,7 @@ def display_member_management():
102105
freshmen=freshmen_list,
103106
co_op=co_op_list,
104107
site_lockdown=lockdown,
108+
accept_dues_until=accept_dues_until,
105109
intro_form=intro_form)
106110

107111

@@ -136,6 +140,31 @@ def member_management_eval():
136140
return jsonify({"success": True}), 200
137141

138142

143+
@member_management_bp.route('/manage/accept_dues_until', methods=['PUT'])
144+
def member_management_financial():
145+
log = logger.new(request=request)
146+
147+
username = request.headers.get('x-webauth-user')
148+
account = ldap_get_member(username)
149+
150+
if not ldap_is_financial_director(account):
151+
return "must be financial director", 403
152+
153+
post_data = request.get_json()
154+
155+
if 'acceptDuesUntil' in post_data:
156+
date = datetime.strptime(post_data['acceptDuesUntil'], "%Y-%m-%d")
157+
log.info('Changed Dues Accepted Until: {}'.format(date))
158+
EvalSettings.query.update(
159+
{
160+
'accept_dues_until': date
161+
})
162+
163+
db.session.flush()
164+
db.session.commit()
165+
return jsonify({"success": True}), 200
166+
167+
139168
@member_management_bp.route('/manage/user', methods=['POST'])
140169
def member_management_adduser():
141170
log = logger.new(request=request)
@@ -496,13 +525,11 @@ def member_management_upgrade_user():
496525
def member_management_make_user_active():
497526
log = logger.new(request=request)
498527

499-
post_data = request.get_json()
500-
501-
uid = post_data['uid']
528+
uid = request.headers.get('x-webauth-user')
502529
account = ldap_get_member(uid)
503530

504531
if not ldap_is_current_student(account) or ldap_is_active(account):
505-
return jsonify({"success": False}), 403
532+
return "must be current student and not active", 403
506533

507534
ldap_set_active(account)
508535
log.info("Make user {} active".format(uid))
@@ -603,6 +630,31 @@ def clear_active_members():
603630
return jsonify({"success": True}), 200
604631

605632

633+
@member_management_bp.route('/manage/export_active_list', methods=['GET'])
634+
def export_active_list():
635+
sio = io.StringIO()
636+
csvw = csv.writer(sio)
637+
638+
active_list = [["Full Name", "RIT Username", "Amount to Charge"]]
639+
for member in ldap_get_active_members():
640+
full_name = member.cn
641+
rit_username = re.search(".*uid=(\\w*)", member.ritDn).group(1)
642+
will_coop = CurrentCoops.query.filter(
643+
CurrentCoops.date_created > start_of_year(),
644+
CurrentCoops.uid == member.uid).first()
645+
if will_coop:
646+
dues = 80
647+
else:
648+
dues = 160
649+
active_list.append([full_name, rit_username, dues])
650+
651+
csvw.writerows(active_list)
652+
output = make_response(sio.getvalue())
653+
output.headers["Content-Disposition"] = "attachment; filename=csh_active_list.csv"
654+
output.headers["Content-type"] = "text/csv"
655+
return output
656+
657+
606658
@member_management_bp.route('/manage/current/<uid>', methods=['POST', 'DELETE'])
607659
def remove_current_student(uid):
608660
log = logger.new(request=request)

conditional/models/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,11 +243,13 @@ class EvalSettings(db.Model):
243243
housing_form_active = Column(Boolean)
244244
intro_form_active = Column(Boolean)
245245
site_lockdown = Column(Boolean)
246+
accept_dues_until = Column(Date)
246247

247248
def __init__(self):
248249
self.housing_form_active = True
249250
self.intro_form_active = True
250251
self.site_lockdown = False
252+
self.accept_dues_until = datetime.now()
251253

252254

253255
class SpringEval(db.Model):

conditional/templates/dashboard.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ <h3 class="panel-title">Major Projects</h3>
251251
</div>
252252
{% endif %}
253253

254-
{% if student and not active %}
254+
{% if accepting_dues and student and not active %}
255255
<div class="panel panel-info" id="becomeActive">
256256
<div class="panel-heading">
257257
<h3 class="panel-title">Become Active</h3>
@@ -260,7 +260,7 @@ <h3 class="panel-title">Become Active</h3>
260260
Hey there, you're eligible to become an active member! Click the button below if you'd like to become active and pay dues.
261261
</div>
262262
<div class="panel-footer text-right">
263-
<a href="#" data-module="becomeActive" data-uid="{{username}}" class="btn btn-sm btn-default">Become Active</a>
263+
<a href="#" data-module="becomeActive" class="btn btn-sm btn-default">Become Active</a>
264264
</div>
265265
</div>
266266
{% endif %}

conditional/templates/member_management.html

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ <h3 class="panel-title">Administration</h3>
1010
</div>
1111
<div class="panel-body">
1212
<div class="container-fluid">
13-
<div class="col-xs-6 col-sm-2{% if not is_eval_director %} col-sm-offset-2{% endif %}">
13+
<div class="col-xs-6 col-sm-2">
1414
<div class="stat-number">{{num_current}}</div>
1515
<div class="stat-title">Current Students</div>
1616
</div>
@@ -37,6 +37,11 @@ <h3 class="panel-title">Administration</h3>
3737
<div class="col-xs-6 col-sm-2 align-center">
3838
<a href="/manage/new" class="btn btn-danger btn-sm btn-new-year"><span class="glyphicon glyphicon-repeat"></span> New Year</a>
3939
</div>
40+
{% else %}
41+
<div class="col-xs-6 col-sm-2 align-center">
42+
<label for="acceptDuesUntil" class="control-label accept-dues-until">Accept Dues Until</label>
43+
<input type="text" name="acceptDuesUntil" class="form-control" value="{{ accept_dues_until }}" data-module="acceptDuesDatepicker" data-setting="acceptDuesUntil" />
44+
</div>
4045
{% endif %}
4146
</div>
4247
</div>
@@ -166,7 +171,14 @@ <h3 class="panel-title">Freshmen Management</h3>
166171

167172
<div class="panel panel-default">
168173
<div class="panel-heading">
169-
<h3 class="panel-title">Member Management</h3>
174+
<h3 class="panel-title">
175+
Member Management
176+
<a href="/manage/export_active_list">
177+
<button type="button" class="btn btn-primary btn-sm btn-conditional pull-right">
178+
<span class="glyphicon glyphicon-save"></span> Export Active List
179+
</button>
180+
</a>
181+
</h3>
170182
</div>
171183
<div class="panel-body table-fill">
172184
<div class="table-responsive">

conditional/util/flask.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from datetime import date
2+
13
from flask import render_template as flask_render_template
24
from conditional.models.models import EvalSettings
35

@@ -27,6 +29,7 @@ def render_template(request, template_name, **kwargs):
2729
db.session.commit()
2830
account = ldap_get_member(user_name)
2931
lockdown = EvalSettings.query.first().site_lockdown
32+
accepting_dues = EvalSettings.query.first().accept_dues_until > date.today()
3033
is_active = ldap_is_active(account)
3134
is_alumni = ldap_is_alumni(account)
3235
is_eboard = ldap_is_eboard(account)
@@ -46,6 +49,7 @@ def render_template(request, template_name, **kwargs):
4649
return flask_render_template(
4750
template_name,
4851
lockdown=lockdown,
52+
accepting_dues=accepting_dues,
4953
is_active=is_active,
5054
is_alumni=is_alumni,
5155
is_eboard=is_eboard,
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/* global $ */
2+
import "bootstrap-material-datetimepicker";
3+
import "whatwg-fetch";
4+
import FetchUtil from "../utils/fetchUtil";
5+
import Exception from "../exceptions/exception";
6+
import FetchException from "../exceptions/fetchException";
7+
import sweetAlert from "../../../node_modules/bootstrap-sweetalert/dev/sweetalert.es6.js"; // eslint-disable-line max-len
8+
9+
export default class DatePicker {
10+
constructor(input) {
11+
this.input = input;
12+
this.endpoint = '/manage/accept_dues_until';
13+
this.setting = input.dataset.setting;
14+
this.render();
15+
}
16+
17+
render() {
18+
$(this.input).bootstrapMaterialDatePicker({
19+
weekStart: 0,
20+
time: false
21+
});
22+
23+
document.getElementsByClassName('dtp-btn-ok')[0].addEventListener('click',
24+
() => {
25+
this._updateSetting();
26+
});
27+
}
28+
29+
_updateSetting() {
30+
console.log("Update dues until: " + this.input.value);
31+
let payload = {};
32+
payload[this.setting] = this.input.value;
33+
34+
fetch(this.endpoint, {
35+
method: 'PUT',
36+
headers: {
37+
'Accept': 'application/json',
38+
'Content-Type': 'application/json'
39+
},
40+
credentials: 'same-origin',
41+
body: JSON.stringify(payload)
42+
})
43+
.then(FetchUtil.checkStatus)
44+
.then(FetchUtil.parseJSON)
45+
.then(response => {
46+
if (!response.hasOwnProperty('success') || !response.success) {
47+
sweetAlert("Uh oh...", "We're having trouble submitting this " +
48+
"form right now. Please try again later.", "error");
49+
throw new Exception(FetchException.REQUEST_FAILED, response);
50+
}
51+
})
52+
.catch(error => {
53+
sweetAlert("Uh oh...", "We're having trouble submitting this " +
54+
"form right now. Please try again later.", "error");
55+
throw new Exception(FetchException.REQUEST_FAILED, error);
56+
});
57+
}
58+
}

frontend/javascript/modules/becomeActive.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import FetchUtil from "../utils/fetchUtil";
33
export default class becomeActive {
44
constructor(link) {
55
this.link = link;
6-
this.uid = this.link.dataset.uid;
76
this.endpoint = '/manage/make_user_active';
87
this.render();
98
}
@@ -15,11 +14,7 @@ export default class becomeActive {
1514
_delete(e) {
1615
e.preventDefault();
1716

18-
let payload = {
19-
uid: this.uid
20-
};
21-
22-
FetchUtil.postWithWarning(this.endpoint, payload, {
17+
FetchUtil.postWithWarning(this.endpoint, {}, {
2318
warningText: "Becoming an active member means that you will be charged" +
2419
" dues, which are $80 per semester.",
2520
successText: "You are now an active member."

frontend/stylesheets/pages/_management.scss

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@
1212
margin: 30px 0;
1313
}
1414

15+
.btn-get-active {
16+
float: right;
17+
margin-top: -4px;
18+
box-shadow: none;
19+
padding: 3px 7px;
20+
}
21+
22+
.accept-dues-until {
23+
margin-top: 10px;
24+
}
25+
1526
.upload-title {
1627
padding-top: 20px;
1728
height: 55px;

migrations/versions/d1a06ab54211_.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Add Accept Dues Until site setting
2+
3+
Revision ID: d1a06ab54211
4+
Revises: 117567def844
5+
Create Date: 2017-07-21 17:09:37.540766
6+
7+
"""
8+
9+
# revision identifiers, used by Alembic.
10+
revision = 'd1a06ab54211'
11+
down_revision = '117567def844'
12+
13+
from alembic import op
14+
import sqlalchemy as sa
15+
from datetime import datetime
16+
17+
def upgrade():
18+
# ### commands auto generated by Alembic - please adjust! ###
19+
op.add_column('settings', sa.Column('accept_dues_until', sa.Date(), server_default=datetime.now().strftime("%Y-%m-%d"), nullable=True))
20+
# ### end Alembic commands ###
21+
22+
23+
def downgrade():
24+
# ### commands auto generated by Alembic - please adjust! ###
25+
op.drop_column('settings', 'accept_dues_until')
26+
# ### end Alembic commands ###

0 commit comments

Comments
 (0)