models.py 8.07 KB
Newer Older
1
# standard library imports
2
from __future__ import absolute_import, print_function
3
import hashlib
4
from datetime import date
5
# core django imports
Jason D Yeomans's avatar
Jason D Yeomans committed
6
from django.db import models
7
from django.utils import timezone
8
from model_utils.models import TimeStampedModel
9
from django.contrib.auth.models import User
Daniel W Bond's avatar
Daniel W Bond committed
10
from django.core.urlresolvers import reverse
11
from django.utils.text import slugify
12 13
# third party imports
from autoslug import AutoSlugField
Daniel W Bond's avatar
Daniel W Bond committed
14
from randomslugfield import RandomSlugField
15
from multiselectfield import MultiSelectField
16 17
from allauth.socialaccount.models import SocialAccount
# imports from your apps
David Haynes's avatar
David Haynes committed
18
from housing.models import Room
19

Jason D Yeomans's avatar
Jason D Yeomans committed
20

21
class Major(TimeStampedModel):
Daniel W Bond's avatar
Daniel W Bond committed
22
    name = models.CharField(max_length=50)
23
    # I believe the longest is "Government and International Politics"
24

Daniel W Bond's avatar
Daniel W Bond committed
25 26
    slug = AutoSlugField(populate_from='name', unique=True)

Daniel W Bond's avatar
Daniel W Bond committed
27 28 29
    def first_letter(self):
        return self.name and self.name[0] or ''

Daniel W Bond's avatar
Daniel W Bond committed
30 31
    def __str__(self):
        return self.name
Daniel W Bond's avatar
Daniel W Bond committed
32

Daniel W Bond's avatar
Daniel W Bond committed
33 34 35
    def __unicode__(self):
        return unicode(self.name)

Daniel W Bond's avatar
Daniel W Bond committed
36
    def get_absolute_url(self):
37 38 39 40
        return reverse('detail_major', kwargs={
            'slug': self.slug,
            'major': slugify(self.name),
        })
Daniel W Bond's avatar
Daniel W Bond committed
41

Daniel W Bond's avatar
Daniel W Bond committed
42 43
    class Meta:
        ordering = ['name']
Daniel W Bond's avatar
Daniel W Bond committed
44

Daniel W Bond's avatar
Daniel W Bond committed
45

Daniel W Bond's avatar
Daniel W Bond committed
46 47
class StudentQuerySet(models.query.QuerySet):
    def floor(self):
Daniel W Bond's avatar
Daniel W Bond committed
48
        return self.filter(privacy='floor')
Daniel W Bond's avatar
Daniel W Bond committed
49 50

    def building(self):
Daniel W Bond's avatar
Daniel W Bond committed
51
        return self.filter(privacy='building')
Daniel W Bond's avatar
Daniel W Bond committed
52 53

    def students(self):
Daniel W Bond's avatar
Daniel W Bond committed
54
        return self.filter(privacy='students')
Daniel W Bond's avatar
Daniel W Bond committed
55

Daniel W Bond's avatar
Daniel W Bond committed
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    # when a student is not on a floor, but in a building
    def building_students(self):
        building = self.building()
        students = self.students()
        return list(building) + list(set(students) - set(building))

    # when a student is on a floor
    def floor_building_students(self):
        floor = self.floor()
        building = self.building()
        students = self.students()

        # using the function above results in UnboundLocalError excpetion
        building_students = list(building) + list(set(students) - set(building))

        return list(floor) + list(set(building_students) - set(floor))

Daniel W Bond's avatar
Daniel W Bond committed
73

Daniel W Bond's avatar
Daniel W Bond committed
74
class StudentManager(models.Manager):
Daniel W Bond's avatar
Daniel W Bond committed
75 76 77

    # this 'duplication' allows for queryset chaining

Daniel W Bond's avatar
Daniel W Bond committed
78
    def get_queryset(self):
Daniel W Bond's avatar
Daniel W Bond committed
79 80 81
        return StudentQuerySet(self.model, using=self._db)

    def floor(self):
Daniel W Bond's avatar
Daniel W Bond committed
82
        return self.get_queryset().floor()
Daniel W Bond's avatar
Daniel W Bond committed
83 84

    def building(self):
Daniel W Bond's avatar
Daniel W Bond committed
85
        return self.get_queryset().building()
