5 from django.utils.safestring import mark_safe
\r
6 from django.utils.html import strip_tags
\r
7 from forum.utils.html import sanitize_html
\r
9 class NodeContent(models.Model):
\r
10 title = models.CharField(max_length=300)
\r
11 tagnames = models.CharField(max_length=125)
\r
12 author = models.ForeignKey(User, related_name='%(class)ss')
\r
13 body = models.TextField()
\r
21 return mark_safe(sanitize_html(markdown.markdown(self.body)))
\r
27 def tagname_list(self):
\r
29 return [name for name in self.tagnames.split(u' ')]
\r
33 def tagname_meta_generator(self):
\r
34 return u','.join([unicode(tag) for tag in self.tagname_list()])
\r
40 class NodeMetaClass(models.Model.__metaclass__):
\r
43 def __new__(cls, *args, **kwargs):
\r
44 new_cls = super(NodeMetaClass, cls).__new__(cls, *args, **kwargs)
\r
46 if not new_cls._meta.abstract and new_cls.__name__ is not 'Node':
\r
47 NodeMetaClass.types[new_cls.__name__.lower()] = new_cls
\r
52 def setup_relations(cls):
\r
53 for node_cls in NodeMetaClass.types.values():
\r
54 NodeMetaClass.setup_relation(node_cls)
\r
57 def setup_relation(cls, node_cls):
\r
58 name = node_cls.__name__.lower()
\r
61 if node_cls._meta.proxy:
\r
62 return node_cls.objects.filter(node_type=name, parent=self)
\r
64 return node_cls.objects.filter(parent=self)
\r
67 p = self.__dict__.get('_%s_cache' % name, None)
\r
69 if p is None and (self.parent is not None) and self.parent.node_type == name:
\r
70 p = self.parent.leaf
\r
71 self.__dict__['_%s_cache' % name] = p
\r
75 Node.add_to_class(name + 's', property(children))
\r
76 Node.add_to_class(name, property(parent))
\r
79 node_create = django.dispatch.Signal(providing_args=['instance'])
\r
81 class Node(BaseModel, NodeContent, DeletableContent):
\r
82 __metaclass__ = NodeMetaClass
\r
84 node_type = models.CharField(max_length=16, default='node')
\r
85 parent = models.ForeignKey('Node', related_name='children', null=True)
\r
87 added_at = models.DateTimeField(default=datetime.datetime.now)
\r
89 tags = models.ManyToManyField('Tag', related_name='%(class)ss')
\r
91 score = models.IntegerField(default=0)
\r
92 vote_up_count = models.IntegerField(default=0)
\r
93 vote_down_count = models.IntegerField(default=0)
\r
95 comment_count = models.PositiveIntegerField(default=0)
\r
96 offensive_flag_count = models.SmallIntegerField(default=0)
\r
98 last_edited_at = models.DateTimeField(null=True, blank=True)
\r
99 last_edited_by = models.ForeignKey(User, null=True, blank=True, related_name='last_edited_%(class)ss')
\r
101 active_revision = models.OneToOneField('NodeRevision', related_name='active', null=True)
\r
105 return NodeMetaClass.types[self.node_type].objects.get(id=self.id)
\r
109 return strip_tags(self.html)[:300]
\r
111 def create_revision(self, user, **kwargs):
\r
112 revision = NodeRevision(author=user, **kwargs)
\r
117 revision.revision = 1
\r
119 revision.revision = self.revisions.aggregate(last=models.Max('revision'))['last'] + 1
\r
121 revision.node_id = self.id
\r
123 self.activate_revision(user, revision)
\r
125 def activate_revision(self, user, revision):
\r
126 self.title = revision.title
\r
127 self.tagnames = revision.tagnames
\r
128 self.body = revision.body
\r
130 old_revision = self.active_revision
\r
132 self.active_revision = revision
\r
135 if not old_revision:
\r
136 self.last_edited_at = datetime.datetime.now()
\r
137 self.last_edited_by = user
\r
138 node_create.send(sender=self.__class__, instance=self)
\r
140 def get_tag_list_if_changed(self):
\r
141 dirty = self.get_dirty_fields()
\r
143 if 'tagnames' in dirty:
\r
144 new_tags = self.tagname_list()
\r
145 old_tags = dirty['tagnames']
\r
147 if old_tags is None or not old_tags:
\r
150 old_tags = [name for name in dirty['tagnames'].split(u' ')]
\r
154 for name in new_tags:
\r
156 tag = Tag.objects.get(name=name)
\r
158 tag = Tag.objects.create(name=name, created_by=self.last_edited_by or self.author)
\r
160 tag_list.append(tag)
\r
162 if not name in old_tags:
\r
163 tag.used_count = tag.used_count + 1
\r
165 tag.unmark_deleted()
\r
168 for name in [n for n in old_tags if not n in new_tags]:
\r
169 tag = Tag.objects.get(name=name)
\r
170 tag.used_count = tag.used_count - 1
\r
171 if tag.used_count == 0:
\r
172 tag.mark_deleted(self.last_edited_by or self.author)
\r
179 def save(self, *args, **kwargs):
\r
181 self.node_type = self.__class__.__name__.lower()
\r
183 tags = self.get_tag_list_if_changed()
\r
184 super(Node, self).save(*args, **kwargs)
\r
185 if tags is not None: self.tags = tags
\r
188 app_label = 'forum'
\r
191 class NodeRevision(NodeContent):
\r
192 node = models.ForeignKey(Node, related_name='revisions')
\r
193 summary = models.CharField(max_length=300)
\r
194 revision = models.PositiveIntegerField()
\r
195 revised_at = models.DateTimeField(default=datetime.datetime.now)
\r
198 unique_together = ('node', 'revision')
\r
199 app_label = 'forum'
\r
202 from user import ValidationHash
\r
204 class AnonymousNode(Node):
\r
205 validation_hash = models.ForeignKey(Node, related_name='anonymous_content')
\r
206 convertible_to = models.CharField(max_length=16, default='node')
\r