diff --git a/requirements.txt b/requirements.txt index 9e67ee8c..cdca65da 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -Django==1.7.6 +Django==1.7.7 Fabric==1.10.1 Markdown==2.6.1 Pillow==2.7.0 @@ -35,7 +35,6 @@ wsgiref==0.1.2 xlrd==0.9.3 xlwt==0.7.5 dealer==2.0.4 -uwsgi==2.0.9 +uwsgi==2.0.10 # virtualcommons forked django-cas git+http://git@github.com/virtualcommons/django-cas.git#egg=cas - diff --git a/vcweb/core/decorators.py b/vcweb/core/decorators.py index e7d0150c..d6927d09 100644 --- a/vcweb/core/decorators.py +++ b/vcweb/core/decorators.py @@ -25,7 +25,7 @@ def is_anonymous(user): return user is None or not user.is_authenticated() -def anonymous_required(view_function=None, redirect_to='core:dashboard'): +def anonymous_required(view_function=None, redirect_to='home'): return create_user_decorator(view_function, is_anonymous, redirect_to=redirect_to) @@ -47,29 +47,26 @@ def is_participant(user): def group_required(*permission_groups, **kwargs): """Requires user membership in at least one of the groups passed in.""" def in_groups(u): - if u.is_authenticated() and (is_participant(u) or is_experimenter(u)): - group_names = [pgroup.value for pgroup in permission_groups] + if u.is_authenticated() and u.is_active: + group_names = [pg.value for pg in permission_groups] return u.groups.filter(name__in=group_names).exists() return user_passes_test(in_groups) -def create_user_decorator(view_function, is_valid_user, redirect_to='core:dashboard'): - - def decorator(fn): +def create_user_decorator(view_function, is_valid_user, redirect_to='core:login'): + def _decorator(fn): + @wraps(fn) def _decorated_view(request, *args, **kwargs): - if is_valid_user(request.user): - logger.debug('user was valid: %s', request.user) + user = request.user + if is_valid_user(user): + logger.debug('checked if user %s was valid with %s', user, is_valid_user) return fn(request, *args, **kwargs) else: - logger.debug('user was invalid, redirecting to %s', redirect_to) + logger.debug('user %s was deemed invalid with %s, redirecting to %s', user, is_valid_user, redirect_to) return redirect(redirect_to) - - _decorated_view.__name__ = fn.__name__ - _decorated_view.__dict__ = fn.__dict__ - _decorated_view.__doc__ = fn.__doc__ return _decorated_view - return decorator if view_function is None else decorator(view_function) + return _decorator if view_function is None else _decorator(view_function) def retry(exceptiontocheck, tries=4, delay=3, backoff=2, logger=None): diff --git a/vcweb/core/models.py b/vcweb/core/models.py index 35952d04..5cae7df0 100644 --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -289,6 +289,16 @@ class Meta: ordering = ['title', 'namespace'] +class ActivityLog(models.Model): + LogType = Choices('Experimenter', 'Scheduled', 'System') + log_message = models.TextField() + date_created = models.DateTimeField(auto_now_add=True) + # log_type = models.CharField(max_length=64, choices=LogType, default=LogType.System) + + def __unicode__(self): + return u"%s - %s" % (self.date_created.strftime("%m-%d-%Y %H:%M"), self.log_message) + + class OstromlabFaqEntry(models.Model): question = models.TextField(help_text=_("FAQ Question")) answer = models.TextField(help_text=_("FAQ Answer")) @@ -1160,7 +1170,7 @@ def initialize_data_values(self, group_parameters=None, participant_parameters=N defaults=parameter_defaults[parameter]) logger.debug("prdv: %s (%s)", participant_data_value, created) - def log(self, log_message, *args, **kwargs): + def log(self, log_message, log_type=ActivityLog.LogType.System, *args, **kwargs): if log_message: message = "%s: %s" % (self, log_message) logger.debug(message, *args) @@ -1422,10 +1432,9 @@ def check_elapsed_time(self): def all_round_data(self): # FIXME: figure out a better way to convert these to json that doesn't involve manual remapping of attribute - # names or be consistent so that things on the client side are named - # the same as the server side + # names or be consistent so that things on the client side are named the same as the server side all_round_data = [] - for round_data in self.round_data_set.select_related('round_configuration').reverse(): + for round_data in self.round_data_set.select_related('round_configuration').order_by('-pk'): rc = round_data.round_configuration all_round_data.append({ 'pk': round_data.pk, @@ -2114,7 +2123,7 @@ def get_related_group(self): else: return None - def log(self, log_message): + def log(self, log_message, log_type=ActivityLog.LogType.System): if log_message: logger.debug(log_message) self.activity_log_set.create(round_configuration=self.current_round, log_message=log_message) @@ -2839,14 +2848,6 @@ def to_dict(self, cacheable=True, include_email=False): return super(Like, self).to_dict(cacheable=cacheable) -class ActivityLog(models.Model): - log_message = models.TextField() - date_created = models.DateTimeField(auto_now_add=True) - - def __unicode__(self): - return u"%s - %s" % (self.date_created.strftime("%m-%d-%Y %H:%M"), self.log_message) - - class GroupActivityLog(ActivityLog): group = models.ForeignKey(Group, related_name='activity_log_set') round_configuration = models.ForeignKey(RoundConfiguration) @@ -2996,7 +2997,7 @@ def _experiment_metadata_criteria(self, criteria, return criteria def with_attendance(self, attendance, **kwargs): - attendance_key = 'attendance__in' if isinstance(attendance, (list, tuple)) else 'attendance' + attendance_key = 'attendance__in' if isinstance(attendance, (list, set, tuple)) else 'attendance' criteria = self._experiment_metadata_criteria({attendance_key: attendance}, **kwargs) return self.filter(**criteria) @@ -3242,8 +3243,10 @@ def weekly_schedule_tasks(sender, start=None, **kwargs): experiment status changes (run or archived), invitations sent """ # FIXME add information regarding experiment status changes - invalid_permission_participants = Participant.objects.active().exclude(user__groups__name=PermissionGroup.participant) - invalid_permission_experimenters = Experimenter.objects.filter(user__is_active=True).exclude(user__email__contains=('mailinator.com')).exclude(user__groups__name=PermissionGroup.experimenter) + invalid_permission_participants = Participant.objects.active().exclude( + user__groups__name=PermissionGroup.participant.value) + invalid_permission_experimenters = Experimenter.objects.filter(user__is_active=True).exclude( + user__email__contains=('mailinator.com')).exclude(user__groups__name=PermissionGroup.experimenter.value) # invalid users who are experimenter as well as participant participant_users = Participant.objects.active().values_list('user__id', flat=True) @@ -3256,10 +3259,14 @@ def weekly_schedule_tasks(sender, start=None, **kwargs): # Invitations sent in last week invites_last_week = Invitation.objects.filter(date_created__gt=last_week_datetime).count() - email = create_markdown_email(template="email/audit-email.txt", context={ - "invalid_users": invalid_users, - "participants": invalid_permission_participants, - "experimenters": invalid_permission_experimenters, - "signups": signup_last_week, "invites": invites_last_week - }, subject="VCWEB Audit", to_email=[settings.DEFAULT_EMAIL]) - mail.get_connection().send_messages([email,]) + email = create_markdown_email(template="email/audit-email.txt", + context={ + "invalid_users": invalid_users, + "participants": invalid_permission_participants, + "experimenters": invalid_permission_experimenters, + "signups": signup_last_week, + "invites": invites_last_week + }, + subject="VCWEB Audit", + to_email=[settings.DEFAULT_EMAIL]) + email.send() diff --git a/vcweb/core/templates/experimenter/session_detail.html b/vcweb/core/subjectpool/templates/subjectpool/experiment-session-detail.html similarity index 99% rename from vcweb/core/templates/experimenter/session_detail.html rename to vcweb/core/subjectpool/templates/subjectpool/experiment-session-detail.html index a9d423ff..8183b9ce 100644 --- a/vcweb/core/templates/experimenter/session_detail.html +++ b/vcweb/core/subjectpool/templates/subjectpool/experiment-session-detail.html @@ -15,6 +15,7 @@ {{ session_detail.scheduled_end_date.time }}

