Skip to content
This repository has been archived by the owner on Oct 4, 2022. It is now read-only.

Commit

Permalink
Refactoring subjectpool
Browse files Browse the repository at this point in the history
  • Loading branch information
tgpatel committed Apr 2, 2015
1 parent 3d3753d commit 9d65681
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 79 deletions.
6 changes: 3 additions & 3 deletions vcweb/core/subjectpool/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ def save(self, commit=True):
if self.request_type == 'delete':
logger.warn("Deleting experiment session %s", es)
es.delete()
elif commit:
else:
es.creator = self.user
es.date_created = datetime.now()
es.save()
if commit:
es.save()
return es

class Meta:
Expand Down
30 changes: 30 additions & 0 deletions vcweb/core/subjectpool/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from django.contrib.sites.models import Site, RequestSite
from django.template import Context
from django.template.loader import get_template
from vcweb.core.models import ExperimentSession

class InvitationEmail(object):

def __init__(self, request):
self.request = request
self.plaintext_template = get_template('email/invitation-email.txt')

@property
def site_url(self):
if Site._meta.installed:
site = Site.objects.get_current()
else:
site = RequestSite(self.request)

if self.request.is_secure():
return "https://" + site.domain
else:
return "http://" + site.domain

def get_plaintext_content(self, message, session_ids):
context = Context({
'SITE_URL': self.site_url,
'invitation_text': message,
'session_list': ExperimentSession.objects.filter(pk__in=session_ids),
})
return self.plaintext_template.render(context)
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@
{% endblock %}
{% block page %}
<div id='page'>
<a class="btn btn-default" href="{% url 'subjectpool:experimenter_index' %}"><i class="fa fa-arrow-left"></i> Back</a>
<a class="btn btn-default" href="{% url 'subjectpool:subjectpool_index' %}"><i class="fa fa-arrow-left"></i> Back</a>
<div id="session-detail" class="callout callout-info">
<p><strong>Experiment: </strong>
{{ session_detail.experiment_metadata.title }}
<p><strong>Date/Time: </strong> {{ session_detail.scheduled_date.date }}, {{ session_detail.scheduled_date.time }} -
{% if session_detail.scheduled_end_date.date != session_detail.scheduled_date.date %}
{{ session_detail.scheduled_end_date.date }},
{{ session.experiment_metadata.title }}
<p><strong>Date/Time: </strong> {{ session.scheduled_date.date }}, {{ session.scheduled_date.time }} -
{% if session.scheduled_end_date.date != session.scheduled_date.date %}
{{ session.scheduled_end_date.date }},
{% endif %}
{{ session_detail.scheduled_end_date.time }}</p>
<p><strong>Location: </strong> {{ session_detail.location }}</p>
<p><strong>Capacity: </strong> {{ session_detail.capacity }}</p>
<p><strong>Waitlist enabled: </strong> {{ session_detail.waitlist }}</p>
{{ session.scheduled_end_date.time }}</p>
<p><strong>Location: </strong> {{ session.location }}</p>
<p><strong>Capacity: </strong> {{ session.capacity }}</p>
<p><strong>Waitlist enabled: </strong> {{ session.waitlist }}</p>
</div>
<div class="alert alert-warning">
{% if formset.forms|length > 0 %}
<a target="_blank" href="/subject-pool/session/{{ session_detail.pk }}/download/">Download Registered Participants</a>
<a target="_blank" href="/subject-pool/session/{{ session.pk }}/download/">Download Registered Participants</a>
{% endif %}
<form class="form-inline">
<div class="form-group">
Expand Down Expand Up @@ -112,7 +112,7 @@ <h3>Registered Participants</h3>
});

