from django.db import models
from django.core.exceptions import ValidationError
from askbot.utils import markup
from askbot.utils.html import sanitize_html
#class Post(models.Model):
# pass
class PostRevisionManager(models.Manager):
def create(self, *kargs, **kwargs):
raise NotImplementedError # Prevent accidental creation of PostRevision instance without `revision_type` set
def create_question_revision(self, *kargs, **kwargs):
kwargs['revision_type'] = self.model.QUESTION_REVISION
return super(PostRevisionManager, self).create(*kargs, **kwargs)
def create_answer_revision(self, *kargs, **kwargs):
kwargs['revision_type'] = self.model.ANSWER_REVISION
return super(PostRevisionManager, self).create(*kargs, **kwargs)
def question_revisions(self):
return self.filter(revision_type=self.model.QUESTION_REVISION)
def answer_revisions(self):
return self.filter(revision_type=self.model.ANSWER_REVISION)
class PostRevision(models.Model):
QUESTION_REVISION_TEMPLATE_NO_TAGS = (
'
%(title)s
\n'
'%(html)s
\n'
)
QUESTION_REVISION = 1
ANSWER_REVISION = 2
REVISION_TYPE_CHOICES = (
(QUESTION_REVISION, 'question'),
(ANSWER_REVISION, 'answer'),
)
REVISION_TYPE_CHOICES_DICT = dict(REVISION_TYPE_CHOICES)
answer = models.ForeignKey('askbot.Answer', related_name='revisions', null=True, blank=True)
question = models.ForeignKey('askbot.Question', related_name='revisions', null=True, blank=True)
revision_type = models.SmallIntegerField(choices=REVISION_TYPE_CHOICES)
revision = models.PositiveIntegerField()
author = models.ForeignKey('auth.User', related_name='%(class)ss')
revised_at = models.DateTimeField()
summary = models.CharField(max_length=300, blank=True)
text = models.TextField()
# Question-specific fields
title = models.CharField(max_length=300, blank=True, default='')
tagnames = models.CharField(max_length=125, blank=True, default='')
is_anonymous = models.BooleanField(default=False)
objects = PostRevisionManager()
class Meta:
# INFO: This `unique_together` constraint might be problematic for databases in which
# 2+ NULLs cannot be stored in an UNIQUE column.
# As far as I know MySQL, PostgreSQL and SQLite allow that so we're on the safe side.
unique_together = (('answer', 'revision'), ('question', 'revision'))
ordering = ('-revision',)
app_label = 'askbot'
def revision_type_str(self):
return self.REVISION_TYPE_CHOICES_DICT[self.revision_type]
def __unicode__(self):
return u'%s - revision %s of %s' % (self.revision_type_str(), self.revision, self.title)
def parent(self):
if self.is_question_revision():
return self.question
elif self.is_answer_revision():
return self.answer
def clean(self):
"Internal cleaning method, called from self.save() by self.full_clean()"
if bool(self.question) == bool(self.answer): # one and only one has to be set (!xor)
raise ValidationError('One (and only one) of question/answer fields has to be set.')
if (self.question and not self.is_question_revision()) or (self.answer and not self.is_answer_revision()):
raise ValidationError('Revision_type doesn`t match values in question/answer fields.')
def save(self, **kwargs):
# Determine the revision number, if not set
if not self.revision:
# TODO: Maybe use Max() aggregation? Or `revisions.count() + 1`
self.revision = self.parent().revisions.values_list('revision', flat=True)[0] + 1
# Make sure that everything is ok, in particular that `revision_type` and `revision` are set to valid values
self.full_clean()
super(PostRevision, self).save(**kwargs)
def is_question_revision(self):
return self.revision_type == self.QUESTION_REVISION
def is_answer_revision(self):
return self.revision_type == self.ANSWER_REVISION
@models.permalink
def get_absolute_url(self):
if self.is_question_revision():
return 'question_revisions', (self.question.id,), {}
elif self.is_answer_revision():
return 'answer_revisions', (), {'id':self.answer.id}
def get_question_title(self):
#INFO: ack-grepping shows that it's only used for Questions, so there's no code for Answers
return self.question.title
def as_html(self, **kwargs):
markdowner = markup.get_parser()
sanitized_html = sanitize_html(markdowner.convert(self.text))
if self.is_question_revision():
return self.QUESTION_REVISION_TEMPLATE_NO_TAGS % {
'title': self.title,
'html': sanitized_html
}
elif self.is_answer_revision():
return sanitized_html