Commit 1f8de306 authored by Daniel W Bond's avatar Daniel W Bond
Browse files

added comments to the accounts app

parent 867e0dc0
......@@ -14,26 +14,33 @@ from allauth.exceptions import ImmediateHttpResponse
from braces.views import LoginRequiredMixin
class AccountAdapter(DefaultSocialAccountAdapter):
"""A custom implementation of a portion of the allauth social media package.
# the request processed by the adapter is one from the successful oauth callback
We're overriding a number of aspects of the allauth account adapter to support
our special use of the package. We are using CAS, not Django's built-in
authentication. Accordingly we change the where directed when successfully
connecting an account and how errors are dealt with. Additionally, we are not using
the social media accounts to verify or overwrite any aspect of the User model.
"""
# the request processed by the adapter is one from the successful oauth callback
# uncomment this method to print what URL you are arriving from
#def pre_social_login(self, request, sociallogin):
#print(request.get_full_path(), 'pre_login')
def populate_user(self, request, sociallogin, data):
# we don't actually want to overwrite anything from the
# social media account user
# This is a hook to populate User attributes, but we expressly don't actually
# want to overwrite anything from the social media account user. It's intended
# in the package for when you are using social media for login.
user = sociallogin.user
return user
def get_connect_redirect_url(self, request, socialaccount):
# where the user is sent if the social account is indeed authenticated
assert request.user.is_authenticated()
#print(request.get_full_path())
#if 'welcome' in request.get_full_path():
# ergo, we go with more of an approximation (at least for now)
# we are approximating that if a user has not completed the welcome walkthough,
# it is likely the page on which they started-- see the pre_social_login method
if not request.user.student.completedSocial:
return reverse('welcomeSocial', kwargs={
'slug': request.user.username,
......@@ -45,6 +52,7 @@ class AccountAdapter(DefaultSocialAccountAdapter):
def authentication_error(self, request, provider_id, error=None, exception=None,
extra_context=None):
"""Adds a custom message to the message queue if social media auth fails."""
error_message = """Looks like something went awry with your social
authentication. Wait a moment and try your username and
......@@ -52,6 +60,8 @@ class AccountAdapter(DefaultSocialAccountAdapter):
sending an email to roomlist@lists.srct.gmu.edu."""
if not request.user.student.completedSocial:
# as a reminder, here is how django handles messages
# https://docs.djangoproject.com/en/1.8/ref/contrib/messages/
messages.add_message(request, messages.ERROR, error_message)
social_redirect = HttpResponseRedirect(reverse('welcomeSocial', kwargs={
'slug': request.user.username,
......@@ -65,6 +75,10 @@ class AccountAdapter(DefaultSocialAccountAdapter):
raise ImmediateHttpResponse(update_redirect)
class RemoveSocialConfirmationView(LoginRequiredMixin, ConnectionsView):
"""To customize where users are sent when removing their social media connections.
We have written our own template to handle this feature that is much prettier than
the one provided by allauth."""
template_name = "remove_social.html"
login_url = 'login'
......
......@@ -13,6 +13,7 @@ from housing.models import Building, Floor, Room
class SelectRoomWidget(forms.widgets.Select):
"""A series of dropdowns in which a student can filter through housing options."""
template_name = 'room_select_widget.html'
......@@ -47,6 +48,7 @@ class SelectRoomWidget(forms.widgets.Select):
class SelectRoomField(forms.models.ModelChoiceField):
"""A special field for room selection, using the room selection widget."""
widget = SelectRoomWidget
# should raise error if user hasn't actually selected room, made it to end of selectors
......@@ -54,6 +56,7 @@ class SelectRoomField(forms.models.ModelChoiceField):
class BooleanRadioField(forms.TypedChoiceField):
"""Displays booleans as a radio selector, rather than checkboxes."""
def __init__(self, *args, **kwargs):
boolean_choices = ((True, 'Yes'), (False, 'No'))
......
# standard library imports
from __future__ import absolute_import, print_function
from __future__ import absolute_import, print_function, division
import hashlib
from datetime import date
# core django imports
......@@ -46,6 +46,12 @@ class Major(TimeStampedModel):
class StudentQuerySet(models.query.QuerySet):
"""Set theory defining groups of students based on their housing locations.
Used in determining privacy."""
# allows calling .floor or .building or .students when referencing a students'
# privacy to simplify life syntactically
def floor(self):
return self.filter(privacy='floor')
......@@ -73,6 +79,10 @@ class StudentQuerySet(models.query.QuerySet):
return list(floor) + list(set(building_students) - set(floor))
def visible(self, student, housing):
"""Returns a list of students visible to the student reviewing a housing object.
Example usage:
Student.objects.visible(request.user.student, floor)"""
if isinstance(housing, Room):
rooms = [housing]
elif isinstance(housing, Floor):
......@@ -96,8 +106,8 @@ class StudentQuerySet(models.query.QuerySet):
class StudentManager(models.Manager):
# this 'duplication' allows for queryset chaining
# https://docs.djangoproject.com/en/1.8/topics/db/managers/
def get_queryset(self):
return StudentQuerySet(self.model, using=self._db)
......@@ -173,9 +183,9 @@ class Student(TimeStampedModel):
original_first_name = models.CharField(max_length=100, blank=True)
original_last_name = models.CharField(max_length=100, blank=True)
# social media accounts
# welcome walkthrough completion
# each of these booleans is toggled when a student submits the form
# on the associated page
completedName = models.BooleanField(default=False)
completedPrivacy = models.BooleanField(default=False)
completedMajor = models.BooleanField(default=False)
......@@ -186,7 +196,7 @@ class Student(TimeStampedModel):
objects = StudentManager()
# this doesn't take into account superseniors or graduate students or negative values
# hence private method
# hence private method; not yet suggested for use
def _get_class(self):
time_to_graduate = self.graduating_year - self.current_year
if time_to_graduate >= 4:
......@@ -201,17 +211,19 @@ class Student(TimeStampedModel):
return "magic"
def recent_changes(self):
# part of TimeStampedModel
# timezone.now takes into account timezones, which a local machine may not
now = timezone.now()
# part of TimeStampedModel
created = self.created
# could make this more formal with dateutil, but...
days = (now - created).days
# must be int-- floor function
third_years = (days / (30 * 4)) + 1
third_years = (days // (30 * 4)) + 1
return (self.times_changed_room / third_years)
return (self.times_changed_room // third_years)
def get_floor(self):
try:
......@@ -228,6 +240,7 @@ class Student(TimeStampedModel):
return None
def totally_done(self):
"""To assess if a user has completed the welcome walkthrough."""
if self.completedName and self.completedPrivacy and self.completedMajor and self.completedSocial:
return True
else:
......@@ -248,7 +261,9 @@ class Student(TimeStampedModel):
def get_flag_count(self):
my_flag_num = Confirmation.objects.filter(student=self, lives_there=False).count()
return my_flag_num
# displays the student's username if the student if they choose to delete their name
def get_first_name_or_uname(self):
if not(self.user.get_short_name()):
return self.user.username
......@@ -267,6 +282,7 @@ class Student(TimeStampedModel):
else:
return self.user.get_full_name()
# how recently has the student joined roomlist? changes some messages displayed
def is_noob(self):
now = timezone.now()
days = (now - self.created).days
......@@ -283,8 +299,9 @@ class Student(TimeStampedModel):
def __unicode__(self):
return unicode(self.user.username)
# def save(self, *args, **kwargs):
# uncomment if there's something going awry while saving
#def save(self, *args, **kwargs):
#print('we be savin\'!')
#from django.db.models.signals import pre_save, post_save
#for signal in [pre_save, post_save]:
......@@ -293,6 +310,7 @@ class Student(TimeStampedModel):
class Confirmation(TimeStampedModel):
"""Tracks relations between two students in crowdsourcing the room validity."""
confirmer = models.ForeignKey(Student, related_name='confirmer_set')
student = models.ForeignKey(Student, related_name='student_set')
......
bug_reporting = """Welcome back to SRCT Roomlist. This project is the
<a href="https://srct.gmu.edu/projects/">collaborative work
of students like you</a>. If you see anything amiss, or have ideas for
features or a better user experience, please send an email to
roomlist@lists.srct.gmu.edu, tweet
<a href="https://twitter.com/MasonSRCT/">@MasonSRCT</a>, or, for the
more technically experienced, review our
<a href="https://git.gmu.edu/srct/roomlist/issues">issues page</a>."""
privacy_reminder = """Welcome back to SRCT Roomlist. A friendly reminder you can change
your privacy settings at any time on your settings page by
clicking the cog in the upper right of your screen."""
disclaimer = """Welcome back to SRCT Roomlist. Just to be perfectly clear, this project
is provided as a service by the
<a href="https://gmu.collegiatelink.net/organization/srct">registered
student organization</a>
<a href="https://srct.gmu.edu/">Student-Run Computing and Technology</a>.
We are not a part of <a href="http://housing.gmu.edu/">Mason Housing</a>:
all information is voluntarily provided by participating students."""
whatsopen_plug = """Welcome back to SRCT Roomlist. Wondering what's open at this hour?
Check out another one of our
<a href="https://srct.gmu.edu/projects/">student-built and hosted</a>
projects: <a href="https://whatsopen.gmu.edu/">whatsopen.gmu.edu</a>."""
open_source = """Welcome back to SRCT Roomlist. For the curious at heart,
<a href="http://www.gnu.org/philosophy/free-sw.en.html">you can always
review</a> this project's
<a href="https://git.gmu.edu/srct/roomlist/tree/master">source code</a>.
Come <a href="https://srct.gmu.edu/">to a meeting</a> and learn how to
contribute!"""
return_messages = [bug_reporting, privacy_reminder, disclaimer, whatsopen_plug, open_source]
{% extends 'layouts/base.html' %}
{% block title %} SRCT Roomlist | {{ student.get_full_name_or_uname }} {% endblock %}
{% block messsage_queue %}
{% endblock %}
{% block content %}
{% load socialaccount %} {% load gravatar %}
<div class="page-header" id="banner">
<div class="row">
<div class="col-md-8 col-md-offset-2 text-center">
<img class="img-circle img-responsive center center-block" src="{{ student.profile_image_url }}" alt="{{ student.get_first_name_or_uname }} Gravatar picture">
<h1>{{ student.get_full_name_or_uname }} , {{ student.user.username }}</h1>
</div>
</div>
</div>
{% load socialaccount %} {% providers_media_js %}
<legend>Account Settings</legend>
<div class="row">
{{ student }} text text text {{ request.user }}
<a href="{% url 'update_student' request.user.student.slug %}">
<div class="col-md-3 text-center">
<h4><i class="fa fa-lock fa-5x"></i></h4>
<h4>Set Your Room and Privacy</h4>
</div>
</a>
<a href="{% url 'update_student_major' request.user.student.slug %}">
<div class="col-md-3 text-center">
<h4><i class="fa fa-graduation-cap fa-5x"></i></h4>
<h4>Set Your Major</h4>
</div>
</a>
{% comment %} email was here; a good idea {% endcomment %}
</div>
<legend style="margin-top: 50px">Social Media Settings</legend>
<div class="row" style="margin-top: 50px">
<a href="{% provider_login_url 'facebook' method='js_sdk' process='connect' next='/accounts/student/' %}">
<div class="col-md-3 text-center">
<h4><i class="fa fa-facebook fa-5x"></i></h4>
<h4>Link to your Facebook</h4>
</div>
</a>
<a href="{% provider_login_url 'google' process='connect' next='/accounts/student/' %}">
<div class="col-md-3 text-center">
<h4><i class="fa fa-google fa-5x"></i></h4>
<h4>Link to your Google</h4>
</div>
</a>
<a href="{% provider_login_url 'twitter' process='connect' next='/accounts/student/' %}">
<div class="col-md-3 text-center">
<h4><i class="fa fa-twitter fa-5x"></i></h4>
<h4>Link to your Twitter</h4>
</div>
</a>
<div class="col-md-3 text-center">
<!--<a href="{% provider_login_url 'instagram' process='connect' next='/accounts/student/' %}"><i class="fa fa-instagram fa-5x"></i></a>-->
<h4><i class="fa fa-instagram fa-5x"></i></h4>
<h4>Link to your Instagram (Soon!)</h4>
</div>
</div>
{% endblock %}
......@@ -24,22 +24,15 @@ urlpatterns = patterns('',
url(r'^student/(?P<slug>[\w-]+)/$',
DetailStudent.as_view(), name='detail_student'),
#url(r'^student/$',
#cache_page(60 * 2)(DetailCurrentStudent.as_view()),
#name='detailCurrentStudent'),
# student settings
url(r'^student/(?P<slug>[\w-]+)/settings/$',
UpdateStudent.as_view(), name='update_student'),
# custom allauth page to disconnect a social media account
url(r'^student/(?P<slug>[\w-]+)/settings/social/remove/$',
RemoveSocialConfirmationView.as_view(),
name='remove_social'),
#url(r'^settings/$',
#cache_page(4)(DetailCurrentStudentSettings.as_view()),
#name='currentStudentSettings'),
# student confirmation pages
url(r'^student/(?P<student_slug>[\w-]+)/flag/$',
CreateConfirmation.as_view(), name='createConfirmation'),
......
......@@ -21,47 +21,11 @@ from ratelimit.decorators import ratelimit
from .models import Student, Major, Confirmation
from housing.models import Building, Floor, Room
from .forms import StudentUpdateForm
#########
bug_reporting = """Welcome back to SRCT Roomlist. This project is the
<a href="https://srct.gmu.edu/projects/">collaborative work
of students like you</a>. If you see anything amiss, or have ideas for
features or a better user experience, please send an email to
roomlist@lists.srct.gmu.edu, tweet
<a href="https://twitter.com/MasonSRCT/">@MasonSRCT</a>, or, for the
more technically experienced, review our
<a href="https://git.gmu.edu/srct/roomlist/issues">issues page</a>."""
privacy_reminder = """Welcome back to SRCT Roomlist. A friendly reminder you can change
your privacy settings at any time on your settings page by
clicking the cog in the upper right of your screen."""
disclaimer = """Welcome back to SRCT Roomlist. Just to be perfectly clear, this project
is provided as a service by the
<a href="https://gmu.collegiatelink.net/organization/srct">registered
student organization</a>
<a href="https://srct.gmu.edu/">Student-Run Computing and Technology</a>.
We are not a part of <a href="http://housing.gmu.edu/">Mason Housing</a>:
all information is voluntarily provided by participating students."""
whatsopen_plug = """Welcome back to SRCT Roomlist. Wondering what's open at this hour?
Check out another one of our
<a href="https://srct.gmu.edu/projects/">student-built and hosted</a>
projects: <a href="https://whatsopen.gmu.edu/">whatsopen.gmu.edu</a>."""
open_source = """Welcome back to SRCT Roomlist. For the curious at heart,
<a href="http://www.gnu.org/philosophy/free-sw.en.html">you can always
review</a> this project's
<a href="https://git.gmu.edu/srct/roomlist/tree/master">source code</a>.
Come <a href="https://srct.gmu.edu/">to a meeting</a> and learn how to
contribute!"""
#########
return_messages = [bug_reporting, privacy_reminder, disclaimer, whatsopen_plug, open_source]
from .student_messages import return_messages
def custom_cas_login(request, *args, **kwargs):
"""If a student has not completed the welcome walkthrough, go there on login."""
response = cas_login(request, *args, **kwargs)
# returns HttpResponseRedirect
......@@ -84,6 +48,7 @@ def custom_cas_login(request, *args, **kwargs):
return response
# only two students on the same floor can confirm one another (crowdsourced verification)
def on_the_same_floor(student, confirmer):
if student == confirmer:
# Student is confirmer
......@@ -168,36 +133,6 @@ class DetailStudent(LoginRequiredMixin, DetailView):
return context
class DetailCurrentStudent(LoginRequiredMixin, DetailView):
model = Student
context_object_name = 'student'
template_name = 'detailStudent.html'
login_url = 'login'
def get_object(self):
return get_object_or_404(Student, pk=self.request.session['_auth_user_id'])
# changeable student settings
class DetailStudentSettings(LoginRequiredMixin, DetailView):
model = Student
context_object_name = 'student'
template_name = 'studentSettings.html'
login_url = 'login'
class DetailCurrentStudentSettings(LoginRequiredMixin, DetailView):
model = Student
context_object_name = 'student'
template_name = 'studentSettings.html'
login_url = 'login'
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 = 'update_student.html'
......@@ -374,6 +309,9 @@ class DetailMajor(LoginRequiredMixin, DetailView):
class CreateConfirmation(LoginRequiredMixin, CreateView):
"""Students on the same floor may flag one another.
This is our attempt at crowdsourced verification."""
model = Confirmation
fields = []
template_name = 'create_confirmation.html'
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment