Points for email address confirm, fix little bug
[oweals/karmaworld.git] / karmaworld / apps / users / models.py
1 #!/usr/bin/env python
2 # -*- coding:utf8 -*-
3 # Copyright (C) 2013  FinalsClub Foundation
4 import logging
5 import datetime
6 from allauth.account.signals import email_confirmed, email_added
7 from django.contrib.auth.models import User
8 from django.db.models import Sum
9 from django.db.models.signals import post_save
10 from django.dispatch import receiver
11 from django.db import models, DatabaseError
12 from django.middleware.transaction import transaction
13 from karmaworld.apps.courses.models import School
14
15 logger = logging.getLogger(__name__)
16
17
18 class UserProfile(models.Model):
19     user      = models.OneToOneField(User)
20
21     school    = models.ForeignKey(School, blank=True, null=True)
22
23     def get_points(self):
24         sum = 0
25         for cls in ALL_KARMA_EVENT_CLASSES:
26             points = cls.objects.filter(user=self.user).aggregate(Sum('points'))['points__sum']
27             if points:
28                 sum += points
29
30         return sum
31
32     NO_BADGE = 0
33     PROSPECT = 1
34     BEGINNER = 2
35     TRAINEE = 3
36     APPRENTICE = 4
37     SCHOLAR = 5
38
39     BADGES = (
40         PROSPECT,
41         BEGINNER,
42         TRAINEE,
43         APPRENTICE,
44         SCHOLAR
45     )
46
47     BADGE_NAMES = {
48         PROSPECT: 'Prospect',
49         BEGINNER: 'Beginner',
50         TRAINEE: 'Trainee',
51         APPRENTICE: 'Apprentice',
52         SCHOLAR: 'Scholar'
53     }
54
55     BADGE_THRESHOLDS = {
56         PROSPECT: 10,
57         BEGINNER: 100,
58         TRAINEE: 200,
59         APPRENTICE: 500,
60         SCHOLAR: 1000
61     }
62
63     def get_badge(self):
64         points = self.get_points()
65         highest_badge = self.NO_BADGE
66         for badge in self.BADGES:
67             if points >= self.BADGE_THRESHOLDS[badge]:
68                 highest_badge = badge
69
70         if highest_badge is not self.NO_BADGE:
71             return self.BADGE_NAMES[highest_badge]
72         else:
73             return None
74
75     def __unicode__(self):
76         return self.user.__unicode__()
77
78
79 @receiver(email_confirmed, weak=True)
80 def give_email_confirm_karma(sender, **kwargs):
81     GenericKarmaEvent.create_event(kwargs['email_address'].user, "You confirmed your email address", 5)
82
83
84 class BaseKarmaEvent(models.Model):
85     points    = models.IntegerField()
86     user      = models.ForeignKey(User)
87     timestamp = models.DateTimeField(default=datetime.datetime.utcnow)
88
89     class Meta:
90         abstract = True
91
92     def get_message(self):
93         raise NotImplemented()
94
95
96 class GenericKarmaEvent(BaseKarmaEvent):
97     message = models.CharField(max_length=255)
98
99     @staticmethod
100     def create_event(user, message, points):
101         event = GenericKarmaEvent.objects.create(user=user,
102                                                  points=points,
103                                                  message=message)
104         event.save()
105
106     def get_message(self):
107         return self.message
108
109
110 class NoteKarmaEvent(BaseKarmaEvent):
111     UPLOAD       = 'upload'
112     THANKS       = 'thanks'
113     NOTE_DELETED = 'deleted'
114     GIVE_FLAG    = 'give_flag'
115     GET_FLAGGED  = 'get_flagged'
116     EVENT_TYPE_CHOICES = (
117         (UPLOAD,       "You uploaded a note"),
118         (THANKS,       "You received a thanks for your note"),
119         (NOTE_DELETED, "Your note was deleted"),
120         (GIVE_FLAG,    "You flagged a note"),
121         (GET_FLAGGED,  "Your note was flagged as spam"),
122     )
123     note = models.ForeignKey('notes.Note')
124     event_type = models.CharField(max_length=15, choices=EVENT_TYPE_CHOICES)
125
126     POINTS = {
127         UPLOAD: 5,
128         THANKS: 1,
129         NOTE_DELETED: -5,
130         GIVE_FLAG: -1,
131         GET_FLAGGED: -100
132     }
133
134     def get_message(self):
135         return self.get_event_type_display()
136
137     def __unicode__(self):
138         return unicode(self.user) + ' -- ' + self.get_event_type_display() + ' -- ' + unicode(self.note)
139
140     @staticmethod
141     def create_event(user, note, type):
142         event = NoteKarmaEvent.objects.create(user=user,
143                                       note=note,
144                                       points=NoteKarmaEvent.POINTS[type],
145                                       event_type=type)
146         event.save()
147
148
149 class CourseKarmaEvent(BaseKarmaEvent):
150     GIVE_FLAG    = 'give_flag'
151     EVENT_TYPE_CHOICES = (
152         (GIVE_FLAG,    "You flagged a course"),
153     )
154     course = models.ForeignKey('courses.Course')
155     event_type = models.CharField(max_length=15, choices=EVENT_TYPE_CHOICES)
156
157     POINTS = {
158         GIVE_FLAG: -1,
159     }
160
161     def get_message(self):
162         return self.get_event_type_display()
163
164     def __unicode__(self):
165         return unicode(self.user) + ' -- ' + self.get_event_type_display() + ' -- ' + unicode(self.course)
166
167     @staticmethod
168     def create_event(user, course, type):
169         event = CourseKarmaEvent.objects.create(user=user,
170                                       course=course,
171                                       points=CourseKarmaEvent.POINTS[type],
172                                       event_type=type)
173         event.save()
174
175
176 ALL_KARMA_EVENT_CLASSES = (GenericKarmaEvent, NoteKarmaEvent, CourseKarmaEvent)
177
178
179 def user_display_name(user):
180     """Return the best way to display a user's
181     name to them on the site."""
182     if hasattr(user, 'first_name') and user.first_name and \
183             hasattr(user, 'last_name') and user.last_name:
184         return user.first_name + ' ' + user.last_name
185     elif hasattr(user, 'email') and user.email:
186         return user.email
187     else:
188         return user.username
189
190
191 @receiver(post_save, sender=User, weak=True)
192 def create_user_profile(sender, instance, created, **kwargs):
193     if created:
194         with transaction.commit_on_success():
195             try:
196                 UserProfile.objects.create(user=instance)
197             except DatabaseError:
198                 logger.warn("Could not create UserProfile for user {u}. This is okay if running syncdb.".format(u=instance))
199