]> git.openstreetmap.org Git - osqa.git/blob - forum/models/base.py
63ab1eb16b1d8761781bf513e5b458d357f46c15
[osqa.git] / forum / models / base.py
1 import datetime
2 import hashlib
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
19 import logging
20
21 from forum.const import *
22
23 class CachedManager(models.Manager):
24     use_for_related_fields = True
25
26     def get(self, *args, **kwargs):
27         try:
28             pk = [v for (k,v) in kwargs.items() if k in ('pk', 'pk__exact', 'id', 'id__exact') or k.endswith('_ptr__pk')][0]
29         except:
30             pk = None
31
32         if pk is not None:
33             key = self.model.cache_key(pk)
34             obj = cache.get(key)
35
36             if obj is None:
37                 obj = super(CachedManager, self).get(*args, **kwargs)
38                 cache.set(key, obj, 60 * 60)
39
40             return obj
41         
42         return super(CachedManager, self).get(*args, **kwargs)
43
44     def get_or_create(self, *args, **kwargs):
45         try:
46             return self.get(*args, **kwargs)
47         except:
48             return super(CachedManager, self).get_or_create(*args, **kwargs)
49
50
51 class BaseModel(models.Model):
52     objects = CachedManager()
53
54     class Meta:
55         abstract = True
56         app_label = 'forum'
57
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])
61
62     @classmethod
63     def cache_key(cls, pk):
64         return '%s.%s:%s' % (settings.APP_URL, cls.__name__, pk)
65
66     def get_dirty_fields(self):
67         missing = object()
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])
70
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)
75
76     def delete(self):
77         cache.delete(self.cache_key(self.pk))
78         super(BaseModel, self).delete()
79
80
81 class ActiveObjectManager(models.Manager):
82     def get_query_set(self):
83         return super(ActiveObjectManager, self).get_query_set().filter(canceled=False)
84
85 class UndeletedObjectManager(models.Manager):
86     def get_query_set(self):
87         return super(UndeletedObjectManager, self).get_query_set().filter(deleted=False)
88
89 class MetaContent(BaseModel):
90     """
91         Base class for Vote, Comment and FlaggedItem
92     """
93     content_type   = models.ForeignKey(ContentType)
94     object_id      = models.PositiveIntegerField()
95     content_object = generic.GenericForeignKey('content_type', 'object_id')
96
97     class Meta:
98         abstract = True
99         app_label = 'forum'
100
101 from user import User
102
103 class UserContent(models.Model):
104     user = models.ForeignKey(User, related_name='%(class)ss')
105
106     class Meta:
107         abstract = True
108         app_label = 'forum'
109
110
111 marked_deleted = django.dispatch.Signal(providing_args=["instance", "deleted_by"])
112
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')
117
118     active = UndeletedObjectManager()
119
120     class Meta:
121         abstract = True
122         app_label = 'forum'
123
124     def mark_deleted(self, user):
125         if not self.deleted:
126             self.deleted = True
127             self.deleted_at = datetime.datetime.now()
128             self.deleted_by = user
129             self.save()
130             marked_deleted.send(sender=self.__class__, instance=self, deleted_by=user)
131             return True
132         else:
133             return False
134
135     def unmark_deleted(self):
136         if self.deleted:
137             self.deleted = False
138             self.save()
139             return True
140         else:
141             return False
142
143
144 class ContentRevision(models.Model):
145     """
146         Base class for QuestionRevision and AnswerRevision
147     """
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()
153
154     class Meta:
155         abstract = True
156         app_label = 'forum'
157
158
159 class AnonymousContent(models.Model):
160     """
161         Base class for AnonymousQuestion and AnonymousAnswer
162     """
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)
170
171     class Meta:
172         abstract = True
173         app_label = 'forum'
174
175
176 from meta import Comment, Vote, FlaggedItem
177 from user import activity_record
178
179 class Content(BaseModel, DeletableContent):
180     """
181         Base class for Question and Answer
182     """
183     author               = models.ForeignKey(User, related_name='%(class)ss')
184     added_at             = models.DateTimeField(default=datetime.datetime.now)
185
186     wiki                 = models.BooleanField(default=False)
187     wikified_at          = models.DateTimeField(null=True, blank=True)
188
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)
192
193     score                = models.IntegerField(default=0)
194     vote_up_count        = models.IntegerField(default=0)
195     vote_down_count      = models.IntegerField(default=0)
196
197     comment_count        = models.PositiveIntegerField(default=0)
198     offensive_flag_count = models.SmallIntegerField(default=0)
199
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')
202
203     html                 = models.TextField()
204     comments             = generic.GenericRelation(Comment)
205     votes                = generic.GenericRelation(Vote)
206     flagged_items        = generic.GenericRelation(FlaggedItem)
207
208     class Meta:
209         abstract = True
210         app_label = 'forum'
211
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)
215
216         try:
217             ping_google()
218         except Exception:
219             logging.debug('problem pinging google did you register you sitemap with google?')
220
221
222     def post_get_last_update_info(self):
223             when = self.added_at
224             who = self.author
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:
230                 for c in comments:
231                     if c.added_at > when:
232                         when = c.added_at
233                         who = c.user
234             return when, who