Daniel W Bond's avatar
Daniel W Bond committed
86 87

    def students(self):
Daniel W Bond's avatar
Daniel W Bond committed
88
        return self.get_queryset().students()
Daniel W Bond's avatar
Daniel W Bond committed
89 90

    def building_students(self):
Daniel W Bond's avatar
Daniel W Bond committed
91
        return self.get_queryset().building_students()
Daniel W Bond's avatar
Daniel W Bond committed
92

Daniel W Bond's avatar
Daniel W Bond committed
93
    def floor_building_students(self):
Daniel W Bond's avatar
Daniel W Bond committed
94
        return self.get_queryset().floor_building_students()
Daniel W Bond's avatar
Daniel W Bond committed
95

Daniel W Bond's avatar
Daniel W Bond committed
96

97 98 99
class Student(TimeStampedModel):
    user = models.OneToOneField(User)
    # Django user includes a username, password, email, first name, and last name
Daniel W Bond's avatar
Daniel W Bond committed
100 101 102 103 104 105 106 107 108 109 110

    FLOOR = 'floor'
    BUILDING = 'building'
    STUDENTS = 'students'

    PRIVACY_CHOICES = (
        (FLOOR, 'My Floor'),
        (BUILDING, 'My Building'),
        (STUDENTS, 'All Students'),
    )

Daniel W Bond's avatar
Daniel W Bond committed
111 112 113
    FEMALE = 'female'
    MALE = 'male'
    TRANS = 'trans'
114 115
    INTERSEX = 'intersex'
    GENDERLESS = 'genderless'
Daniel W Bond's avatar
Daniel W Bond committed
116 117 118 119 120 121
    OTHER = 'other'

    GENDER_CHOICES = (
        (FEMALE, 'female'),
        (MALE, 'male'),
        (TRANS, 'trans'),
122 123
        (INTERSEX, 'intersex'),
        (GENDERLESS, 'genderless'),
Daniel W Bond's avatar
Daniel W Bond committed
124 125 126 127
        (OTHER, 'other'),
    )

    # selectmultiple in forms
128
    gender = MultiSelectField(max_length=25, choices=GENDER_CHOICES, blank=True)
129
    show_gender = models.BooleanField(default=False)
Daniel W Bond's avatar
Daniel W Bond committed
130

Daniel W Bond's avatar
Daniel W Bond committed
131 132
    privacy = models.CharField(max_length=100, choices=PRIVACY_CHOICES, default=FLOOR)

133
    room = models.ForeignKey(Room, null=True, blank=True)
134

135
    major = models.ForeignKey('Major', related_name='major', null=True, blank=True)
136

137
    times_changed_room = models.PositiveIntegerField(default=0)
138

139 140 141
    current_year = date.today().year
    graduating_year = models.IntegerField(default=current_year, blank=True)

Daniel W Bond's avatar
Daniel W Bond committed
142
    # from when first logged in through peoplefinder, stored for later
143 144
    original_major = models.ForeignKey('Major', related_name='original_major',
                                       null=True, blank=True)
145 146
    original_first_name = models.CharField(max_length=100, blank=True)
    original_last_name = models.CharField(max_length=100, blank=True)
Daniel W Bond's avatar
Daniel W Bond committed
147

148 149
    # social media accounts

150
    # welcome walkthrough completion
151 152 153 154
    completedName = models.BooleanField(default=False)
    completedPrivacy = models.BooleanField(default=False)
    completedMajor = models.BooleanField(default=False)
    completedSocial = models.BooleanField(default=False)
155

156 157
    slug = AutoSlugField(populate_from='user', unique=True)

Daniel W Bond's avatar
Daniel W Bond committed
158 159
    objects = StudentManager()

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    # this doesn't take into account superseniors or graduate students or negative values
    # hence private method
    def _get_class(self):
        time_to_graduate = self.graduating_year - self.current_year
        if time_to_graduate >= 4:
            return "freshman"
        elif time_to_graduate == 3:
            return "sophomore"
        elif time_to_graduate == 2:
            return "junior"
        elif time_to_graduate == 1:
            return "freshman"
        else:
            return "magic"

175
    def recent_changes(self):
