3 # Copyright (C) 2013 FinalsClub Foundation
6 from allauth.account.signals import email_confirmed
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
15 logger = logging.getLogger(__name__)
18 class UserProfileManager(models.Manager):
19 """ Handle restoring data. """
20 def get_by_natural_key(self, user):
21 return self.get(user=user)
24 class UserProfile(models.Model):
25 user = models.OneToOneField(User)
26 thanked_notes = models.ManyToManyField('notes.Note', related_name='users_thanked', blank=True, null=True)
27 flagged_notes = models.ManyToManyField('notes.Note', related_name='users_flagged', blank=True, null=True)
28 flagged_courses = models.ManyToManyField('courses.Course', related_name='users_flagged', blank=True, null=True)
29 school = models.ForeignKey(School, blank=True, null=True)
31 def natural_key(self):
36 for cls in ALL_KARMA_EVENT_CLASSES:
37 points = cls.objects.filter(user=self.user).aggregate(Sum('points'))['points__sum']
43 def can_edit_items(self):
44 if self.user.is_staff:
47 return (self.get_points() >= 20)
68 APPRENTICE: 'Apprentice',
81 points = self.get_points()
82 highest_badge = self.NO_BADGE
83 for badge in self.BADGES:
84 if points >= self.BADGE_THRESHOLDS[badge]:
87 if highest_badge is not self.NO_BADGE:
88 return self.BADGE_NAMES[highest_badge]
92 def __unicode__(self):
93 return self.user.__unicode__()
96 @receiver(email_confirmed, weak=True)
97 def give_email_confirm_karma(sender, **kwargs):
98 GenericKarmaEvent.create_event(kwargs['email_address'].user, kwargs['email_address'].email, GenericKarmaEvent.EMAIL_CONFIRMED)
101 class BaseKarmaEventManager(models.Manager):
102 """ Handle restoring data. """
103 def get_by_natural_key(self, points, user, timestamp):
104 return self.get(user=user, timestamp=timestamp)
107 class BaseKarmaEvent(models.Model):
108 points = models.IntegerField()
109 user = models.ForeignKey(User)
110 timestamp = models.DateTimeField(default=datetime.datetime.utcnow)
114 unique_together = ('points', 'user', 'timestamp')
116 def natural_key(self):
117 return (self.user, self.timestamp)
119 def get_message(self):
120 raise NotImplemented()
123 class GenericKarmaEvent(BaseKarmaEvent):
125 NOTE_DELETED = 'upload'
126 EMAIL_CONFIRMED = 'thanks'
128 EVENT_TYPE_CHOICES = (
129 (NONE, 'This should not happen'),
130 (NOTE_DELETED, 'Your note "{m}" was deleted'),
131 (EMAIL_CONFIRMED, 'You confirmed your email address {m}'),
139 event_type = models.CharField(max_length=15, choices=EVENT_TYPE_CHOICES, default=NONE)
140 message = models.CharField(max_length=255)
143 def create_event(user, message, type):
144 event = GenericKarmaEvent.objects.create(user=user,
145 points=GenericKarmaEvent.POINTS[type],
150 def get_message(self):
151 if self.event_type == self.NONE:
154 return self.get_event_type_display().format(m=self.message)
156 def __unicode__(self):
157 return unicode(self.user) + ' -- ' + self.get_message()
160 class NoteKarmaEvent(BaseKarmaEvent):
163 NOTE_DELETED = 'deleted'
164 GIVE_FLAG = 'give_flag'
165 GET_FLAGGED = 'get_flagged'
166 DOWNLOADED_NOTE = 'downloaded'
167 HAD_NOTE_DOWNLOADED = 'was_downloaded'
168 CREATED_KEYWORD = 'created_keyword'
170 EVENT_TYPE_CHOICES = (
171 (UPLOAD, "You uploaded a note"),
172 (THANKS, "You received a thanks for your note"),
173 (NOTE_DELETED, "Your note was deleted"),
174 (GIVE_FLAG, "You flagged a note"),
175 (GET_FLAGGED, "Your note was flagged as spam"),
176 (DOWNLOADED_NOTE, "You downloaded a note"),
177 (HAD_NOTE_DOWNLOADED, "Your note was downloaded"),
178 (CREATED_KEYWORD, "You created a keyword"),
180 note = models.ForeignKey('notes.Note')
181 event_type = models.CharField(max_length=15, choices=EVENT_TYPE_CHOICES)
190 HAD_NOTE_DOWNLOADED: 2,
194 def get_message(self):
195 return self.get_event_type_display()
197 def __unicode__(self):
198 return unicode(self.user) + ' -- ' + self.get_event_type_display() + ' -- ' + unicode(self.note)
201 def create_event(user, note, type):
202 event = NoteKarmaEvent.objects.create(user=user,
204 points=NoteKarmaEvent.POINTS[type],
209 class CourseKarmaEvent(BaseKarmaEvent):
210 GIVE_FLAG = 'give_flag'
211 EVENT_TYPE_CHOICES = (
212 (GIVE_FLAG, "You flagged a course"),
214 course = models.ForeignKey('courses.Course')
215 event_type = models.CharField(max_length=15, choices=EVENT_TYPE_CHOICES)
221 def get_message(self):
222 return self.get_event_type_display()
224 def __unicode__(self):
225 return unicode(self.user) + ' -- ' + self.get_event_type_display() + ' -- ' + unicode(self.course)
228 def create_event(user, course, type):
229 event = CourseKarmaEvent.objects.create(user=user,
231 points=CourseKarmaEvent.POINTS[type],
236 ALL_KARMA_EVENT_CLASSES = (GenericKarmaEvent, NoteKarmaEvent, CourseKarmaEvent)
239 def user_display_name(user):
240 """Return the best way to display a user's
241 name to them on the site."""
242 if hasattr(user, 'first_name') and user.first_name and \
243 hasattr(user, 'last_name') and user.last_name:
244 return user.first_name + ' ' + user.last_name
245 elif hasattr(user, 'email') and user.email:
251 @receiver(post_save, sender=User, weak=True)
252 def create_user_profile(sender, instance, created, **kwargs):
254 with transaction.commit_on_success():
256 UserProfile.objects.create(user=instance)
257 except DatabaseError:
258 logger.warn("Could not create UserProfile for user {u}. This is okay if running syncdb.".format(u=instance))