$("#addParticipant").submit(function(event) {
$.post("{% url 'subjectpool:add_participant' session_detail.pk %}", $(event.target).serialize(), function(data) {
$.post("{% url 'subjectpool:add_participant' session.pk %}", $(event.target).serialize(), function(data) {
console.log(data.success);
if(data.success) {
// reload page to show the added participant
Expand Down Expand Up @@ -142,7 +142,8 @@ <h3>Registered Participants</h3>
search_input.addClass('form-control input-sm');
search_input.css('width', '150px');


// hack to make sure that the table has all the rows before making post
// required to make django formset to work
$("#submit-attendance").click(function() {
oTable.fnFilter('');
});
Expand Down
9 changes: 5 additions & 4 deletions vcweb/core/subjectpool/urls.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
from django.conf.urls import url

from vcweb.core.subjectpool.views import (experimenter_index, manage_experiment_session, get_session_events,
from vcweb.core.subjectpool.views import (subjectpool_index, manage_experiment_session, get_session_events,
manage_participant_attendance, send_invitations, get_invitations_count,
invite_email_preview, experiment_session_signup,
submit_experiment_session_signup, cancel_experiment_session_signup,
download_experiment_session, add_participant)

urlpatterns = [
url(r'^$', experimenter_index, name='experimenter_index'),
url(r'^$', subjectpool_index, name='subjectpool_index'),
url(r'^session/manage/(?P<pk>\-?\d+)$', manage_experiment_session, name='manage_experiment_session'),
url(r'^session/events$', get_session_events, name='session_events'),
url(r'^session/detail/event/(?P<pk>\d+)$', manage_participant_attendance, name='session_event_detail'),
url(r'^session/(?P<pk>\d+)/participant/add/$', add_participant, name='add_participant'),
url(r'^session/invite$', send_invitations, name='send_invites'),
url(r'^session/invite/count$', get_invitations_count, name='get_invitations_count'),
url(r'^session/email-preview$', invite_email_preview, name='invite_email_preview'),
url(r'^session/(?P<pk>\d+)/download/$', download_experiment_session, name='download_experiment_session'),
url(r'^session/events$', get_session_events, name='session_events'),

url(r'^signup/$', experiment_session_signup, name='experiment_session_signup'),
url(r'^signup/submit/$', submit_experiment_session_signup, name='submit_experiment_session_signup'),
url(r'^signup/cancel/$', cancel_experiment_session_signup, name='cancel_experiment_session_signup'),
url(r'^session/(?P<pk>\d+)/download/$', download_experiment_session, name='download_experiment_session'),
]
98 changes: 40 additions & 58 deletions vcweb/core/subjectpool/views.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,52 @@
from datetime import datetime
from time import mktime
import logging
import random
import unicodecsv
import markdown


from django.conf import settings
from django.contrib import messages
from django.core.mail import EmailMultiAlternatives
from django.db import transaction
from django.forms.models import modelformset_factory
from django.http import HttpResponse
from django.shortcuts import render, redirect, get_object_or_404
from django.template import Context
from django.template.loader import get_template
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.http import require_GET, require_POST

from .forms import (SessionInviteForm, ExperimentSessionForm, ParticipantAttendanceForm, CancelSignupForm)

from vcweb.core.decorators import group_required, ownership_required
from vcweb.core.http import JsonResponse, dumps
from vcweb.core.models import (Participant, ParticipantSignup, PermissionGroup, ExperimentSession, ExperimentMetadata,
Invitation, send_markdown_email)
from vcweb.core.views import mimetypes

from .forms import (SessionInviteForm, ExperimentSessionForm, ParticipantAttendanceForm, CancelSignupForm)
from .models import InvitationEmail

from datetime import datetime
from time import mktime

import logging
import random
import unicodecsv
import markdown

logger = logging.getLogger(__name__)


@group_required(PermissionGroup.experimenter)
@require_GET
def experimenter_index(request):
def subjectpool_index(request):
"""
Provides experimenter subject recruitment interface with all active experiment sessions and past experiment
sessions.
Provides subject recruitment interface with all the active and past experiment sessions.
"""
experimenter = request.user.experimenter
data = ExperimentSession.objects.select_related('experiment_metadata').filter(creator=request.user)
es_list = ExperimentSession.objects.select_related('experiment_metadata').filter(creator=request.user)
session_list = [session.to_dict() for session in es_list]
experiment_metadata_list = [em.to_dict() for em in ExperimentMetadata.objects.bookmarked(experimenter)]
session_list = [session.to_dict() for session in data]
potential_participants_count = Participant.objects.active().count()
session_data = {
"session_list": session_list,
"experiment_metadata_list": experiment_metadata_list,
data = {
'session_list': session_list,
'experiment_metadata_list': experiment_metadata_list,
'allEligibleParticipants': potential_participants_count,
'potentialParticipantsCount': potential_participants_count,
}
form = SessionInviteForm()
return render(request, "subjectpool/experimenter-index.html",
{"view_model_json": dumps(session_data), "form": form})
return render(request, "subjectpool/index.html",
{"view_model_json": dumps(data), "form": SessionInviteForm()})


@group_required(PermissionGroup.experimenter)
Expand All @@ -64,7 +60,7 @@ def manage_experiment_session(request, pk):
return JsonResponse({'success': False, 'errors': form.errors})


@group_required(PermissionGroup.experimenter, PermissionGroup.demo_experimenter)
@group_required(PermissionGroup.experimenter)
@require_GET
def get_session_events(request):
"""
Expand Down Expand Up @@ -148,19 +144,6 @@ def get_invitations_count(request):
return JsonResponse({'success': False, 'invitesCount': 0, 'errors': form.errors})


def get_invitation_email_content(custom_invitation_text, experiment_session_ids):
plaintext_template = get_template('email/invitation-email.txt')
c = Context({
'invitation_text': custom_invitation_text,
'session_list': ExperimentSession.objects.filter(pk__in=experiment_session_ids),
'SITE_URL': settings.SITE_URL,
})
plaintext_content = plaintext_template.render(c)
html_content = markdown.markdown(plaintext_content)

return plaintext_content, html_content


@group_required(PermissionGroup.experimenter)
@require_POST
def send_invitations(request):
Expand Down Expand Up @@ -224,42 +207,39 @@ def send_invitations(request):
Invitation.objects.bulk_create(invitations)

if settings.ENVIRONMENT.is_production:
plaintext_content, html_content = get_invitation_email_content(invitation_text, session_pk_list)
ie = InvitationEmail(request)
plaintext_content = ie.get_plaintext_content(invitation_text, session_pk_list)
html_content = markdown.markdown(plaintext_content)
msg = EmailMultiAlternatives(subject=invitation_subject, body=plaintext_content,
from_email=from_email, to=[from_email], bcc=recipient_list)
msg.attach_alternative(html_content, "text/html")
msg.send()
else:
logger.debug("Sending invitation emails in non-production environment is disabled: %s",
recipient_list)

return JsonResponse({
'success': True,
'message': message,
'invitesCount': len(final_participants)
})
return JsonResponse({'success': True, 'message': message, 'invitesCount': len(final_participants)})
else:
return JsonResponse({
'success': False,
'message': "Please select experiment sessions from the same experiment to send invitations."
})
else:
# Form is not valid
return JsonResponse({'success': False, 'errors': form.errors})
# Form is not valid
return JsonResponse({'success': False, 'errors': form.errors})


@group_required(PermissionGroup.experimenter)
@require_POST
def invite_email_preview(request):
"""
Generates email Preview for the provided invitation details
Generates preview email for the provided invitation details
"""
form = SessionInviteForm(request.POST or None)
message = "Please fill in all the form fields to preview the invitation email."
if form.is_valid():
session_pk_list = request.POST.get('session_pk_list').split(",")
plaintext_content, html_content = get_invitation_email_content(form.cleaned_data.get('invitation_text'),
session_pk_list)
session_ids = request.POST.get('session_pk_list').split(",")
invitation_text = form.cleaned_data.get('invitation_text')
plaintext_content = InvitationEmail(request).get_plaintext_content(invitation_text, session_ids)
html_content = markdown.markdown(plaintext_content)
return JsonResponse({'success': True, 'content': html_content})
return JsonResponse({'success': False, 'message': message})

Expand All @@ -284,12 +264,14 @@ def manage_participant_attendance(request, pk=None):
messages.success(request, 'Your changes were successfully saved.')
if formset.has_changed():
formset.save()
else:
logger.debug("The formset was invalid with errors %s", formset.errors)
messages.error(request, _("Invalid data. Please Try again."))
else:
formset = attendanceformset(queryset=ParticipantSignup.objects.select_related(
'invitation__participant__user').filter(invitation__in=invitations_sent))

return render(request, 'subjectpool/experiment-session-detail.html',
{'session_detail': es, 'formset': formset})
return render(request, 'subjectpool/experiment-session-detail.html', {'session': es, 'formset': formset})


@group_required(PermissionGroup.experimenter)
Expand All @@ -303,13 +285,13 @@ def add_participant(request, pk=None):

es = get_object_or_404(ExperimentSession, pk=pk)

# First check the experiment session should be over
# First check, the experiment session should be over
if es.scheduled_end_date < datetime.now():
logger.debug("Experimeter %s tried adding participant %s to experiment session %s that isn't still over",
request.user, participant, pk)
return JsonResponse({'success': False, 'error': "Can't add a participant to yet not finished experiment session"})

# second check the participant must have recevied invitations
# second check, the participant must have recevied invitations
if len(invitations) == 0:
logger.debug("Experimeter %s tried adding participant %s to experiment session %s, who hasn't recevied invitation for the same",
request.user, participant, pk)
Expand All @@ -322,9 +304,9 @@ def add_participant(request, pk=None):
logger.debug("Experimeter %s tried adding participant %s to experiment session %s, who is already signed up for the same",
request.user, participant, pk)
return JsonResponse({'success': False, 'error': 'Participant is already signed up of the experiment session'})
else:
ParticipantSignup(invitation=invitations[0], attendance=ParticipantSignup.ATTENDANCE.participated).save()
return JsonResponse({'success': True})

ParticipantSignup(invitation=invitations[0], attendance=ParticipantSignup.ATTENDANCE.participated).save()
return JsonResponse({'success': True})


@group_required(PermissionGroup.participant)
Expand Down
2 changes: 1 addition & 1 deletion vcweb/core/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
{% url 'core:register' as register %}
{% url 'core:report_issues' as issues_url %}
{% url 'core:audit_report' as audit_report %}
{% url 'subjectpool:experimenter_index' as subjectpool %}
{% url 'subjectpool:subjectpool_index' as subjectpool %}
<!DOCTYPE html>
<html lang="en">
{% with jquery_version="1.11.2" bootstrap_version="3.3.2" bootswatch_version="3.3.0" fontawesome_version="4.3.0" knockout_version="3.3.0" ravenjs_version="1.1.16" %}
Expand Down
2 changes: 1 addition & 1 deletion vcweb/core/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def test_subjectpool_experimenter_page(self):
e = self.create_experimenter()
self.assertTrue(self.login_experimenter(e))

response = self.get(self.reverse('subjectpool:experimenter_index'))
response = self.get(self.reverse('subjectpool:subjectpool_index'))
self.assertEqual(200, response.status_code)

def test_send_invitations(self):
Expand Down

0 comments on commit 9d65681

Please sign in to comment.