62
62
class Forum(models.Model):
63
category = models.ForeignKey(Category, related_name='forums', verbose_name=_('Category'))
63
category = models.ForeignKey(
64
Category, related_name='forums', verbose_name=_('Category'))
64
65
name = models.CharField(_('Name'), max_length=80)
65
66
position = models.IntegerField(_('Position'), blank=True, default=0)
66
67
description = models.TextField(_('Description'), blank=True, default='')
67
moderators = models.ManyToManyField(User, blank=True, verbose_name=_('Moderators'))
68
moderators = models.ManyToManyField(
69
User, blank=True, verbose_name=_('Moderators'))
68
70
updated = models.DateTimeField(_('Updated'), null=True)
93
95
def last_post(self):
94
posts = self.posts.exclude(hidden=True).order_by('-created').select_related()
96
posts = self.posts.exclude(hidden=True).order_by(
97
'-created').select_related()
97
100
except IndexError:
100
104
class Topic(models.Model):
101
forum = models.ForeignKey(Forum, related_name='topics', verbose_name=_('Forum'))
105
forum = models.ForeignKey(
106
Forum, related_name='topics', verbose_name=_('Forum'))
102
107
name = models.CharField(_('Subject'), max_length=255)
103
108
created = models.DateTimeField(_('Created'), null=True)
104
109
updated = models.DateTimeField(_('Updated'), null=True)
106
111
views = models.IntegerField(_('Views count'), blank=True, default=0)
107
112
sticky = models.BooleanField(_('Sticky'), blank=True, default=False)
108
113
closed = models.BooleanField(_('Closed'), blank=True, default=False)
109
subscribers = models.ManyToManyField(User, related_name='subscriptions', verbose_name=_('Subscribers'), blank=True)
114
subscribers = models.ManyToManyField(
115
User, related_name='subscriptions', verbose_name=_('Subscribers'), blank=True)
112
118
if settings.USE_SPHINX:
113
119
search = SphinxSearch(
120
126
ordering = ['-updated']
160
167
read.time = datetime.now()
163
#def has_unreads(self, user):
170
# def has_unreads(self, user):
165
172
#read = Read.objects.get(user=user, topic=self)
166
#except Read.DoesNotExist:
169
#return self.updated > read.time
173
# except Read.DoesNotExist:
176
# return self.updated > read.time
172
179
class RenderableItem(models.Model):
174
Base class for models that has markup, body, body_text and body_html fields.
180
"""Base class for models that has markup, body, body_text and body_html
181
187
if self.markup == 'bbcode':
182
188
self.body_html = mypostmarkup.markup(self.body, auto_urls=False)
183
189
elif self.markup == 'markdown':
184
self.body_html = unicode(do_wl_markdown(self.body, 'bleachit', wikiwords=False))
190
self.body_html = unicode(do_wl_markdown(
191
self.body, 'bleachit', wikiwords=False))
186
193
raise Exception('Invalid markup property: %s' % self.markup)
194
201
self.body_html = urlize(self.body_html)
196
204
class Post(RenderableItem):
197
topic = models.ForeignKey(Topic, related_name='posts', verbose_name=_('Topic'))
198
user = models.ForeignKey(User, related_name='posts', verbose_name=_('User'))
205
topic = models.ForeignKey(
206
Topic, related_name='posts', verbose_name=_('Topic'))
207
user = models.ForeignKey(
208
User, related_name='posts', verbose_name=_('User'))
199
209
created = models.DateTimeField(_('Created'), blank=True)
200
210
updated = models.DateTimeField(_('Updated'), blank=True, null=True)
201
markup = models.CharField(_('Markup'), max_length=15, default=pybb_settings.DEFAULT_MARKUP, choices=MARKUP_CHOICES)
211
markup = models.CharField(_('Markup'), max_length=15,
212
default=pybb_settings.DEFAULT_MARKUP, choices=MARKUP_CHOICES)
202
213
body = models.TextField(_('Message'))
203
214
body_html = models.TextField(_('HTML version'))
204
215
body_text = models.TextField(_('Text version'))
244
254
super(Post, self).save(*args, **kwargs)
247
256
def get_absolute_url(self):
248
257
return reverse('pybb_post', args=[self.id])
250
259
def unhide_post(self):
251
"Unhide post(s) and inform subscribers"
260
"""Unhide post(s) and inform subscribers."""
252
261
self.hidden = False
254
263
if self.topic.post_count == 1:
255
264
# The topic is new
256
send(User.objects.all(), "forum_new_topic",
257
{'topic': self.topic, 'post':self, 'user':self.topic.user})
265
send(User.objects.all(), 'forum_new_topic',
266
{'topic': self.topic, 'post': self, 'user': self.topic.user})
259
268
# Inform topic subscribers
260
send(self.topic.subscribers.all(), "forum_new_post",
261
{'post':self, 'topic':self.topic, 'user':self.user})
269
send(self.topic.subscribers.all(), 'forum_new_post',
270
{'post': self, 'topic': self.topic, 'user': self.user})
263
272
def delete(self, *args, **kwargs):
264
273
self_id = self.id
275
284
class Read(models.Model):
277
For each topic that user has entered the time
278
is logged to this model.
285
"""For each topic that user has entered the time is logged to this
281
288
user = models.ForeignKey(User, verbose_name=_('User'))
282
289
topic = models.ForeignKey(Topic, verbose_name=_('Topic'))
292
299
self.time = datetime.now()
293
300
super(Read, self).save(*args, **kwargs)
296
302
def __unicode__(self):
297
303
return u'T[%d], U[%d]: %s' % (self.topic.id, self.user.id, unicode(self.time))
300
306
class PrivateMessage(RenderableItem):
302
dst_user = models.ForeignKey(User, verbose_name=_('Recipient'), related_name='dst_users')
303
src_user = models.ForeignKey(User, verbose_name=_('Author'), related_name='src_users')
308
dst_user = models.ForeignKey(User, verbose_name=_(
309
'Recipient'), related_name='dst_users')
310
src_user = models.ForeignKey(User, verbose_name=_(
311
'Author'), related_name='src_users')
304
312
read = models.BooleanField(_('Read'), blank=True, default=False)
305
313
created = models.DateTimeField(_('Created'), blank=True)
306
markup = models.CharField(_('Markup'), max_length=15, default=pybb_settings.DEFAULT_MARKUP, choices=MARKUP_CHOICES)
314
markup = models.CharField(_('Markup'), max_length=15,
315
default=pybb_settings.DEFAULT_MARKUP, choices=MARKUP_CHOICES)
307
316
subject = models.CharField(_('Subject'), max_length=255)
308
317
body = models.TextField(_('Message'))
309
318
body_html = models.TextField(_('HTML version'))
333
342
super(PrivateMessage, self).save(*args, **kwargs)
335
344
def get_absolute_url(self):
336
return reverse('pybb_show_pm', args=[self.id])
345
return reverse('pybb_show_pm', args=[self.id])
339
348
class Attachment(models.Model):
340
post = models.ForeignKey(Post, verbose_name=_('Post'), related_name='attachments')
349
post = models.ForeignKey(Post, verbose_name=_(
350
'Post'), related_name='attachments')
341
351
size = models.IntegerField(_('Size'))
342
352
content_type = models.CharField(_('Content type'), max_length=255)
343
353
path = models.CharField(_('Path'), max_length=255)
344
354
name = models.TextField(_('Name'))
345
hash = models.CharField(_('Hash'), max_length=40, blank=True, default='', db_index=True)
355
hash = models.CharField(_('Hash'), max_length=40,
356
blank=True, default='', db_index=True)
347
358
def save(self, *args, **kwargs):
348
359
super(Attachment, self).save(*args, **kwargs)
349
360
if not self.hash:
350
self.hash = hashlib.sha1(str(self.id) + settings.SECRET_KEY).hexdigest()
361
self.hash = hashlib.sha1(
362
str(self.id) + settings.SECRET_KEY).hexdigest()
351
363
super(Attachment, self).save(*args, **kwargs)
353
365
def __unicode__(self):