comparison bio/models.py @ 581:ee87ea74d46b

For Django 1.4, rearranged project structure for new manage.py.
author Brian Neal <bgneal@gmail.com>
date Sat, 05 May 2012 17:10:48 -0500
parents gpp/bio/models.py@98b373ca09f3
children 678a1a2ef55a
comparison
equal deleted inserted replaced
580:c525f3e0b5d0 581:ee87ea74d46b
1 """
2 Contains models for the bio application.
3 I would have picked profile for this application, but that is already taken, apparently.
4 """
5 import datetime
6 import os.path
7
8 from django.db import models
9 from django.contrib.auth.models import User
10 from django.conf import settings
11 from django.core.cache import cache
12 from django.template.loader import render_to_string
13
14 from core.markup import SiteMarkup
15
16
17 # These are the secondary user status enumeration values.
18 (STA_ACTIVE, # User is a full member in good standing.
19 STA_RESIGNED, # User has voluntarily asked to be removed.
20 STA_REMOVED, # User was removed for bad behavior.
21 STA_SUSPENDED, # User is temporarily suspended; e.g. a stranger tripped
22 # the spam filter.
23 STA_SPAMMER, # User has been removed for spamming.
24 STA_STRANGER, # New member, isn't fully trusted yet. Their comments and
25 # forum posts are scanned for spam. They can have their
26 # accounts deactivated by moderators for spamming.
27 ) = range(6)
28
29 USER_STATUS_CHOICES = (
30 (STA_ACTIVE, "Active"),
31 (STA_RESIGNED, "Resigned"),
32 (STA_REMOVED, "Removed"),
33 (STA_SUSPENDED, "Suspended"),
34 (STA_SPAMMER, "Spammer"),
35 (STA_STRANGER, "Stranger")
36 )
37
38
39 class Badge(models.Model):
40 """This model represents badges that users can earn."""
41 image = models.ImageField(upload_to='badges')
42 name = models.CharField(max_length=64)
43 description = models.TextField(blank=True)
44 order = models.IntegerField()
45 numeric_id = models.IntegerField(db_index=True)
46
47 class Meta:
48 ordering = ('order', )
49
50 def __unicode__(self):
51 return self.name
52
53 def get_absolute_url(self):
54 return self.image.url
55
56 def html(self):
57 """Returns a HTML img tag representation of the badge."""
58 if self.image:
59 return u'<img src="%s" alt="%s" title="%s" />' % (
60 self.get_absolute_url(), self.name, self.name)
61 return u''
62 html.allow_tags = True
63
64
65 def avatar_file_path(instance, filename):
66 ext = os.path.splitext(filename)[1]
67 if not ext:
68 ext = '.jpg'
69 avatar_name = instance.user.username + ext
70 return os.path.join(settings.AVATAR_DIR, 'users', avatar_name)
71
72
73 class UserProfile(models.Model):
74 """model to represent additional information about users"""
75
76 user = models.ForeignKey(User, unique=True)
77 location = models.CharField(max_length=128, blank=True)
78 birthday = models.DateField(blank=True, null=True,
79 help_text='Optional; the year is not shown to others')
80 occupation = models.CharField(max_length=128, blank=True)
81 interests = models.CharField(max_length=255, blank=True)
82 profile_text = models.TextField(blank=True)
83 profile_html = models.TextField(blank=True)
84 hide_email = models.BooleanField(default=True)
85 signature = models.TextField(blank=True)
86 signature_html = models.TextField(blank=True)
87 avatar = models.ImageField(upload_to=avatar_file_path, blank=True)
88 time_zone = models.CharField(max_length=64, blank=True,
89 default='US/Pacific')
90 use_24_time = models.BooleanField(default=False)
91 forum_post_count = models.IntegerField(default=0)
92 status = models.IntegerField(default=STA_STRANGER,
93 choices=USER_STATUS_CHOICES)
94 status_date = models.DateTimeField(auto_now_add=True)
95 badges = models.ManyToManyField(Badge, through="BadgeOwnership")
96 update_date = models.DateTimeField(db_index=True, blank=True)
97 auto_favorite = models.BooleanField(default=False)
98 auto_subscribe = models.BooleanField(default=False)
99
100 def __unicode__(self):
101 return self.user.username
102
103 class Meta:
104 ordering = ('user__username', )
105
106 def save(self, *args, **kwargs):
107 """
108 Custom profile save() function.
109 If content_update is True (default), then it is assumed that major
110 fields are being updated and that the profile_content_update signal
111 should be signalled. When content_update is False, the update_date is
112 not updated, expensive markup conversions are not performed, and the
113 signal is not signalled. This is useful for updating the
114 forum_post_count, for example.
115
116 """
117 content_update = kwargs.pop('content_update', True)
118
119 if content_update:
120 self.update_date = datetime.datetime.now()
121 sm = SiteMarkup()
122 self.profile_html = sm.convert(self.profile_text)
123 self.signature_html = sm.convert(self.signature)
124 cache.delete('avatar_' + self.user.username)
125
126 super(UserProfile, self).save(*args, **kwargs)
127
128 if content_update:
129 notify_profile_content_update(self)
130
131 @models.permalink
132 def get_absolute_url(self):
133 return ('bio-view_profile', (), {'username': self.user.username})
134
135 def badge_ownership(self):
136 return BadgeOwnership.objects.filter(profile=self).select_related('badge')
137
138 def is_stranger(self):
139 """Returns True if this user profile status is STA_STRANGER."""
140 return self.status == STA_STRANGER
141
142 def user_is_active(self):
143 """Returns the profile's user is_active status. This function exists
144 for the admin.
145 """
146 return self.user.is_active
147 user_is_active.boolean = True
148 user_is_active.short_description = "Is Active"
149
150 def reset_text_fields(self):
151 """
152 Reset profile text fields to empty defaults.
153 This function is useful when a spammer is identified.
154
155 """
156 self.location = ''
157 self.occupation = ''
158 self.interests = ''
159 self.profile_text = ''
160 self.signature = ''
161
162 def search_title(self):
163 full_name = self.user.get_full_name()
164 if full_name:
165 return u"%s (%s)" % (self.user.username, full_name)
166 return self.user.username
167
168 def search_summary(self):
169 text = render_to_string('search/indexes/bio/userprofile_text.txt',
170 {'object': self});
171 return text
172
173
174 class UserProfileFlag(models.Model):
175 """This model represents a user flagging a profile as inappropriate."""
176 user = models.ForeignKey(User)
177 profile = models.ForeignKey(UserProfile)
178 flag_date = models.DateTimeField(auto_now_add=True)
179
180 def __unicode__(self):
181 return u"%s's profile flagged by %s" % (self.profile.user.username,
182 self.user.username)
183
184 class Meta:
185 ordering = ('flag_date', )
186
187 def get_profile_url(self):
188 return '<a href="%s">Profile</a>' % self.profile.get_absolute_url()
189 get_profile_url.allow_tags = True
190
191
192 class BadgeOwnership(models.Model):
193 """This model represents the ownership of badges by users."""
194 profile = models.ForeignKey(UserProfile)
195 badge = models.ForeignKey(Badge)
196 count = models.IntegerField(default=1)
197
198 class Meta:
199 verbose_name_plural = "badge ownership"
200 ordering = ('badge__order', )
201
202 def __unicode__(self):
203 if self.count == 1:
204 return u"%s owns 1 %s" % (self.profile.user.username,
205 self.badge.name)
206 else:
207 return u"%s owns %d %s badges" % (self.profile.user.username,
208 self.count, self.badge.name)
209
210 def badge_count_str(self):
211 if self.count == 1:
212 return u"1 %s" % self.badge.name
213 return u"%d %ss" % (self.count, self.badge.name)
214
215 # Put down here to avoid a circular import
216 from bio.signals import notify_profile_content_update