summaryrefslogtreecommitdiffstats
path: root/askbot/models/post.py
blob: c61e88774a41a9291bdfd55741d8a9b3e8a4ae2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from django.db import models

from askbot.utils import markup
from askbot.utils.html import sanitize_html

#class Post(models.Model):
#    pass

class PostRevisionManager(models.Manager):
    def create_question_revision(self, *kargs, **kwargs):
        kwargs['revision_type'] = self.model.QUESTION_REVISION
        return self.create(*kargs, **kwargs)

    def create_answer_revision(self, *kargs, **kwargs):
        kwargs['revision_type'] = self.model.ANSWER_REVISION
        return 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 = (
        '<h3>%(title)s</h3>\n'
        '<div class="text">%(html)s</div>\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 save(self, **kwargs):
        """Determines the revistion type and then looks up the next available revision number if not set."""

        if not self.revision:
            # TODO: Maybe use Max() aggregation?
            # TODO: Handle IntegrityError if revision id is already occupied?
            self.revision = self.parent().revisions.values_list('revision', flat=True)[0] + 1

        self.full_clean() # Make sure that everything is ok, in particular that `revision_type` and `revision` are set to valid values

        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