Location: {{ session_detail.location }}

Capacity: {{ session_detail.capacity }}

+

Waitlist enabled: {{ session_detail.waitlist }}

{% if formset.forms|length > 0 %} diff --git a/vcweb/core/templates/participant/experiment-session-signup.html b/vcweb/core/subjectpool/templates/subjectpool/experiment-session-signup.html similarity index 100% rename from vcweb/core/templates/participant/experiment-session-signup.html rename to vcweb/core/subjectpool/templates/subjectpool/experiment-session-signup.html diff --git a/vcweb/core/templates/experimenter/subject-pool-index.html b/vcweb/core/subjectpool/templates/subjectpool/experimenter-index.html similarity index 100% rename from vcweb/core/templates/experimenter/subject-pool-index.html rename to vcweb/core/subjectpool/templates/subjectpool/experimenter-index.html diff --git a/vcweb/core/subjectpool/views.py b/vcweb/core/subjectpool/views.py index a2cd05c5..88ed7f59 100644 --- a/vcweb/core/subjectpool/views.py +++ b/vcweb/core/subjectpool/views.py @@ -49,7 +49,7 @@ def experimenter_index(request): 'potentialParticipantsCount': potential_participants_count, } form = SessionInviteForm() - return render(request, "experimenter/subject-pool-index.html", + return render(request, "subjectpool/experimenter-index.html", {"view_model_json": dumps(session_data), "form": form}) @@ -288,7 +288,7 @@ def manage_participant_attendance(request, pk=None): formset = attendanceformset(queryset=ParticipantSignup.objects.select_related( 'invitation__participant__user').filter(invitation__in=invitations_sent)) - return render(request, 'experimenter/session_detail.html', + return render(request, 'subjectpool/experiment-session-detail.html', {'session_detail': es, 'formset': formset}) @@ -350,7 +350,8 @@ def submit_experiment_session_signup(request): if registered or waitlist: # Check for any already registered or waitlisted participant signups for the current user - ps = ParticipantSignup.objects.registered_or_waitlisted(invitation__participant=user.participant, invitation__experiment_session__experiment_metadata__pk=experiment_metadata_pk) + ps = ParticipantSignup.objects.registered_or_waitlisted(invitation__participant=user.participant, + experiment_metadata_pk=experiment_metadata_pk) ps = ps.first() if len(ps) > 0 else ParticipantSignup() @@ -428,4 +429,4 @@ def experiment_session_signup(request): still eligible to participate in future experiments and may receive future invitations for this experiment.""")) - return render(request, "participant/experiment-session-signup.html", {"invitation_list": invitation_list}) + return render(request, "subjectpool/experiment-session-signup.html", {"invitation_list": invitation_list}) diff --git a/vcweb/core/templates/base.html b/vcweb/core/templates/base.html index c8b368df..2ca499a7 100644 --- a/vcweb/core/templates/base.html +++ b/vcweb/core/templates/base.html @@ -4,6 +4,7 @@ {% load raven %} {% url 'about' as about %} {% url 'home' as home %} +{% url 'contact_form' as contact %} {% url 'core:dashboard' as dashboard %} {% url 'core:login' as login %} {% url 'core:logout' as logout %} @@ -42,21 +43,21 @@ - the virtual commonsvirtual commons + the virtual commonsvirtual commons