Mercurial > public > sg101
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 |