176 177 178 179 180 181 182
        # part of TimeStampedModel
        now = timezone.now()
        created = self.created

        # could make this more formal with dateutil, but...
        days = (now - created).days

183 184
        # must be int-- floor function
        third_years = (days / (30 * 4)) + 1
185

186
        return (self.times_changed_room / third_years)
187

Daniel W Bond's avatar
Daniel W Bond committed
188
    def get_floor(self):
189 190 191 192 193
        try:
            floor = self.room.floor
            return floor
        except AttributeError:
            return None
Daniel W Bond's avatar
Daniel W Bond committed
194 195

    def get_building(self):
196 197 198 199 200
        try:
            building = self.room.floor.building
            return building
        except AttributeError:
            return None
Daniel W Bond's avatar
Daniel W Bond committed
201

Jason D Yeomans's avatar
Jason D Yeomans committed
202
    def profile_image_url(self):
203 204
        fb_uid = SocialAccount.objects.filter(user=self.user.id, provider='facebook')
        print("profile_image")
Jason D Yeomans's avatar
Jason D Yeomans committed
205

Daniel W Bond's avatar
Daniel W Bond committed
206
        if len(fb_uid) > 0:
207
            return "http://graph.facebook.com/{}/picture?width=175&height=175".format(fb_uid[0].uid)
Jason D Yeomans's avatar
Jason D Yeomans committed
208

209
        return "http://www.gravatar.com/avatar/{}?s=175".format(hashlib.md5(self.user.email).hexdigest())
Jason D Yeomans's avatar
Jason D Yeomans committed
210

Daniel W Bond's avatar
Daniel W Bond committed
211
    def get_absolute_url(self):
Daniel W Bond's avatar
Daniel W Bond committed
212
        return reverse('detail_student', kwargs={'slug': self.slug})
Daniel W Bond's avatar
Daniel W Bond committed
213

214 215 216
    def get_flag_count(self):
        my_flag_num = Confirmation.objects.filter(student=self, lives_there=False).count()
        return my_flag_num
217
    
218 219
    def get_first_name_or_uname(self):
        if not(self.user.get_short_name()):
220 221 222 223
            return self.user.get_username()
        else:
            return self.user.get_short_name()
    
224 225
    def get_last_name_or_uname(self):
        if not(self.user.last_name):
226 227 228 229
            return self.user.get_username()
        else:
            return self.user.last_name
    
230 231
    def get_full_name_or_uname(self):
        if not(self.user.get_full_name_or_uname()):
232 233
            return self.user.get_username()
        else:
234
            return self.user.get_full_name_or_uname()
235

Daniel W Bond's avatar
Daniel W Bond committed
236 237 238
    class Meta:
        ordering = ['user']

239 240
    def __str__(self):              # __unicode__ on Python 2
        return self.user.username
Daniel W Bond's avatar
Daniel W Bond committed
241

Daniel W Bond's avatar
Daniel W Bond committed
242 243
    def __unicode__(self):
        return unicode(self.user.username)
244
    
245
    # def save(self, *args, **kwargs):
Daniel W Bond's avatar
Daniel W Bond committed
246 247 248 249 250
        #print('we be savin\'!')
        #from django.db.models.signals import pre_save, post_save
        #for signal in [pre_save, post_save]:
            #print(signal, signal.receivers)
        #super(Student, self).save(*args, **kwargs)
251

Daniel W Bond's avatar
Daniel W Bond committed
252

Daniel W Bond's avatar
Daniel W Bond committed
253 254 255 256 257 258
class Confirmation(TimeStampedModel):

    confirmer = models.ForeignKey(Student, related_name='confirmer_set')
    student = models.ForeignKey(Student, related_name='student_set')

    lives_there = models.BooleanField(default=False)
Daniel W Bond's avatar
Daniel W Bond committed
259
    # is RA? -- for later
Daniel W Bond's avatar
Daniel W Bond committed
260 261 262 263

    slug = RandomSlugField(length=6)

    def __unicode__(self):
Daniel W Bond's avatar
Daniel W Bond committed
264 265 266 267
        if self.lives_there:  # implicitly is True
            return "%s Confirmed %s" % (self.confirmer.user.username, self.student.user.username)
        else:  # implicitly is False
            return "%s Flagged %s" % (self.confirmer.user.username, self.student.user.username)