3 from urllib import quote_plus, urlencode
 
   4 from django.db import models, IntegrityError, connection, transaction
 
   5 from django.utils.http import urlquote  as django_urlquote
 
   6 from django.utils.html import strip_tags
 
   7 from django.core.urlresolvers import reverse
 
   8 from django.contrib.contenttypes import generic
 
   9 from django.contrib.contenttypes.models import ContentType
 
  10 from django.core.cache import cache
 
  11 from django.template.defaultfilters import slugify
 
  12 from django.db.models.signals import post_delete, post_save, pre_save, pre_delete
 
  13 from django.utils.translation import ugettext as _
 
  14 from django.utils.safestring import mark_safe
 
  15 from django.contrib.sitemaps import ping_google
 
  16 import django.dispatch
 
  17 from django.conf import settings
 
  18 from forum import const
 
  21 from forum.const import *
 
  23 class CachedManager(models.Manager):
 
  24     use_for_related_fields = True
 
  26     def get(self, *args, **kwargs):
 
  28             pk = [v for (k,v) in kwargs.items() if k in ('pk', 'pk__exact', 'id', 'id__exact') or k.endswith('_ptr__pk')][0]
 
  33             key = self.model.cache_key(pk)
 
  37                 obj = super(CachedManager, self).get(*args, **kwargs)
 
  38                 cache.set(key, obj, 60 * 60)
 
  42         return super(CachedManager, self).get(*args, **kwargs)
 
  44     def get_or_create(self, *args, **kwargs):
 
  46             return self.get(*args, **kwargs)
 
  48             return super(CachedManager, self).get_or_create(*args, **kwargs)
 
  51 class BaseModel(models.Model):
 
  52     objects = CachedManager()
 
  58     def __init__(self, *args, **kwargs):
 
  59         super(BaseModel, self).__init__(*args, **kwargs)
 
  60         self._original_state = dict([(k, v) for k,v in self.__dict__.items() if not k in kwargs])
 
  63     def cache_key(cls, pk):
 
  64         return '%s.%s:%s' % (settings.APP_URL, cls.__name__, pk)
 
  66     def get_dirty_fields(self):
 
  68         return dict([(k, self._original_state.get(k, None)) for k,v in self.__dict__.items()
 
  69                  if self._original_state.get(k, missing) == missing or self._original_state[k] != v])
 
  71     def save(self, *args, **kwargs):
 
  72         super(BaseModel, self).save(*args, **kwargs)
 
  73         self._original_state = dict(self.__dict__)
 
  74         cache.set(self.cache_key(self.pk), self, 86400)
 
  77         cache.delete(self.cache_key(self.pk))
 
  78         super(BaseModel, self).delete()
 
  81 class ActiveObjectManager(models.Manager):
 
  82     def get_query_set(self):
 
  83         return super(ActiveObjectManager, self).get_query_set().filter(canceled=False)
 
  85 class UndeletedObjectManager(models.Manager):
 
  86     def get_query_set(self):
 
  87         return super(UndeletedObjectManager, self).get_query_set().filter(deleted=False)
 
  89 class MetaContent(BaseModel):
 
  91         Base class for Vote, Comment and FlaggedItem
 
  93     content_type   = models.ForeignKey(ContentType)
 
  94     object_id      = models.PositiveIntegerField()
 
  95     content_object = generic.GenericForeignKey('content_type', 'object_id')
 
 101 from user import User
 
 103 class UserContent(models.Model):
 
 104     user = models.ForeignKey(User, related_name='%(class)ss')
 
 111 marked_deleted = django.dispatch.Signal(providing_args=["instance", "deleted_by"])
 
 113 class DeletableContent(models.Model):
 
 114     deleted     = models.BooleanField(default=False)
 
 115     deleted_at  = models.DateTimeField(null=True, blank=True)
 
 116     deleted_by  = models.ForeignKey(User, null=True, blank=True, related_name='deleted_%(class)ss')
 
 118     active = UndeletedObjectManager()
 
 124     def mark_deleted(self, user):
 
 127             self.deleted_at = datetime.datetime.now()
 
 128             self.deleted_by = user
 
 130             marked_deleted.send(sender=self.__class__, instance=self, deleted_by=user)
 
 135     def unmark_deleted(self):
 
 144 class ContentRevision(models.Model):
 
 146         Base class for QuestionRevision and AnswerRevision
 
 148     revision   = models.PositiveIntegerField()
 
 149     author     = models.ForeignKey(User, related_name='%(class)ss')
 
 150     revised_at = models.DateTimeField()
 
 151     summary    = models.CharField(max_length=300, blank=True)
 
 152     text       = models.TextField()
 
 159 class AnonymousContent(models.Model):
 
 161         Base class for AnonymousQuestion and AnonymousAnswer
 
 163     session_key = models.CharField(max_length=40)  #session id for anonymous questions
 
 164     wiki = models.BooleanField(default=False)
 
 165     added_at = models.DateTimeField(default=datetime.datetime.now)
 
 166     ip_addr = models.IPAddressField(max_length=21) #allow high port numbers
 
 167     author = models.ForeignKey(User,null=True)
 
 168     text = models.TextField()
 
 169     summary = models.CharField(max_length=180)
 
 176 from meta import Comment, Vote, FlaggedItem
 
 177 from user import activity_record
 
 179 class Content(BaseModel, DeletableContent):
 
 181         Base class for Question and Answer
 
 183     author               = models.ForeignKey(User, related_name='%(class)ss')
 
 184     added_at             = models.DateTimeField(default=datetime.datetime.now)
 
 186     wiki                 = models.BooleanField(default=False)
 
 187     wikified_at          = models.DateTimeField(null=True, blank=True)
 
 189     #locked               = models.BooleanField(default=False)
 
 190     #locked_by            = models.ForeignKey(User, null=True, blank=True, related_name='locked_%(class)ss')
 
 191     #locked_at            = models.DateTimeField(null=True, blank=True)
 
 193     score                = models.IntegerField(default=0)
 
 194     vote_up_count        = models.IntegerField(default=0)
 
 195     vote_down_count      = models.IntegerField(default=0)
 
 197     comment_count        = models.PositiveIntegerField(default=0)
 
 198     offensive_flag_count = models.SmallIntegerField(default=0)
 
 200     last_edited_at       = models.DateTimeField(null=True, blank=True)
 
 201     last_edited_by       = models.ForeignKey(User, null=True, blank=True, related_name='last_edited_%(class)ss')
 
 203     html                 = models.TextField()
 
 204     comments             = generic.GenericRelation(Comment)
 
 205     votes                = generic.GenericRelation(Vote)
 
 206     flagged_items        = generic.GenericRelation(FlaggedItem)
 
 212     def save(self, *args, **kwargs):
 
 213         self.__dict__['score'] = self.__dict__['vote_up_count'] - self.__dict__['vote_down_count']
 
 214         super(Content,self).save(*args, **kwargs)
 
 219             logging.debug('problem pinging google did you register you sitemap with google?')
 
 222     def post_get_last_update_info(self):
 
 225             if self.last_edited_at and self.last_edited_at > when:
 
 226                 when = self.last_edited_at
 
 227                 who = self.last_edited_by
 
 228             comments = self.comments.all()
 
 229             if len(comments) > 0:
 
 231                     if c.added_at > when: