annotate gpp/bio/models.py @ 348:d1b11096595b

Fix #168; when nailing a spammer, clear their profile text fields. Guard against topics and forums that don't exist when deleting posts in the signal handler. Make the forum stats template tag only display the latest active users.
author Brian Neal <bgneal@gmail.com>
date Wed, 02 Mar 2011 02:18:28 +0000
parents 000c006fee97
children 9d470c7a2b93
rev   line source
gremmie@1 1 """
gremmie@1 2 Contains models for the bio application.
gremmie@1 3 I would have picked profile for this application, but that is already taken, apparently.
gremmie@1 4 """
bgneal@277 5 import datetime
gremmie@1 6 import os.path
gremmie@1 7
gremmie@1 8 from django.db import models
bgneal@259 9 from django.contrib.auth.models import User
gremmie@1 10 from django.conf import settings
bgneal@54 11 from django.core.cache import cache
bgneal@277 12 from django.template.loader import render_to_string
gremmie@1 13
bgneal@128 14 from core.markup import SiteMarkup
bgneal@124 15
bgneal@215 16 # These are the secondary user status enumeration values.
bgneal@215 17 (STA_ACTIVE, # User is a full member in good standing.
bgneal@215 18 STA_RESIGNED, # User has voluntarily asked to be removed.
bgneal@215 19 STA_REMOVED, # User was removed for bad behavior.
bgneal@215 20 STA_SUSPENDED, # User is temporarily suspended; e.g. a stranger tripped
bgneal@215 21 # the spam filter.
bgneal@215 22 STA_SPAMMER, # User has been removed for spamming.
bgneal@215 23 STA_STRANGER, # New member, isn't fully trusted yet. Their comments and
bgneal@215 24 # forum posts are scanned for spam. They can have their
bgneal@215 25 # accounts deactivated by moderators for spamming.
bgneal@215 26 ) = range(6)
bgneal@147 27
bgneal@147 28 USER_STATUS_CHOICES = (
bgneal@147 29 (STA_ACTIVE, "Active"),
bgneal@147 30 (STA_RESIGNED, "Resigned"),
bgneal@147 31 (STA_REMOVED, "Removed"),
bgneal@147 32 (STA_SUSPENDED, "Suspended"),
bgneal@147 33 (STA_SPAMMER, "Spammer"),
bgneal@215 34 (STA_STRANGER, "Stranger")
bgneal@147 35 )
bgneal@147 36
bgneal@204 37
bgneal@204 38 class Badge(models.Model):
bgneal@204 39 """This model represents badges that users can earn."""
bgneal@204 40 image = models.ImageField(upload_to='badges')
bgneal@204 41 name = models.CharField(max_length=64)
bgneal@204 42 description = models.TextField(blank=True)
bgneal@204 43 order = models.IntegerField()
bgneal@204 44 numeric_id = models.IntegerField(db_index=True)
bgneal@204 45
bgneal@204 46 class Meta:
bgneal@204 47 ordering = ('order', )
bgneal@204 48
bgneal@204 49 def __unicode__(self):
bgneal@204 50 return self.name
bgneal@204 51
bgneal@204 52 def get_absolute_url(self):
bgneal@204 53 return self.image.url
bgneal@204 54
bgneal@204 55 def html(self):
bgneal@204 56 """Returns a HTML img tag representation of the badge."""
bgneal@204 57 if self.image:
bgneal@204 58 return u'<img src="%s" alt="%s" title="%s" />' % (
bgneal@204 59 self.get_absolute_url(), self.name, self.name)
bgneal@204 60 return u''
bgneal@204 61 html.allow_tags = True
bgneal@204 62
bgneal@204 63
gremmie@1 64 def avatar_file_path_for_user(username, filename):
gremmie@1 65 return os.path.join(settings.AVATAR_DIR, 'users', username, filename)
gremmie@1 66
gremmie@1 67 def avatar_file_path(instance, filename):
gremmie@1 68 return avatar_file_path_for_user(instance.user.username, filename)
gremmie@1 69
gremmie@1 70
gremmie@1 71 class UserProfile(models.Model):
gremmie@1 72 """model to represent additional information about users"""
gremmie@1 73
bgneal@259 74 user = models.ForeignKey(User, unique=True)
gremmie@1 75 location = models.CharField(max_length=128, blank=True)
gremmie@1 76 birthday = models.DateField(blank=True, null=True,
gremmie@1 77 help_text='Optional; the year is not shown to others')
gremmie@1 78 occupation = models.CharField(max_length=128, blank=True)
gremmie@1 79 interests = models.CharField(max_length=255, blank=True)
gremmie@1 80 profile_text = models.TextField(blank=True)
gremmie@1 81 profile_html = models.TextField(blank=True)
gremmie@1 82 hide_email = models.BooleanField(default=True)
gremmie@1 83 signature = models.TextField(blank=True)
gremmie@1 84 signature_html = models.TextField(blank=True)
gremmie@1 85 avatar = models.ImageField(upload_to=avatar_file_path, blank=True)
bgneal@70 86 time_zone = models.CharField(max_length=64, blank=True,
bgneal@70 87 default='US/Pacific')
bgneal@120 88 use_24_time = models.BooleanField(default=False)
bgneal@96 89 forum_post_count = models.IntegerField(default=0)
bgneal@215 90 status = models.IntegerField(default=STA_STRANGER,
bgneal@147 91 choices=USER_STATUS_CHOICES)
bgneal@147 92 status_date = models.DateTimeField(auto_now_add=True)
bgneal@204 93 badges = models.ManyToManyField(Badge, through="BadgeOwnership")
bgneal@277 94 update_date = models.DateTimeField(db_index=True, blank=True)
gremmie@1 95
gremmie@1 96 def __unicode__(self):
gremmie@1 97 return self.user.username
gremmie@1 98
gremmie@1 99 class Meta:
gremmie@1 100 ordering = ('user__username', )
gremmie@1 101
gremmie@1 102 def save(self, *args, **kwargs):
bgneal@282 103 self.update_date = datetime.datetime.now()
bgneal@128 104 sm = SiteMarkup()
bgneal@128 105 self.profile_html = sm.convert(self.profile_text)
bgneal@128 106 self.signature_html = sm.convert(self.signature)
gremmie@1 107 super(UserProfile, self).save(*args, **kwargs)
bgneal@54 108 cache.delete('avatar_' + self.user.username)
bgneal@138 109
bgneal@138 110 @models.permalink
bgneal@138 111 def get_absolute_url(self):
bgneal@138 112 return ('bio-view_profile', (), {'username': self.user.username})
bgneal@138 113
bgneal@204 114 def badge_ownership(self):
bgneal@329 115 return BadgeOwnership.objects.filter(profile=self).select_related('badge')
bgneal@204 116
bgneal@215 117 def is_stranger(self):
bgneal@215 118 """Returns True if this user profile status is STA_STRANGER."""
bgneal@215 119 return self.status == STA_STRANGER
bgneal@215 120
bgneal@215 121 def user_is_active(self):
bgneal@215 122 """Returns the profile's user is_active status. This function exists
bgneal@215 123 for the admin.
bgneal@215 124 """
bgneal@215 125 return self.user.is_active
bgneal@215 126 user_is_active.boolean = True
bgneal@215 127 user_is_active.short_description = "Is Active"
bgneal@215 128
bgneal@223 129 def search_title(self):
bgneal@223 130 full_name = self.user.get_full_name()
bgneal@223 131 if full_name:
bgneal@223 132 return u"%s (%s)" % (self.user.username, full_name)
bgneal@223 133 return self.user.username
bgneal@223 134
bgneal@223 135 def search_summary(self):
bgneal@277 136 text = render_to_string('search/indexes/bio/userprofile_text.txt',
bgneal@277 137 {'object': self});
bgneal@277 138 return text
bgneal@223 139
bgneal@138 140
bgneal@138 141 class UserProfileFlag(models.Model):
bgneal@138 142 """This model represents a user flagging a profile as inappropriate."""
bgneal@259 143 user = models.ForeignKey(User)
bgneal@138 144 profile = models.ForeignKey(UserProfile)
bgneal@138 145 flag_date = models.DateTimeField(auto_now_add=True)
bgneal@138 146
bgneal@138 147 def __unicode__(self):
bgneal@138 148 return u"%s's profile flagged by %s" % (self.profile.user.username,
bgneal@138 149 self.user.username)
bgneal@138 150
bgneal@138 151 class Meta:
bgneal@138 152 ordering = ('flag_date', )
bgneal@138 153
bgneal@138 154 def get_profile_url(self):
bgneal@138 155 return '<a href="%s">Profile</a>' % self.profile.get_absolute_url()
bgneal@138 156 get_profile_url.allow_tags = True
bgneal@204 157
bgneal@204 158
bgneal@204 159 class BadgeOwnership(models.Model):
bgneal@204 160 """This model represents the ownership of badges by users."""
bgneal@204 161 profile = models.ForeignKey(UserProfile)
bgneal@204 162 badge = models.ForeignKey(Badge)
bgneal@204 163 count = models.IntegerField(default=1)
bgneal@204 164
bgneal@204 165 class Meta:
bgneal@204 166 verbose_name_plural = "badge ownership"
bgneal@204 167 ordering = ('badge__order', )
bgneal@204 168
bgneal@204 169 def __unicode__(self):
bgneal@204 170 if self.count == 1:
bgneal@204 171 return u"%s owns 1 %s" % (self.profile.user.username,
bgneal@204 172 self.badge.name)
bgneal@204 173 else:
bgneal@204 174 return u"%s owns %d %s badges" % (self.profile.user.username,
bgneal@204 175 self.count, self.badge.name)
bgneal@204 176
bgneal@204 177 def badge_count_str(self):
bgneal@204 178 if self.count == 1:
bgneal@204 179 return u"1 %s" % self.badge.name
bgneal@204 180 return u"%d %ss" % (self.count, self.badge.name)