Skip to content

Commit

Permalink
Add CSRF token to check-in form.
Browse files Browse the repository at this point in the history
  • Loading branch information
vidya-ram committed Nov 17, 2015
1 parent b1311e7 commit d272421
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 25 deletions.
2 changes: 1 addition & 1 deletion funnel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def init_for(env):
lastuser.init_usermanager(UserManager(db, models.User, models.Team))
baseframe.init_app(app, requires=['funnel'], ext_requires=[
('codemirror-markdown', 'pygments'), 'toastr', 'baseframe-bs3', 'fontawesome>=4.0.0',
'ractive'])
'ractive'], enable_csrf=True)

This comment has been minimized.

Copy link
@jace

jace Nov 17, 2015

Member

If you enable global CSRF, you have to add the @csrf.exempt decorator to every view that does form validation, as the UI will break without it (in the case of form timeout).

app.assets.register('js_fullcalendar',
Bundle(assets.require('!jquery.js', 'jquery.fullcalendar.js', 'spectrum.js'),
output='js/fullcalendar.packed.js', filters='uglipyjs'))
Expand Down
28 changes: 16 additions & 12 deletions funnel/templates/event.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ <h3>{{event.title}}</h3>
</div>
<div class='col-lg-9 col-md-6 col-sm-8 col-xs-6'>
<h3 class='pull-right'>
Total: <span class="js-total">{{participants | length}}</span> |
Checked In: <span class="js-totalcheckin">{{checked_in_count}}</span>
Checked In: <span class="js-totalcheckin"></span> |
Total: <span class="js-total"></span>
</h3>
</div>
</div>
Expand Down Expand Up @@ -73,6 +73,9 @@ <h3 class='pull-right'>
</li>
<li>
<form action="{{ checkin_url }}" method='POST' class='checkin_form form-inline' id="{{ pid }}">
<div style="display:none;">
<input id="csrf_token" name="csrf_token" value="{{ getCsrfToken() }}" type="hidden">
</div>
<input type="hidden" name="pid" value="{{ pid }}">
{{#checked_in}}
<input type="hidden" name="checkin" value="f">
Expand All @@ -96,7 +99,6 @@ <h3 class='pull-right'>
</table>
{% endblock %}
{% block footerscripts %}
<script type="text/javascript" src="{{ url_for("static", filename="js/modernizr.min.js") }}"></script>
<script>
if (Modernizr.localstorage) {
//If there is no network, display a confirmation dialog when user closes/reloades the page
Expand All @@ -116,7 +118,10 @@ <h3 class='pull-right'>
el: '#participants-table-content',
template: '#participant-row',
data: {
participants: ''
participants: '',
getCsrfToken: function() {
return $('meta[name="csrf-token"]').attr('content');
}
}
});

Expand All @@ -136,7 +141,7 @@ <h3 class='pull-right'>
queue.dequeue(participantID);
}
else {
$('#' + participant).find('.js-loader').show();
$('#' + participantID).find('.js-loader').show();
}
}
else {
Expand All @@ -145,7 +150,7 @@ <h3 class='pull-right'>
queue.dequeue(participantID);
}
else {
$('#' + participant).find('.js-loader').show();
$('#' + participantID).find('.js-loader').show();
}
}
});
Expand Down Expand Up @@ -174,14 +179,14 @@ <h3 class='pull-right'>
}

var postCheckinStatus = function(participantIDs, action) {
var posturl = "{{ url_for('event_checkin', profile=space.profile.name, space=space.name, name=event.name) }}";
var formValues = $.param({"pid":participantIDs}, true)
var formValues = $.param({"pid":participantIDs}, true);
if(action) {
formValues += "&checkin=t";
}
formValues += "&csrf_token=" + $("meta[name='csrf-token']").attr('content');
$.ajax({
type: 'post',
url: posturl,
url: "{{ url_for('event_checkin', profile=space.profile.name, space=space.name, name=event.name) }}",
data : formValues,
timeout: 5000,
dataType: "json",
Expand Down Expand Up @@ -240,12 +245,11 @@ <h3 class='pull-right'>
});
if(formValues["checkin"] === "t") {
checkinQ.enqueue(formValues["pid"]);
$(this).find('.js-loader').show();
}
else {
cancelcheckinQ.enqueue(formValues["pid"]);
$(this).find('.js-loader').show();
}
$(this).find('.js-loader').show();
});

$('#participants-table-content').on('click', '.js-abort', function(event) {
Expand All @@ -255,7 +259,7 @@ <h3 class='pull-right'>

if(checkinStatus === "t") {
// Case 1: On abort, participantID is removed from "checkin-queue" if present.
// Case 2: On abort, if participantID is not present in the "checkin-queue" it implies check-in request has been sent to server, so check-in has to be cancelled hence add it to "cancelcheckin-queue".
// Case 2: On abort, if participantID is not present in the "checkin-queue" it implies check-in request has been sent to server, so check-in has to be cancelled, hence add it to "cancelcheckin-queue".
if(!checkinQ.dequeue(participantID)) {
cancelcheckinQ.enqueue(participantID);
}
Expand Down
3 changes: 1 addition & 2 deletions funnel/views/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,5 +173,4 @@ def event(profile, space, event):
update({'badge_printed': badge_printed}, False)
db.session.commit()
return redirect(url_for('event', profile=space.profile.name, space=space.name, name=event.name), code=303)
checked_in_count = len([p for p in participants if p.checked_in])
return render_template('event.html', profile=profile, space=space, participants=participants, event=event, badge_form=ParticipantBadgeForm(model=Participant), checked_in_count=checked_in_count, checkin_form=forms.Form())
return render_template('event.html', profile=profile, space=space, event=event, badge_form=ParticipantBadgeForm(model=Participant))
22 changes: 12 additions & 10 deletions funnel/views/participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,23 +159,25 @@ def event_participants_json(profile, space, event):
return jsonp(participants=[participant_checkin_data(participant, space, event) for participant in Participant.checkin_list(event)], total_participants=total_participants, total_checkedin=total_checkedin)


@app.route('/<space>/event/<name>/checkin/', methods=['POST'], subdomain='<profile>')
@app.route('/<space>/event/<name>/checkin', methods=['POST'], subdomain='<profile>')
@lastuser.requires_login
@load_models(
(Profile, {'name': 'profile'}, 'g.profile'),
((ProposalSpace, ProposalSpaceRedirect), {'name': 'space', 'profile': 'profile'}, 'space'),
(Event, {'name': 'name', 'proposal_space': 'space'}, 'event'),
permission='event-checkin')
def event_checkin(profile, space, event):
checked_in = True if request.form.get('checkin') == 't' else False
participant_ids = request.form.getlist('pid')
for participant_id in participant_ids:
participant = Participant.query.filter_by(id=participant_id).first()
attendee = Attendee.get(event, participant)
attendee.checked_in = checked_in
db.session.commit()
if request.is_xhr:
return jsonify(status=True, participant_ids=participant_ids, checked_in=checked_in)
form = forms.Form()
if form.validate_on_submit():
checked_in = True if request.form.get('checkin') == 't' else False
participant_ids = request.form.getlist('pid')
for participant_id in participant_ids:
participant = Participant.query.filter_by(id=participant_id).first()
attendee = Attendee.get(event, participant)
attendee.checked_in = checked_in
db.session.commit()
if request.is_xhr:
return jsonify(status=True, participant_ids=participant_ids, checked_in=checked_in)
return redirect(url_for('event', profile=space.profile.name, space=space.name, name=event.name), code=303)


Expand Down

0 comments on commit d272421

Please sign in to comment.