We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Committee positions in dashboard looks ugly as shit


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `apps/authentication/models.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 import datetime
4 import socket
5 import urllib
6 import hashlib
7 
8 from django.conf import settings
9 from django.contrib.auth.models import AbstractUser
10 from django.db import models
11 from django.utils.translation import ugettext as _
12 from django.utils import timezone
13 from django.utils.html import strip_tags
14 
15 import watson
16 
17 
18 # If this list is changed, remember to check that the year property on
19 # OnlineUser is still correct!
20 FIELD_OF_STUDY_CHOICES = [
21     (0, _(u'Gjest')),
22     (1, _(u'Bachelor i Informatikk (BIT)')),
23     # master degrees take up the interval [10,30]
24     (10, _(u'Software (SW)')),
25     (11, _(u'Informasjonsforvaltning (DIF)')),
26     (12, _(u'Komplekse Datasystemer (KDS)')),
27     (13, _(u'Spillteknologi (SPT)')),
28     (14, _(u'Intelligente Systemer (IRS)')),
29     (15, _(u'Helseinformatikk (MSMEDTEK)')),
30     (30, _(u'Annen mastergrad')),
31     (80, _(u'PhD')),
32     (90, _(u'International')),
33     (100, _(u'Annet Onlinemedlem')),
34 ]
35 
36 GENDER_CHOICES = [
37     ("male", _(u"mann")),
38     ("female", _(u"kvinne")),
39 ]
40 
41 COMMITTEES = [
42     ('hs', _(u'Hovedstyret')),
43     ('arrkom', _(u'Arrangementskomiteen')),
44     ('bankom', _(u'Bank- og økonomikomiteen')),
45     ('bedkom', _(u'Bedriftskomiteen')),
46     ('dotkom', _(u'Drifts- og utviklingskomiteen')),
47     ('ekskom', _(u'Ekskursjonskomiteen')),
48     ('fagkom', _(u'Fag- og kurskomiteen')),
49     ('jubkom', _(u'Jubileumskomiteen')),
50     ('pangkom', _(u'Pensjonistkomiteen')),
51     ('prokom', _(u'Profil-og aviskomiteen')),
52     ('trikom', _(u'Trivselskomiteen')),
53     ('velkom', _(u'Velkomstkomiteen')),
54 ]
55 
56 POSITIONS = [
57     ('medlem', _(u'Medlem')),
58     ('leder', _(u'Leder')),
59     ('nestleder', _(u'Nestleder')),
60     ('okonomiansvarlig', _(u'Økonomiansvarlig')),
61 ]
62 
63 class OnlineUser(AbstractUser):
64 
65     IMAGE_FOLDER = "images/profiles"
66     IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.gif', '.png']
67     
68     # Online related fields
69     field_of_study = models.SmallIntegerField(_(u"studieretning"), choices=FIELD_OF_STUDY_CHOICES, default=0)
70     started_date = models.DateField(_(u"startet studie"), default=timezone.now().date())
71     compiled = models.BooleanField(_(u"kompilert"), default=False)
72 
73     # Email
74     infomail = models.BooleanField(_(u"vil ha infomail"), default=True)
75 
76     # Address
77     phone_number = models.CharField(_(u"telefonnummer"), max_length=20, blank=True, null=True)
78     address = models.CharField(_(u"adresse"), max_length=30, blank=True, null=True)
79     zip_code = models.CharField(_(u"postnummer"), max_length=4, blank=True, null=True)
80 
81     # Other
82     allergies = models.TextField(_(u"allergier"), blank=True, null=True)
83     mark_rules = models.BooleanField(_(u"godtatt prikkeregler"), default=False)
84     rfid = models.CharField(_(u"RFID"), max_length=50, blank=True, null=True)
85     nickname = models.CharField(_(u"nickname"), max_length=50, blank=True, null=True)
86     website = models.URLField(_(u"hjemmeside"), blank=True, null=True)
87     gender = models.CharField(_(u"kjønn"), max_length=10, choices=GENDER_CHOICES, default="male")
88 
89     # NTNU credentials
90     ntnu_username = models.CharField(_(u"NTNU-brukernavn"), max_length=10, blank=True, null=True, unique=True)
91 
92     # TODO checkbox for forwarding of @online.ntnu.no mail
93 
94     @property
95     def is_member(self):
96         """
97         Returns true if the User object is associated with Online.
98         """
99         if self.ntnu_username:
100             if AllowedUsername.objects.filter(username=self.ntnu_username.lower()).filter(expiration_date__gte=timezone.now()).count() > 0:
101                 return True
102         return False
103 
104     def get_full_name(self):
105         """
106         Returns the first_name plus the last_name, with a space in between.
107         """
108         full_name = u'%s %s' % (self.first_name, self.last_name)
109         return full_name.strip()
110 
111     def get_email(self):
112         email = self.get_emails().filter(primary = True)
113         if email:
114             return email[0]
115         return None
116 
117     def get_emails(self):
118         return Email.objects.all().filter(user = self)
119 
120     def in_group(self, group_name):
121         return reduce(lambda x,y: x or y.name == group_name, self.groups.all(), False)
122 
123     @property
124     def year(self):
125         today = timezone.now().date()
126         started = self.started_date
127 
128         # We say that a year is 360 days incase we are a bit slower to
129         # add users one year.
130         year = ((today - started).days / 360) + 1
131 
132         if self.field_of_study == 0 or self.field_of_study == 100:  # others
133             return 0
134         # dont return a bachelor student as 4th or 5th grade
135         elif self.field_of_study == 1:  # bachelor
136             if year > 3:
137                 return 3
138             return year
139         elif 10 <= self.field_of_study <= 30:  # 10-29 is considered master
140             if year >= 2:
141                 return 5
142             return 4
143         elif self.field_of_study == 80:  # phd
144             return year + 5
145         elif self.field_of_study == 90:  # international
146             if year == 1:
147                 return 1
148             return 4
149         # If user's field of study is not matched by any of these tests, return -1
150         else:
151             return -1
152 
153     @models.permalink
154     def get_absolute_url(self):
155         return ('profiles_view', None, {'username': self.username})
156 
157     def __unicode__(self):
158         return self.get_full_name()
159 
160     def save(self, *args, **kwargs):
161         if self.ntnu_username == "":
162             self.ntnu_username = None
163         super(OnlineUser, self).save(*args, **kwargs)
164 
165     def serializable_object(self):
166         if self.privacy.expose_phone_number:
167             phone = self.phone_number
168         else:
169             phone = "Ikke tilgjengelig"
170 
171         return {
172             'id': self.id,
173             'phone': strip_tags(phone),
174             'username': strip_tags(self.username),
175             'value': strip_tags(self.get_full_name()),  # typeahead
176             'name': strip_tags(self.get_full_name()),
177             'image': self.get_image_url(),
178         }
179 
180     def get_image_url(self, size=50):
181         default = "%s%s_%s.png" % (settings.BASE_URL,
182                                    settings.DEFAULT_PROFILE_PICTURE_PREFIX, self.gender)
183 
184         gravatar_url = "https://www.gravatar.com/avatar/" + hashlib.md5(self.email).hexdigest() + "?"
185         gravatar_url += urllib.urlencode({'d': default, 's':str(size)})
186         return gravatar_url
187 
188     class Meta:
189         ordering = ['first_name', 'last_name']
190         verbose_name = _(u"brukerprofil")
191         verbose_name_plural = _(u"brukerprofiler")
192 
193 
194 class Email(models.Model):
195     user = models.ForeignKey(OnlineUser, related_name="email_user")
196     email = models.EmailField(_(u"epostadresse"), unique=True)
197     primary = models.BooleanField(_(u"primær"), default=False)
198     verified = models.BooleanField(_(u"verifisert"), default=False, editable=False)
199 
200     def save(self, *args, **kwargs):
201         primary_email = self.user.get_email()
202         if not primary_email:
203             self.primary = True
204         elif primary_email.email != self.email:
205             self.primary = False
206         self.email = self.email.lower()
207         if self.primary:
208             self.user.email = self.email
209             self.user.save()
210         super(Email, self).save(*args, **kwargs)
211 
212     def __unicode__(self):
213         return self.email
214 
215     class Meta:
216         verbose_name = _(u"epostadresse")
217         verbose_name_plural = _(u"epostadresser")
218 
219 
220 class RegisterToken(models.Model):
221     user = models.ForeignKey(OnlineUser, related_name="register_user")
222     email = models.EmailField(_(u"epost"), max_length=254)
223     token = models.CharField(_(u"token"), max_length=32)
224     created = models.DateTimeField(_(u"opprettet dato"), editable=False, auto_now_add=True)
225 
226     @property
227     def is_valid(self):
228         valid_period = datetime.timedelta(days=1)
229         now = timezone.now()
230         return now < self.created + valid_period 
231 
232 
233 class AllowedUsername(models.Model):
234     """
235     Holds usernames that are considered valid members of Online and the time they expire.
236     """
237     username = models.CharField(_(u"NTNU-brukernavn"), max_length=10, unique=True)
238     registered = models.DateField(_(u"registrert"))
239     note = models.CharField(_(u"notat"), max_length=100)
240     description = models.TextField(_(u"beskrivelse"), blank=True, null=True)
241     expiration_date = models.DateField(_(u"utløpsdato"))
242 
243     @property
244     def is_active(self):
245         return timezone.now().date() < self.expiration_date
246 
247     def save(self, *args, **kwargs):
248         self.username = self.username.lower()
249         super(AllowedUsername, self).save(*args, **kwargs)
250 
251     def __unicode__(self):
252         return self.username
253 
254     class Meta:
255         verbose_name = _(u"medlem")
256         verbose_name_plural = _(u"medlemsregister")
257         ordering = (u"username",)
258 
259 
260 class Position(models.Model):
261     """
262     Contains a users position in the organization from a given year
263     """
264     period     = models.CharField(_(u'periode'), max_length=9, default="2013-2014", blank=False)
265     committee  = models.CharField(_(u"komite"), max_length=10, choices=COMMITTEES, default="hs")
266     position   = models.CharField(_(u"stilling"), max_length=10, choices=POSITIONS, default="medlem")
267     user       = models.ForeignKey(OnlineUser, related_name='positions', blank=False)
268 
269     @property
270     def print_string(self):
271         return '%s: %s(%s)' % (self.period, self.committee, self.position)
272 
273     def __unicode__(self):
274         return self.print_string
275 
276     class Meta:
277         verbose_name = _(u'posisjon')
278         verbose_name_plural = _(u'posisjoner')
279         ordering = (u'user',)
280 
281 # Static method for resetting all users mark rules accepted field to false due to changes in mark rules
282 def reset_marks_acceptance():
283     for user in OnlineUser.objects.all():
284         user.mark_rules = False
285         user.save()
286 
287 # Register OnlineUser in watson index for searching
288 watson.register(OnlineUser)
289
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/apps/authentication/models.py b/apps/authentication/models.py
--- a/apps/authentication/models.py
+++ b/apps/authentication/models.py
@@ -276,7 +276,7 @@
     class Meta:
         verbose_name = _(u'posisjon')
         verbose_name_plural = _(u'posisjoner')
-        ordering = (u'user',)
+        ordering = (u'user', u'period', )
 
 # Static method for resetting all users mark rules accepted field to false due to changes in mark rules
 def reset_marks_acceptance():

{"golden_diff": "diff --git a/apps/authentication/models.py b/apps/authentication/models.py\n--- a/apps/authentication/models.py\n+++ b/apps/authentication/models.py\n@@ -276,7 +276,7 @@\n     class Meta:\n         verbose_name = _(u'posisjon')\n         verbose_name_plural = _(u'posisjoner')\n-        ordering = (u'user',)\n+        ordering = (u'user', u'period', )\n \n # Static method for resetting all users mark rules accepted field to false due to changes in mark rules\n def reset_marks_acceptance():\n", "issue": "Committee positions in dashboard looks ugly as shit\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\nimport datetime\nimport socket\nimport urllib\nimport hashlib\n\nfrom django.conf import settings\nfrom django.contrib.auth.models import AbstractUser\nfrom django.db import models\nfrom django.utils.translation import ugettext as _\nfrom django.utils import timezone\nfrom django.utils.html import strip_tags\n\nimport watson\n\n\n# If this list is changed, remember to check that the year property on\n# OnlineUser is still correct!\nFIELD_OF_STUDY_CHOICES = [\n    (0, _(u'Gjest')),\n    (1, _(u'Bachelor i Informatikk (BIT)')),\n    # master degrees take up the interval [10,30]\n    (10, _(u'Software (SW)')),\n    (11, _(u'Informasjonsforvaltning (DIF)')),\n    (12, _(u'Komplekse Datasystemer (KDS)')),\n    (13, _(u'Spillteknologi (SPT)')),\n    (14, _(u'Intelligente Systemer (IRS)')),\n    (15, _(u'Helseinformatikk (MSMEDTEK)')),\n    (30, _(u'Annen mastergrad')),\n    (80, _(u'PhD')),\n    (90, _(u'International')),\n    (100, _(u'Annet Onlinemedlem')),\n]\n\nGENDER_CHOICES = [\n    (\"male\", _(u\"mann\")),\n    (\"female\", _(u\"kvinne\")),\n]\n\nCOMMITTEES = [\n    ('hs', _(u'Hovedstyret')),\n    ('arrkom', _(u'Arrangementskomiteen')),\n    ('bankom', _(u'Bank- og \u00f8konomikomiteen')),\n    ('bedkom', _(u'Bedriftskomiteen')),\n    ('dotkom', _(u'Drifts- og utviklingskomiteen')),\n    ('ekskom', _(u'Ekskursjonskomiteen')),\n    ('fagkom', _(u'Fag- og kurskomiteen')),\n    ('jubkom', _(u'Jubileumskomiteen')),\n    ('pangkom', _(u'Pensjonistkomiteen')),\n    ('prokom', _(u'Profil-og aviskomiteen')),\n    ('trikom', _(u'Trivselskomiteen')),\n    ('velkom', _(u'Velkomstkomiteen')),\n]\n\nPOSITIONS = [\n    ('medlem', _(u'Medlem')),\n    ('leder', _(u'Leder')),\n    ('nestleder', _(u'Nestleder')),\n    ('okonomiansvarlig', _(u'\u00d8konomiansvarlig')),\n]\n\nclass OnlineUser(AbstractUser):\n\n    IMAGE_FOLDER = \"images/profiles\"\n    IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.gif', '.png']\n    \n    # Online related fields\n    field_of_study = models.SmallIntegerField(_(u\"studieretning\"), choices=FIELD_OF_STUDY_CHOICES, default=0)\n    started_date = models.DateField(_(u\"startet studie\"), default=timezone.now().date())\n    compiled = models.BooleanField(_(u\"kompilert\"), default=False)\n\n    # Email\n    infomail = models.BooleanField(_(u\"vil ha infomail\"), default=True)\n\n    # Address\n    phone_number = models.CharField(_(u\"telefonnummer\"), max_length=20, blank=True, null=True)\n    address = models.CharField(_(u\"adresse\"), max_length=30, blank=True, null=True)\n    zip_code = models.CharField(_(u\"postnummer\"), max_length=4, blank=True, null=True)\n\n    # Other\n    allergies = models.TextField(_(u\"allergier\"), blank=True, null=True)\n    mark_rules = models.BooleanField(_(u\"godtatt prikkeregler\"), default=False)\n    rfid = models.CharField(_(u\"RFID\"), max_length=50, blank=True, null=True)\n    nickname = models.CharField(_(u\"nickname\"), max_length=50, blank=True, null=True)\n    website = models.URLField(_(u\"hjemmeside\"), blank=True, null=True)\n    gender = models.CharField(_(u\"kj\u00f8nn\"), max_length=10, choices=GENDER_CHOICES, default=\"male\")\n\n    # NTNU credentials\n    ntnu_username = models.CharField(_(u\"NTNU-brukernavn\"), max_length=10, blank=True, null=True, unique=True)\n\n    # TODO checkbox for forwarding of @online.ntnu.no mail\n\n    @property\n    def is_member(self):\n        \"\"\"\n        Returns true if the User object is associated with Online.\n        \"\"\"\n        if self.ntnu_username:\n            if AllowedUsername.objects.filter(username=self.ntnu_username.lower()).filter(expiration_date__gte=timezone.now()).count() > 0:\n                return True\n        return False\n\n    def get_full_name(self):\n        \"\"\"\n        Returns the first_name plus the last_name, with a space in between.\n        \"\"\"\n        full_name = u'%s %s' % (self.first_name, self.last_name)\n        return full_name.strip()\n\n    def get_email(self):\n        email = self.get_emails().filter(primary = True)\n        if email:\n            return email[0]\n        return None\n\n    def get_emails(self):\n        return Email.objects.all().filter(user = self)\n\n    def in_group(self, group_name):\n        return reduce(lambda x,y: x or y.name == group_name, self.groups.all(), False)\n\n    @property\n    def year(self):\n        today = timezone.now().date()\n        started = self.started_date\n\n        # We say that a year is 360 days incase we are a bit slower to\n        # add users one year.\n        year = ((today - started).days / 360) + 1\n\n        if self.field_of_study == 0 or self.field_of_study == 100:  # others\n            return 0\n        # dont return a bachelor student as 4th or 5th grade\n        elif self.field_of_study == 1:  # bachelor\n            if year > 3:\n                return 3\n            return year\n        elif 10 <= self.field_of_study <= 30:  # 10-29 is considered master\n            if year >= 2:\n                return 5\n            return 4\n        elif self.field_of_study == 80:  # phd\n            return year + 5\n        elif self.field_of_study == 90:  # international\n            if year == 1:\n                return 1\n            return 4\n        # If user's field of study is not matched by any of these tests, return -1\n        else:\n            return -1\n\n    @models.permalink\n    def get_absolute_url(self):\n        return ('profiles_view', None, {'username': self.username})\n\n    def __unicode__(self):\n        return self.get_full_name()\n\n    def save(self, *args, **kwargs):\n        if self.ntnu_username == \"\":\n            self.ntnu_username = None\n        super(OnlineUser, self).save(*args, **kwargs)\n\n    def serializable_object(self):\n        if self.privacy.expose_phone_number:\n            phone = self.phone_number\n        else:\n            phone = \"Ikke tilgjengelig\"\n\n        return {\n            'id': self.id,\n            'phone': strip_tags(phone),\n            'username': strip_tags(self.username),\n            'value': strip_tags(self.get_full_name()),  # typeahead\n            'name': strip_tags(self.get_full_name()),\n            'image': self.get_image_url(),\n        }\n\n    def get_image_url(self, size=50):\n        default = \"%s%s_%s.png\" % (settings.BASE_URL,\n                                   settings.DEFAULT_PROFILE_PICTURE_PREFIX, self.gender)\n\n        gravatar_url = \"https://www.gravatar.com/avatar/\" + hashlib.md5(self.email).hexdigest() + \"?\"\n        gravatar_url += urllib.urlencode({'d': default, 's':str(size)})\n        return gravatar_url\n\n    class Meta:\n        ordering = ['first_name', 'last_name']\n        verbose_name = _(u\"brukerprofil\")\n        verbose_name_plural = _(u\"brukerprofiler\")\n\n\nclass Email(models.Model):\n    user = models.ForeignKey(OnlineUser, related_name=\"email_user\")\n    email = models.EmailField(_(u\"epostadresse\"), unique=True)\n    primary = models.BooleanField(_(u\"prim\u00e6r\"), default=False)\n    verified = models.BooleanField(_(u\"verifisert\"), default=False, editable=False)\n\n    def save(self, *args, **kwargs):\n        primary_email = self.user.get_email()\n        if not primary_email:\n            self.primary = True\n        elif primary_email.email != self.email:\n            self.primary = False\n        self.email = self.email.lower()\n        if self.primary:\n            self.user.email = self.email\n            self.user.save()\n        super(Email, self).save(*args, **kwargs)\n\n    def __unicode__(self):\n        return self.email\n\n    class Meta:\n        verbose_name = _(u\"epostadresse\")\n        verbose_name_plural = _(u\"epostadresser\")\n\n\nclass RegisterToken(models.Model):\n    user = models.ForeignKey(OnlineUser, related_name=\"register_user\")\n    email = models.EmailField(_(u\"epost\"), max_length=254)\n    token = models.CharField(_(u\"token\"), max_length=32)\n    created = models.DateTimeField(_(u\"opprettet dato\"), editable=False, auto_now_add=True)\n\n    @property\n    def is_valid(self):\n        valid_period = datetime.timedelta(days=1)\n        now = timezone.now()\n        return now < self.created + valid_period \n\n\nclass AllowedUsername(models.Model):\n    \"\"\"\n    Holds usernames that are considered valid members of Online and the time they expire.\n    \"\"\"\n    username = models.CharField(_(u\"NTNU-brukernavn\"), max_length=10, unique=True)\n    registered = models.DateField(_(u\"registrert\"))\n    note = models.CharField(_(u\"notat\"), max_length=100)\n    description = models.TextField(_(u\"beskrivelse\"), blank=True, null=True)\n    expiration_date = models.DateField(_(u\"utl\u00f8psdato\"))\n\n    @property\n    def is_active(self):\n        return timezone.now().date() < self.expiration_date\n\n    def save(self, *args, **kwargs):\n        self.username = self.username.lower()\n        super(AllowedUsername, self).save(*args, **kwargs)\n\n    def __unicode__(self):\n        return self.username\n\n    class Meta:\n        verbose_name = _(u\"medlem\")\n        verbose_name_plural = _(u\"medlemsregister\")\n        ordering = (u\"username\",)\n\n\nclass Position(models.Model):\n    \"\"\"\n    Contains a users position in the organization from a given year\n    \"\"\"\n    period     = models.CharField(_(u'periode'), max_length=9, default=\"2013-2014\", blank=False)\n    committee  = models.CharField(_(u\"komite\"), max_length=10, choices=COMMITTEES, default=\"hs\")\n    position   = models.CharField(_(u\"stilling\"), max_length=10, choices=POSITIONS, default=\"medlem\")\n    user       = models.ForeignKey(OnlineUser, related_name='positions', blank=False)\n\n    @property\n    def print_string(self):\n        return '%s: %s(%s)' % (self.period, self.committee, self.position)\n\n    def __unicode__(self):\n        return self.print_string\n\n    class Meta:\n        verbose_name = _(u'posisjon')\n        verbose_name_plural = _(u'posisjoner')\n        ordering = (u'user',)\n\n# Static method for resetting all users mark rules accepted field to false due to changes in mark rules\ndef reset_marks_acceptance():\n    for user in OnlineUser.objects.all():\n        user.mark_rules = False\n        user.save()\n\n# Register OnlineUser in watson index for searching\nwatson.register(OnlineUser)\n", "path": "apps/authentication/models.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\nimport datetime\nimport socket\nimport urllib\nimport hashlib\n\nfrom django.conf import settings\nfrom django.contrib.auth.models import AbstractUser\nfrom django.db import models\nfrom django.utils.translation import ugettext as _\nfrom django.utils import timezone\nfrom django.utils.html import strip_tags\n\nimport watson\n\n\n# If this list is changed, remember to check that the year property on\n# OnlineUser is still correct!\nFIELD_OF_STUDY_CHOICES = [\n    (0, _(u'Gjest')),\n    (1, _(u'Bachelor i Informatikk (BIT)')),\n    # master degrees take up the interval [10,30]\n    (10, _(u'Software (SW)')),\n    (11, _(u'Informasjonsforvaltning (DIF)')),\n    (12, _(u'Komplekse Datasystemer (KDS)')),\n    (13, _(u'Spillteknologi (SPT)')),\n    (14, _(u'Intelligente Systemer (IRS)')),\n    (15, _(u'Helseinformatikk (MSMEDTEK)')),\n    (30, _(u'Annen mastergrad')),\n    (80, _(u'PhD')),\n    (90, _(u'International')),\n    (100, _(u'Annet Onlinemedlem')),\n]\n\nGENDER_CHOICES = [\n    (\"male\", _(u\"mann\")),\n    (\"female\", _(u\"kvinne\")),\n]\n\nCOMMITTEES = [\n    ('hs', _(u'Hovedstyret')),\n    ('arrkom', _(u'Arrangementskomiteen')),\n    ('bankom', _(u'Bank- og \u00f8konomikomiteen')),\n    ('bedkom', _(u'Bedriftskomiteen')),\n    ('dotkom', _(u'Drifts- og utviklingskomiteen')),\n    ('ekskom', _(u'Ekskursjonskomiteen')),\n    ('fagkom', _(u'Fag- og kurskomiteen')),\n    ('jubkom', _(u'Jubileumskomiteen')),\n    ('pangkom', _(u'Pensjonistkomiteen')),\n    ('prokom', _(u'Profil-og aviskomiteen')),\n    ('trikom', _(u'Trivselskomiteen')),\n    ('velkom', _(u'Velkomstkomiteen')),\n]\n\nPOSITIONS = [\n    ('medlem', _(u'Medlem')),\n    ('leder', _(u'Leder')),\n    ('nestleder', _(u'Nestleder')),\n    ('okonomiansvarlig', _(u'\u00d8konomiansvarlig')),\n]\n\nclass OnlineUser(AbstractUser):\n\n    IMAGE_FOLDER = \"images/profiles\"\n    IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.gif', '.png']\n    \n    # Online related fields\n    field_of_study = models.SmallIntegerField(_(u\"studieretning\"), choices=FIELD_OF_STUDY_CHOICES, default=0)\n    started_date = models.DateField(_(u\"startet studie\"), default=timezone.now().date())\n    compiled = models.BooleanField(_(u\"kompilert\"), default=False)\n\n    # Email\n    infomail = models.BooleanField(_(u\"vil ha infomail\"), default=True)\n\n    # Address\n    phone_number = models.CharField(_(u\"telefonnummer\"), max_length=20, blank=True, null=True)\n    address = models.CharField(_(u\"adresse\"), max_length=30, blank=True, null=True)\n    zip_code = models.CharField(_(u\"postnummer\"), max_length=4, blank=True, null=True)\n\n    # Other\n    allergies = models.TextField(_(u\"allergier\"), blank=True, null=True)\n    mark_rules = models.BooleanField(_(u\"godtatt prikkeregler\"), default=False)\n    rfid = models.CharField(_(u\"RFID\"), max_length=50, blank=True, null=True)\n    nickname = models.CharField(_(u\"nickname\"), max_length=50, blank=True, null=True)\n    website = models.URLField(_(u\"hjemmeside\"), blank=True, null=True)\n    gender = models.CharField(_(u\"kj\u00f8nn\"), max_length=10, choices=GENDER_CHOICES, default=\"male\")\n\n    # NTNU credentials\n    ntnu_username = models.CharField(_(u\"NTNU-brukernavn\"), max_length=10, blank=True, null=True, unique=True)\n\n    # TODO checkbox for forwarding of @online.ntnu.no mail\n\n    @property\n    def is_member(self):\n        \"\"\"\n        Returns true if the User object is associated with Online.\n        \"\"\"\n        if self.ntnu_username:\n            if AllowedUsername.objects.filter(username=self.ntnu_username.lower()).filter(expiration_date__gte=timezone.now()).count() > 0:\n                return True\n        return False\n\n    def get_full_name(self):\n        \"\"\"\n        Returns the first_name plus the last_name, with a space in between.\n        \"\"\"\n        full_name = u'%s %s' % (self.first_name, self.last_name)\n        return full_name.strip()\n\n    def get_email(self):\n        email = self.get_emails().filter(primary = True)\n        if email:\n            return email[0]\n        return None\n\n    def get_emails(self):\n        return Email.objects.all().filter(user = self)\n\n    def in_group(self, group_name):\n        return reduce(lambda x,y: x or y.name == group_name, self.groups.all(), False)\n\n    @property\n    def year(self):\n        today = timezone.now().date()\n        started = self.started_date\n\n        # We say that a year is 360 days incase we are a bit slower to\n        # add users one year.\n        year = ((today - started).days / 360) + 1\n\n        if self.field_of_study == 0 or self.field_of_study == 100:  # others\n            return 0\n        # dont return a bachelor student as 4th or 5th grade\n        elif self.field_of_study == 1:  # bachelor\n            if year > 3:\n                return 3\n            return year\n        elif 10 <= self.field_of_study <= 30:  # 10-29 is considered master\n            if year >= 2:\n                return 5\n            return 4\n        elif self.field_of_study == 80:  # phd\n            return year + 5\n        elif self.field_of_study == 90:  # international\n            if year == 1:\n                return 1\n            return 4\n        # If user's field of study is not matched by any of these tests, return -1\n        else:\n            return -1\n\n    @models.permalink\n    def get_absolute_url(self):\n        return ('profiles_view', None, {'username': self.username})\n\n    def __unicode__(self):\n        return self.get_full_name()\n\n    def save(self, *args, **kwargs):\n        if self.ntnu_username == \"\":\n            self.ntnu_username = None\n        super(OnlineUser, self).save(*args, **kwargs)\n\n    def serializable_object(self):\n        if self.privacy.expose_phone_number:\n            phone = self.phone_number\n        else:\n            phone = \"Ikke tilgjengelig\"\n\n        return {\n            'id': self.id,\n            'phone': strip_tags(phone),\n            'username': strip_tags(self.username),\n            'value': strip_tags(self.get_full_name()),  # typeahead\n            'name': strip_tags(self.get_full_name()),\n            'image': self.get_image_url(),\n        }\n\n    def get_image_url(self, size=50):\n        default = \"%s%s_%s.png\" % (settings.BASE_URL,\n                                   settings.DEFAULT_PROFILE_PICTURE_PREFIX, self.gender)\n\n        gravatar_url = \"https://www.gravatar.com/avatar/\" + hashlib.md5(self.email).hexdigest() + \"?\"\n        gravatar_url += urllib.urlencode({'d': default, 's':str(size)})\n        return gravatar_url\n\n    class Meta:\n        ordering = ['first_name', 'last_name']\n        verbose_name = _(u\"brukerprofil\")\n        verbose_name_plural = _(u\"brukerprofiler\")\n\n\nclass Email(models.Model):\n    user = models.ForeignKey(OnlineUser, related_name=\"email_user\")\n    email = models.EmailField(_(u\"epostadresse\"), unique=True)\n    primary = models.BooleanField(_(u\"prim\u00e6r\"), default=False)\n    verified = models.BooleanField(_(u\"verifisert\"), default=False, editable=False)\n\n    def save(self, *args, **kwargs):\n        primary_email = self.user.get_email()\n        if not primary_email:\n            self.primary = True\n        elif primary_email.email != self.email:\n            self.primary = False\n        self.email = self.email.lower()\n        if self.primary:\n            self.user.email = self.email\n            self.user.save()\n        super(Email, self).save(*args, **kwargs)\n\n    def __unicode__(self):\n        return self.email\n\n    class Meta:\n        verbose_name = _(u\"epostadresse\")\n        verbose_name_plural = _(u\"epostadresser\")\n\n\nclass RegisterToken(models.Model):\n    user = models.ForeignKey(OnlineUser, related_name=\"register_user\")\n    email = models.EmailField(_(u\"epost\"), max_length=254)\n    token = models.CharField(_(u\"token\"), max_length=32)\n    created = models.DateTimeField(_(u\"opprettet dato\"), editable=False, auto_now_add=True)\n\n    @property\n    def is_valid(self):\n        valid_period = datetime.timedelta(days=1)\n        now = timezone.now()\n        return now < self.created + valid_period \n\n\nclass AllowedUsername(models.Model):\n    \"\"\"\n    Holds usernames that are considered valid members of Online and the time they expire.\n    \"\"\"\n    username = models.CharField(_(u\"NTNU-brukernavn\"), max_length=10, unique=True)\n    registered = models.DateField(_(u\"registrert\"))\n    note = models.CharField(_(u\"notat\"), max_length=100)\n    description = models.TextField(_(u\"beskrivelse\"), blank=True, null=True)\n    expiration_date = models.DateField(_(u\"utl\u00f8psdato\"))\n\n    @property\n    def is_active(self):\n        return timezone.now().date() < self.expiration_date\n\n    def save(self, *args, **kwargs):\n        self.username = self.username.lower()\n        super(AllowedUsername, self).save(*args, **kwargs)\n\n    def __unicode__(self):\n        return self.username\n\n    class Meta:\n        verbose_name = _(u\"medlem\")\n        verbose_name_plural = _(u\"medlemsregister\")\n        ordering = (u\"username\",)\n\n\nclass Position(models.Model):\n    \"\"\"\n    Contains a users position in the organization from a given year\n    \"\"\"\n    period     = models.CharField(_(u'periode'), max_length=9, default=\"2013-2014\", blank=False)\n    committee  = models.CharField(_(u\"komite\"), max_length=10, choices=COMMITTEES, default=\"hs\")\n    position   = models.CharField(_(u\"stilling\"), max_length=10, choices=POSITIONS, default=\"medlem\")\n    user       = models.ForeignKey(OnlineUser, related_name='positions', blank=False)\n\n    @property\n    def print_string(self):\n        return '%s: %s(%s)' % (self.period, self.committee, self.position)\n\n    def __unicode__(self):\n        return self.print_string\n\n    class Meta:\n        verbose_name = _(u'posisjon')\n        verbose_name_plural = _(u'posisjoner')\n        ordering = (u'user', u'period', )\n\n# Static method for resetting all users mark rules accepted field to false due to changes in mark rules\ndef reset_marks_acceptance():\n    for user in OnlineUser.objects.all():\n        user.mark_rules = False\n        user.save()\n\n# Register OnlineUser in watson index for searching\nwatson.register(OnlineUser)\n", "path": "apps/authentication/models.py"}]}