Commit 2fbcc4ad authored by Daniel W Bond's avatar Daniel W Bond
Browse files

Merge branch 'offcampus' into amherst

parents 371e591c c391e21d
......@@ -57,22 +57,33 @@ class SelectRoomField(forms.models.ModelChoiceField):
# should raise error if user hasn't actually selected room, made it to end of selectors
# def clean(self, value):
class BooleanRadioField(forms.TypedChoiceField):
def __init__(self, *args, **kwargs):
boolean_choices = ((True, 'Yes'), (False, 'No'))
kwargs['widget'] = forms.RadioSelect
kwargs['choices'] = boolean_choices
kwargs['coerce'] = bool
kwargs['required'] = True
super(BooleanRadioField, self).__init__(*args, **kwargs)
class StudentUpdateForm(forms.Form):
first_name = forms.CharField(label='First Name', required=False)
last_name = forms.CharField(label='Last Name', required=False)
first_name = forms.CharField(required=False)
last_name = forms.CharField(required=False)
gender = MultiSelectFormField(choices=Student.GENDER_CHOICES,
label='Gender Identity (please choose all that apply)',
required=False)
show_gender = forms.BooleanField(label='Show your gender on your profile?',
required=False)
show_gender = BooleanRadioField()
room = SelectRoomField(queryset=Room.objects.all(), label='', required=False)
on_campus = BooleanRadioField()
room = SelectRoomField(queryset=Room.objects.all(), required=False)
privacy = forms.ChoiceField(choices=Student.PRIVACY_CHOICES)
major = forms.ModelChoiceField(queryset=Major.objects.all(), required=False,
label='Major (select one)',)
graduating_year = forms.IntegerField(label='Graduating Year')
privacy = forms.TypedChoiceField(choices=Student.PRIVACY_CHOICES)
major = forms.ModelChoiceField(queryset=Major.objects.all(), required=False)
graduating_year = forms.IntegerField()
def clean(self):
......@@ -94,15 +105,13 @@ class StudentUpdateForm(forms.Form):
#print(valid)
return valid
class WelcomeNameForm(forms.Form):
first_name = forms.CharField(label='First Name', required=False)
last_name = forms.CharField(label='Last Name', required=False)
gender = MultiSelectFormField(choices=Student.GENDER_CHOICES,
label='Gender Identity (please choose all that apply)',
required=False)
show_gender = forms.BooleanField(label='Show your gender on your profile?',
required=False)
first_name = forms.CharField( required=False)
last_name = forms.CharField(required=False)
gender = MultiSelectFormField(choices=Student.GENDER_CHOICES, required=False)
show_gender = BooleanRadioField()
class WelcomePrivacyForm(forms.ModelForm):
......@@ -112,8 +121,9 @@ class WelcomePrivacyForm(forms.ModelForm):
if self.instance.recent_changes() > 2:
self.fields['room'].widget = forms.widgets.HiddenInput()
else:
self.fields['room'] = SelectRoomField(queryset=Room.objects.all(),
label='', required=False)
self.fields['room'] = SelectRoomField(queryset=Room.objects.all(), required=False)
on_campus = BooleanRadioField()
def clean(self):
cleaned_data = super(WelcomePrivacyForm, self).clean()
......@@ -127,8 +137,7 @@ class WelcomePrivacyForm(forms.ModelForm):
class Meta:
model = Student
fields = ('room', 'privacy', )
fields = ('room', 'privacy', 'on_campus')
class WelcomeSocialForm(forms.ModelForm):
......
......@@ -131,6 +131,7 @@ class Student(TimeStampedModel):
privacy = models.CharField(max_length=100, choices=PRIVACY_CHOICES, default=FLOOR)
on_campus = models.BooleanField(default=True)
room = models.ForeignKey(Room, null=True, blank=True)
major = models.ForeignKey('Major', related_name='major', null=True, blank=True)
......
......@@ -17,7 +17,9 @@
<h1><strong>{{ student.get_full_name_or_uname }}</strong></h1>
{% if shares %}
<p class="lead"><strong>
{% if student.room == None %}
{% if not student.on_campus %}
{{ student.get_first_name_or_uname }} doesn't live on campus.
{% elif student.room == None %}
{{ student.get_first_name_or_uname }} hasn't set their room yet.
{% else %}
<a href="{{ student.room.get_absolute_url }}">{{ student.room }}</a>
......@@ -41,7 +43,12 @@
<p><em>* a number of other floormates say this room info is incorrect</em></p>
{% endif %}
{% endif %}
<p><em>shares room with</em>: <span class="label label-default"><strong>{{ student.privacy }}</strong></span></p>
{% if student.on_campus %}
<p>
<em>shares room with</em>:
<span class="label label-default"><strong>{{ student.privacy }}</strong></span>
</p>
{% endif %}
</div>
</div>
</div>
......
{% load humanize %}
<label>Neighborhood</label>
<label>Neighborhood</label>&nbsp;
<select id="neighborhood" name="neighborhood">
{% for neighborhood in neighborhoods %}
{% if user.student.get_building.neighbourhood == neighborhood.0 %}
......@@ -9,7 +9,7 @@
{% endif %}
{% endfor %}
</select>
<label>Building</label>
&nbsp;&nbsp;<label>Building</label>&nbsp;
<select id="building" name="building">
<option value="">---</option>
{% for building in buildings %}
......@@ -20,7 +20,7 @@
{% endif %}
{% endfor %}
</select>
<label>Floor</label>
&nbsp;&nbsp;<label>Floor</label>&nbsp;
<select id="floor" name="floor">
<option value="">---</option>
{% for floor in floors %}
......@@ -31,7 +31,7 @@
{% endif %}
{% endfor %}
</select>
<label>Room</label>
&nbsp;&nbsp;<label>Room</label>&nbsp;
<select id="room" name="room" class="roompicker">
<option value="">---</option>
{% for room in rooms %}
......
......@@ -13,6 +13,8 @@
{% include 'messages.html' %}
{% load accounts_extras %}
<div class="page-header" id="banner">
<div class="row">
<div class="col-md-12 text-center">
......@@ -143,18 +145,112 @@
</div>
<div class="panel-body">
<p class="text-center">Off-campus locations along with a select number of locations <a href="{% url 'list_buildings'%}#Unsupported">on campus</a> aren't currently supported. You are still welcome to use Roomlist as a limited directory until we add support.</p>
<p class="text-center">A select number of locations <a href="{% url 'list_buildings'%}#Unsupported">on campus</a> aren't currently supported. You are still welcome to use Roomlist as a limited directory until we add support.</p>
<p class="text-center">
If you have a <a href="https://en.gravatar.com/">Gravatar profile</a> associated
with your <a href="https://masonlive.gmu.edu/">Masonlive email</a> address, your
default profile picture on this service will that Gravatar profile picture.
</p>
<hr />
{% if my_form.non_field_errors %}
<ul class="text-center">
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
<hr />
{% endif %}
{% spaceless %}
<form class="form-horizontal" autocomplete="off" action="" method="post">{% csrf_token %}
{{ my_form.as_p }}
<fieldset>
<div class="form-group">
<label for="{{ my_form.first_name.id_for_label }}" class="col-md-2">First Name</label>
<div class="col-md-4">
{% if not my_form.first_name.errors %}
{{ my_form.first_name }}
{% else %}
<div class="has-error">
{{ my_form.first_name }}
<p>{{ form.first_name.errors }}</p>
</div>
{% endif %}
</div>
<label for="{{ my_form.last_name.id_for_label }}" class="col-md-2">Last Name</label>
<div class="col-md-4">
{% if not my_form.last_name.errors %}
{{ my_form.last_name }}
{% else %}
<div class="has-error">
{{ my_form.last_name }}
<p>{{ form.last_name.errors }}</p>
</div>
{% endif %}
</div>
</div>
<div class="form-group">
<label for="{{ my_form.gender.id_for_label }}" class="col-md-3">
Gender Identity<br />(choose all that apply)
</label>
{% for checkbox in my_form.gender %}
<div class="checkbox col-md-3">
<label for="{{ checkbox.id_for_label }}">
{{ checkbox.choice_label|gender_icon }}
{{ checkbox.tag }}
</label>
</div>
{% endfor %}
</div>
<div class="form-group">
<label for="{{ my_form.show_gender.id_for_label }}" class="col-md-3">
Show Gender on Profile?
</label>
{% for option in my_form.show_gender %}
<label class="radio-inline">{{ option.choice_label }}{{ option.tag }}</label>
{% endfor %}
</div>
<div class="form-group">
<label for="{{ my_form.major.id_for_label }}" class="col-md-2">
Major<br />(select one)
</label>
<div class="col-md-4">
{{ my_form.major }}
</div>
</div>
<div class="form-group">
<label for="{{ my_form.graduating_year.id_for_label }}" class="col-md-2">
Graduating Year
</label>
<div class="col-md-2">
{{ my_form.graduating_year }}
</div>
</div>
{% if not request.user.student.recent_changes > 2 %}
<hr />
<div class="form-group">
<label for="{{ my_form.on_campus.id_for_label }}" class="col-md-3">
Do You Live on Campus?
</label>
{% for option in my_form.on_campus %}
<label class="radio-inline">{{ option.choice_label }}{{ option.tag }}</label>
{% endfor %}
</div>
<div id="lives-on-campus">
<div class="form-group">
<div class="col-md-12">
{{ my_form.room }}
</div>
</div>
<div class="form-group">
<label for="{{ my_form.privacy.id_for_label }}" class="col-md-2">
Privacy
</label>
{{ my_form.privacy }}
</div>
</div>
{% endif %}
<hr />
<input type="submit" value="Save" class="btn btn-primary"/>
</fieldset>
</form>
{% endspaceless %}
</div>
......@@ -169,6 +265,27 @@
{% block javascript %}
<script type="text/javascript" src="/static/js/jquery.chained.min.js"></script>
<script>
// toggle room selection availability
// can see if on campus, cannot see if not on campus
$(document).ready(function() {
var $radio = $('input:radio[name=on_campus]');
// when first rendering the page
if($radio.filter('[value=False]').is(':checked')) {
$("#lives-on-campus").hide();
} else {
$("#lives-on-campus").show();
}
// if student changes the value
$($radio.filter('[value=False]').click(function(){
$("#lives-on-campus").slideUp();
}));
$($radio.filter('[value=True]').click(function(){
$("#lives-on-campus").slideDown();
}));
});
$("#lives-on-campus").hide();
// room selection
$("#building").chained("#neighborhood");
$("#floor").chained("#building");
$("#room").chained("#floor");
......
......@@ -7,6 +7,8 @@
{% block content %}
{% load accounts_extras %}
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" style="width: 25%;">
<span class="sr-only">25% complete</span>
......@@ -35,10 +37,64 @@
<div class="panel-heading">
<h1 class="panel-title text-center"><strong>Name & Gender</strong></h1>
</div>
{% if error in my_form.non_field_errors %}
<ul class="text-center">
{% for error in my_form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<div class="panel-body">
<form action="" method="post">{% csrf_token %}
{{ my_form.as_p }}
<form class="form-horizontal" autocomplete="off" action="" method="post">{% csrf_token %}
<fieldset>
<div class="form-group">
<label for="{{ my_form.first_name.id_for_label }}" class="col-md-2">First Name</label>
<div class="col-md-4">
{% if not my_form.first_name.errors %}
{{ my_form.first_name }}
{% else %}
<div class="has-error">
{{ my_form.first_name }}
<p>{{ form.first_name.errors }}</p>
</div>
{% endif %}
</div>
<label for="{{ my_form.last_name.id_for_label }}" class="col-md-2">Last Name</label>
<div class="col-md-4">
{% if not my_form.last_name.errors %}
{{ my_form.last_name }}
{% else %}
<div class="has-error">
{{ my_form.last_name }}
<p>{{ form.last_name.errors }}</p>
</div>
{% endif %}
</div>
</div>
<div class="form-group">
<label for="{{ my_form.gender.id_for_label }}" class="col-md-3">
Gender Identity<br />(choose all that apply)
</label>
{% for checkbox in my_form.gender %}
<div class="checkbox col-md-3">
<label for="{{ checkbox.id_for_label }}">
{{ checkbox.choice_label|gender_icon }}
{{ checkbox.tag }}
</div>
{% endfor %}
</div>
<div class="form-group">
<label for "{{ my_form.show_gender.id_for_label }}" class="col-md-3">
Show Gender on Profile?
</label>
{% for radio in my_form.show_gender %}
<label class="radio-inline">{{ radio.choice_label }}{{ radio.tag }}</label>
{% endfor %}
</div>
</fieldset>
<input type="submit" value="Save" class="btn btn-primary"/>
</form>
</div>
......
......@@ -26,12 +26,14 @@
<div class="row">
<div class="col-md-8 col-md-offset-2">
<p class="text-center">Great, {{ request.user.student.get_first_name_or_uname }}! Now to your housing information and settings. Here, you'll select which room you live in, and then choose who you want to be able to see that information.</p>
<p class="text-center">If you don't live on campus, you can select 'No' and move right along.</p>
<p class="text-center">For on campus students, here you'll select which room you live in, and then choose who you want to be able to see that information.</p>
<p class="text-center"><strong>By default, your privacy is set to 'Floor'.</strong> That means only other students <em>living on your floor</em> can see your room or links to your social media profiles.
You can choose to set your privacy to '<strong>Building</strong>', which will make your room visible to everyone living in your building, or to '<strong>Campus</strong>', where it will be visible to anyone with a current Mason username and password.</p>
<p class="text-center">To close a rather straightforward privacy loophole, you can only change your room a limited number of times a year, after which you will need to
<a href="mailto:roomlist@lists.srct.gmu.edu?Subject=I%20Don%27t%20Know%20Where%20I%20Live%3A%20Halp%20Pls">email us</a>.
</p>
<p class="text-center">Off-campus locations along with a select number of locations <a href="{% url 'list_buildings' %}#Unsupported">on campus</a> are not currently supported. You are still welcome to use roomlist as a limited interactive directory until we add support.</p>
<p class="text-center">A select number of locations <a href="{% url 'list_buildings' %}#Unsupported">on campus</a> are not currently supported. You are still welcome to use roomlist as an interactive directory until we add support.</p>
</div>
</div>
......@@ -44,12 +46,49 @@
</div>
<div class="panel-body">
{% if not request.user.student.recent_changes > 2 %}
{% spaceless %}
{% if my_form.non_field_errors %}
<hr />
<ul class="text-center">
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
<hr />
{% endif %}
<form class="form-horizontal" autocomplete="off" action="" method="post">{% csrf_token %}
{{ my_form.as_p }}
<fieldset>
<div class="form-group">
<label for="{{ my_form.on_campus.id_for_label }}" class="col-md-3">
Do You Live on Campus?
</label>
{% for option in my_form.on_campus %}
<label class="radio-inline">{{ option.choice_label }}{{ option.tag }}</label>
{% endfor %}
</div>
<div id="lives-on-campus">
<div class="form-group">
<div class="col-md-12">
{{ my_form.room }}
</div>
</div>
<div class="form-group">
<label for="{{ my_form.privacy.id_for_label }}" class="col-md-2">
Privacy
</label>
{{ my_form.privacy }}
</div>
</div>
</fieldset>
<input type="submit" value="Save" class="btn btn-primary"/>
</form>
{% endspaceless %}
{% else %}
<a href="{% url 'welcomeMajor' request.user.username %}">
<button type="button" class="btn btn-primary">Continue</button>
</a>
{% endif %}
</div>
</div>
......@@ -71,6 +110,27 @@
{% block javascript %}
<script type="text/javascript" src="/static/js/jquery.chained.min.js"></script>
<script>
// toggle room selection availability
// can see if on campus, cannot see if not on campus
$(document).ready(function() {
var $radio = $('input:radio[name=on_campus]');
// when first rendering the page
if($radio.filter('[value=False]').is(':checked')) {
$("#lives-on-campus").hide();
} else {
$("#lives-on-campus").show();
}
// if student changes the value
$($radio.filter('[value=False]').click(function(){
$("#lives-on-campus").slideUp();
}));
$($radio.filter('[value=True]').click(function(){
$("#lives-on-campus").slideDown();
}));
});
$("#lives-on-campus").hide();
// room selection
$("#building").chained("#neighborhood");
$("#floor").chained("#building");
$("#room").chained("#floor");
......
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
......@@ -11,3 +12,21 @@ def bc(num):
return "%s B.C." % (positive_value)
else:
return num
@register.filter(name='gender_icon')
def gender_icon(gender_name):
icon_template = '<i class="fa fa-%s fa-fw"></i>'
if gender_name == 'male':
icon_tag = (icon_template % 'mars') + " Male"
elif gender_name == 'female':
icon_tag = (icon_template % 'venus') + " Female"
elif gender_name == 'trans':
icon_tag = (icon_template % 'transgender') + " Trans"
elif gender_name == 'intersex':
icon_tag = (icon_template % 'transgender-alt') + " Intersex"
elif gender_name == 'genderless':
icon_tag = (icon_template % 'genderless') + " Genderless"
elif gender_name == 'other':
icon_tag = (icon_template % 'mars-stroke-v') + " Other"
return mark_safe(icon_tag)
# standard library imports
from __future__ import absolute_import, print_function
import random
from distutils.util import strtobool
# core django imports
from django.shortcuts import get_object_or_404
from django.http import HttpResponseForbidden, HttpResponseRedirect
......@@ -203,7 +204,6 @@ class DetailCurrentStudentSettings(LoginRequiredMixin, DetailView):
def get_object(self):
return get_object_or_404(Student, pk=self.request.session['_auth_user_id'])
# update a student, but FormView to allow name update on same page
class UpdateStudent(LoginRequiredMixin, FormValidMessageMixin, FormView):
template_name = 'updateStudent.html'
......@@ -234,13 +234,21 @@ class UpdateStudent(LoginRequiredMixin, FormValidMessageMixin, FormView):
'room': pk_or_none(me, me.room),
'privacy': me.privacy,
'major': pk_or_none(me, me.major),
'graduating_year' : me.graduating_year,})
'graduating_year': me.graduating_year,
'on_campus': me.on_campus, })
if me.recent_changes() > 2:
form.fields['room'].widget = HiddenInput()
form.fields['privacy'].widget = HiddenInput()
form.fields['on_campus'].widget = HiddenInput()
else:
form.fields['room'].widget.user = self.request.user
# bootstrap
form.fields['first_name'].widget.attrs['class'] = 'form-control'
form.fields['last_name'].widget.attrs['class'] = 'form-control'
form.fields['graduating_year'].widget.attrs['class'] = 'form-control'
context['my_form'] = form
return context
......@@ -261,15 +269,29 @@ class UpdateStudent(LoginRequiredMixin, FormValidMessageMixin, FormView):
#print(key, value)
current_room = me.room
try:
form_room = Room.objects.get(pk=form.data['room'])
except:
# if you somehow got around the hidden widget, you're still outta luck
if me.recent_changes() > 2:
form_room = current_room
else:
try:
form_room = Room.objects.get(pk=form.data['room'])
except:
form_room = None
# casts to an integer, 0 or 1
on_campus = strtobool(form.data.get('on_campus', 'True'))
# no room if you move off campus
if not on_campus:
form_room = None
# note this is after the 'on campus' check
if current_room != form_room:
me.times_changed_room += 1
Confirmation.objects.filter(student=me).delete()
me.on_campus = on_campus
me.room = form_room
try:
......@@ -280,7 +302,7 @@ class UpdateStudent(LoginRequiredMixin, FormValidMessageMixin, FormView):
me.user.first_name = form.data['first_name']
me.user.last_name = form.data['last_name']
me.gender = form.data.getlist('gender')
me.show_gender = form.data.get('show_gender', False)
me.show_gender = strtobool(form.data.get('show_gender', 'False'))
me.privacy = form.data['privacy']
me.graduating_year = form.data['graduating_year']
......@@ -330,6 +352,10 @@ class WelcomeName(LoginRequiredMixin, FormView):
'last_name': me.user.last_name,
'gender': me.gender,
'show_gender': me.show_gender, })
form.fields['first_name'].widget.attrs['class'] = 'form-control'
form.fields['last_name'].widget.attrs['class'] = 'form-control'
context['my_form'] = form
return context
......@@ -345,7 +371,7 @@ class WelcomeName(LoginRequiredMixin, FormView):
me.user.last_name = form.data['last_name']
me.gender = form.data.getlist('gender')
me.show_gender = form.data.get('show_gender', False)
me.show_gender = strtobool(form.data.get('show_gender', 'False'))
me.completedName = True
......@@ -390,6 +416,8 @@ class WelcomePrivacy(LoginRequiredMixin, UpdateView):
form.fields['room'].widget.user = self.request.user