diff --git a/boards/admin.py b/boards/admin.py
--- a/boards/admin.py
+++ b/boards/admin.py
@@ -5,7 +5,7 @@ from boards.models import Post, Tag, Use
class PostAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'text')
- list_filter = ('pub_time', 'tags')
+ list_filter = ('pub_time', 'thread_new')
search_fields = ('id', 'title', 'text')
diff --git a/boards/mdx_neboard.py b/boards/mdx_neboard.py
--- a/boards/mdx_neboard.py
+++ b/boards/mdx_neboard.py
@@ -14,6 +14,7 @@ SPOILER_PATTERN = r'%%(.+)%%'
COMMENT_PATTERN = r'^(//(.+))'
STRIKETHROUGH_PATTERN = r'~(.+)~'
+
class AutolinkPattern(Pattern):
def handleMatch(self, m):
link_element = etree.Element('a')
@@ -41,17 +42,17 @@ class ReflinkPattern(Pattern):
if posts.count() > 0:
ref_element = etree.Element('a')
- post = posts[0]
+ post = posts[0]
if post.thread:
link = reverse(boards.views.thread, kwargs={'post_id': post.thread.id}) \
+ '#' + post_id
else:
- link = reverse(boards.views.thread, kwargs={'post_id': post_id})
+ link = reverse(boards.views.thread, kwargs={'post_id': post_id})
ref_element.set('href', link)
ref_element.text = m.group(2)
- return ref_element
+ return ref_element
class SpoilerPattern(Pattern):
diff --git a/boards/migrations/0014_auto__add_thread__chg_field_post_thread.py b/boards/migrations/0014_auto__add_thread__chg_field_post_thread.py
new file mode 100644
--- /dev/null
+++ b/boards/migrations/0014_auto__add_thread__chg_field_post_thread.py
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'Thread'
+ db.create_table(u'boards_thread', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('bump_time', self.gf('django.db.models.fields.DateTimeField')()),
+ ('last_edit_time', self.gf('django.db.models.fields.DateTimeField')()),
+ ))
+ db.send_create_signal('boards', ['Thread'])
+
+ # Adding M2M table for field tags on 'Thread'
+ m2m_table_name = db.shorten_name(u'boards_thread_tags')
+ db.create_table(m2m_table_name, (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('thread', models.ForeignKey(orm['boards.thread'], null=False)),
+ ('tag', models.ForeignKey(orm['boards.tag'], null=False))
+ ))
+ db.create_unique(m2m_table_name, ['thread_id', 'tag_id'])
+
+ db.delete_table(db.shorten_name(u'boards_tag_threads'))
+ # Adding M2M table for field threads on 'Tag'
+ m2m_table_name = db.shorten_name(u'boards_tag_threads')
+ db.create_table(m2m_table_name, (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('thread', models.ForeignKey(orm['boards.thread'], null=False)),
+ ('tag', models.ForeignKey(orm['boards.tag'], null=False))
+ ))
+ db.create_unique(m2m_table_name, ['thread_id', 'tag_id'])
+
+ # Adding M2M table for field replies on 'Thread'
+ m2m_table_name = db.shorten_name(u'boards_thread_replies')
+ db.create_table(m2m_table_name, (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('thread', models.ForeignKey(orm['boards.thread'], null=False)),
+ ('post', models.ForeignKey(orm['boards.post'], null=False))
+ ))
+ db.create_unique(m2m_table_name, ['thread_id', 'post_id'])
+
+ db.add_column(u'boards_post', 'thread_new',
+ self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['boards.Thread'], null=True),
+ keep_default=False)
+
+ def backwards(self, orm):
+ pass
+
+ models = {
+ 'boards.ban': {
+ 'Meta': {'object_name': 'Ban'},
+ 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'})
+ },
+ 'boards.post': {
+ 'Meta': {'object_name': 'Post'},
+ '_text_rendered': ('django.db.models.fields.TextField', [], {}),
+ 'bump_time': ('django.db.models.fields.DateTimeField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}),
+ 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
+ 'poster_user_agent': ('django.db.models.fields.TextField', [], {}),
+ 'pub_time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}),
+ 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}),
+ 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}),
+ 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'})
+ },
+ 'boards.setting': {
+ 'Meta': {'object_name': 'Setting'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'boards.tag': {
+ 'Meta': {'object_name': 'Tag'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"})
+ },
+ 'boards.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'bump_time': ('django.db.models.fields.DateTimeField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'})
+ },
+ 'boards.user': {
+ 'Meta': {'object_name': 'User'},
+ 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rank': ('django.db.models.fields.IntegerField', [], {}),
+ 'registration_time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ }
+ }
+
+ complete_apps = ['boards']
\ No newline at end of file
diff --git a/boards/migrations/0015_post_to_thread.py b/boards/migrations/0015_post_to_thread.py
new file mode 100644
--- /dev/null
+++ b/boards/migrations/0015_post_to_thread.py
@@ -0,0 +1,98 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from boards import views
+
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ for post in orm.Post.objects.filter(thread=None):
+ thread = orm.Thread.objects.create(
+ bump_time=post.bump_time,
+ last_edit_time=post.last_edit_time)
+
+ thread.replies.add(post)
+ post.thread_new = thread
+ post.save()
+ print str(post.thread_new.id)
+
+ for reply in post.replies.all():
+ thread.replies.add(reply)
+ reply.thread_new = thread
+ reply.save()
+
+ for tag in post.tags.all():
+ thread.tags.add(tag)
+ tag.threads.add(thread)
+
+ def backwards(self, orm):
+ pass
+
+ models = {
+ 'boards.ban': {
+ 'Meta': {'object_name': 'Ban'},
+ 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'})
+ },
+ 'boards.post': {
+ 'Meta': {'object_name': 'Post'},
+ '_text_rendered': ('django.db.models.fields.TextField', [], {}),
+ 'bump_time': ('django.db.models.fields.DateTimeField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}),
+ 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
+ 'poster_user_agent': ('django.db.models.fields.TextField', [], {}),
+ 'pub_time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}),
+ 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'re+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}),
+ 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}),
+ 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Post']", 'null': 'True'}),
+ 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'})
+ },
+ 'boards.setting': {
+ 'Meta': {'object_name': 'Setting'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'boards.tag': {
+ 'Meta': {'object_name': 'Tag'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"})
+ },
+ 'boards.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'bump_time': ('django.db.models.fields.DateTimeField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'})
+ },
+ 'boards.user': {
+ 'Meta': {'object_name': 'User'},
+ 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rank': ('django.db.models.fields.IntegerField', [], {}),
+ 'registration_time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ }
+ }
+
+ complete_apps = ['boards']
+ symmetrical = True
diff --git a/boards/migrations/0016_auto__del_field_post_bump_time.py b/boards/migrations/0016_auto__del_field_post_bump_time.py
new file mode 100644
--- /dev/null
+++ b/boards/migrations/0016_auto__del_field_post_bump_time.py
@@ -0,0 +1,110 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Deleting field 'Post.bump_time'
+ db.delete_column(u'boards_post', 'bump_time')
+
+ # Removing M2M table for field tags on 'Post'
+ db.delete_table(db.shorten_name(u'boards_post_tags'))
+
+ # Removing M2M table for field replies on 'Post'
+ db.delete_table(db.shorten_name(u'boards_post_replies'))
+
+
+ def backwards(self, orm):
+
+ # User chose to not deal with backwards NULL issues for 'Post.bump_time'
+ raise RuntimeError("Cannot reverse this migration. 'Post.bump_time' and its values cannot be restored.")
+
+ # The following code is provided here to aid in writing a correct migration # Adding field 'Post.bump_time'
+ db.add_column(u'boards_post', 'bump_time',
+ self.gf('django.db.models.fields.DateTimeField')(),
+ keep_default=False)
+
+ # Adding M2M table for field tags on 'Post'
+ m2m_table_name = db.shorten_name(u'boards_post_tags')
+ db.create_table(m2m_table_name, (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('post', models.ForeignKey(orm['boards.post'], null=False)),
+ ('tag', models.ForeignKey(orm['boards.tag'], null=False))
+ ))
+ db.create_unique(m2m_table_name, ['post_id', 'tag_id'])
+
+ # Adding M2M table for field replies on 'Post'
+ m2m_table_name = db.shorten_name(u'boards_post_replies')
+ db.create_table(m2m_table_name, (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('from_post', models.ForeignKey(orm['boards.post'], null=False)),
+ ('to_post', models.ForeignKey(orm['boards.post'], null=False))
+ ))
+ db.create_unique(m2m_table_name, ['from_post_id', 'to_post_id'])
+
+
+ models = {
+ 'boards.ban': {
+ 'Meta': {'object_name': 'Ban'},
+ 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'})
+ },
+ 'boards.post': {
+ 'Meta': {'object_name': 'Post'},
+ '_text_rendered': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}),
+ 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
+ 'poster_user_agent': ('django.db.models.fields.TextField', [], {}),
+ 'pub_time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}),
+ 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}),
+ 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Post']", 'null': 'True'}),
+ 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'})
+ },
+ 'boards.setting': {
+ 'Meta': {'object_name': 'Setting'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'boards.tag': {
+ 'Meta': {'object_name': 'Tag'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"})
+ },
+ 'boards.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'bump_time': ('django.db.models.fields.DateTimeField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'})
+ },
+ 'boards.user': {
+ 'Meta': {'object_name': 'User'},
+ 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rank': ('django.db.models.fields.IntegerField', [], {}),
+ 'registration_time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ }
+ }
+
+ complete_apps = ['boards']
\ No newline at end of file
diff --git a/boards/models/__init__.py b/boards/models/__init__.py
--- a/boards/models/__init__.py
+++ b/boards/models/__init__.py
@@ -1,6 +1,7 @@
__author__ = 'neko259'
from boards.models.post import Post
+from boards.models.post import Thread
from boards.models.tag import Tag
from boards.models.user import Ban
from boards.models.user import Setting
diff --git a/boards/models/post.py b/boards/models/post.py
--- a/boards/models/post.py
+++ b/boards/models/post.py
@@ -38,18 +38,25 @@ class PostManager(models.Manager):
def create_post(self, title, text, image=None, thread=None,
ip=NO_IP, tags=None, user=None):
posting_time = timezone.now()
+ if not thread:
+ thread = Thread.objects.create(bump_time=posting_time,
+ last_edit_time=posting_time)
+ else:
+ thread.bump()
+ thread.last_edit_time = posting_time
+ thread.save()
post = self.create(title=title,
text=text,
pub_time=posting_time,
- thread=thread,
+ thread_new=thread,
image=image,
poster_ip=ip,
poster_user_agent=UNKNOWN_UA,
last_edit_time=posting_time,
- bump_time=posting_time,
user=user)
+ thread.replies.add(post)
if tags:
linked_tags = []
for tag in tags:
@@ -58,31 +65,18 @@ class PostManager(models.Manager):
linked_tags.extend(tag_linked_tags)
tags.extend(linked_tags)
- map(post.tags.add, tags)
- for tag in tags:
- tag.threads.add(post)
+ map(thread.add_tag, tags)
- if thread:
- thread.replies.add(post)
- thread.bump()
- thread.last_edit_time = posting_time
- thread.save()
- else:
- self._delete_old_threads()
-
+ self._delete_old_threads()
self.connect_replies(post)
return post
+ # TODO Remove this method after migration
def delete_post(self, post):
- if post.replies.count() > 0:
- map(self.delete_post, post.replies.all())
-
- # Update thread's last edit time
- thread = post.thread
- if thread:
- thread.last_edit_time = timezone.now()
- thread.save()
+ thread = post.thread_new
+ thread.last_edit_time = timezone.now()
+ thread.save()
post.delete()
@@ -90,15 +84,16 @@ class PostManager(models.Manager):
posts = self.filter(poster_ip=ip)
map(self.delete_post, posts)
+ # TODO Remove this method after migration
def get_threads(self, tag=None, page=ALL_PAGES,
order_by='-bump_time'):
if tag:
threads = tag.threads
- if threads.count() == 0:
+ if not threads.exists():
raise Http404
else:
- threads = self.filter(thread=None)
+ threads = Thread.objects.all()
threads = threads.order_by(order_by)
@@ -113,26 +108,25 @@ class PostManager(models.Manager):
return threads
+ # TODO Remove this method after migration
def get_thread(self, opening_post_id):
try:
- opening_post = self.get(id=opening_post_id, thread=None)
+ opening_post = self.get(id=opening_post_id)
except Post.DoesNotExist:
raise Http404
- if opening_post.replies:
- thread = [opening_post]
- thread.extend(opening_post.replies.all().order_by('pub_time'))
+ return opening_post.thread_new
- return thread
-
+ # TODO Move this method to thread manager
def get_thread_page_count(self, tag=None):
if tag:
- threads = self.filter(thread=None, tags=tag)
+ threads = Thread.objects.filter(tags=tag)
else:
- threads = self.filter(thread=None)
+ threads = Thread.objects.all()
return self._get_page_count(threads.count())
+ # TODO Move this method to thread manager
def _delete_old_threads(self):
"""
Preserves maximum thread count. If there are too many threads,
@@ -143,14 +137,14 @@ class PostManager(models.Manager):
# Maybe make some 'old' field in the model to indicate the thread
# must not be shown and be able for replying.
- threads = self.get_threads()
+ threads = Thread.objects.all()
thread_count = threads.count()
if thread_count > settings.MAX_THREAD_COUNT:
num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
old_threads = threads[thread_count - num_threads_to_delete:]
- map(self.delete_post, old_threads)
+ map(Thread.delete_with_posts, old_threads)
def connect_replies(self, post):
"""Connect replies to a post to show them as a refmap"""
@@ -204,13 +198,10 @@ class Post(models.Model):
poster_user_agent = models.TextField()
thread = models.ForeignKey('Post', null=True, default=None)
- tags = models.ManyToManyField('Tag')
+ thread_new = models.ForeignKey('Thread', null=True, default=None)
last_edit_time = models.DateTimeField()
- bump_time = models.DateTimeField()
user = models.ForeignKey('User', null=True, default=None)
- replies = models.ManyToManyField('Post', symmetrical=False, null=True,
- blank=True, related_name='re+')
referenced_posts = models.ManyToManyField('Post', symmetrical=False,
null=True,
blank=True, related_name='rfp+')
@@ -226,14 +217,40 @@ class Post(models.Model):
return title
+ def get_sorted_referenced_posts(self):
+ return self.referenced_posts.order_by('id')
+
+ def is_referenced(self):
+ return self.referenced_posts.all().exists()
+
+
+class Thread(models.Model):
+
+ class Meta:
+ app_label = 'boards'
+
+ tags = models.ManyToManyField('Tag')
+ bump_time = models.DateTimeField()
+ last_edit_time = models.DateTimeField()
+ replies = models.ManyToManyField('Post', symmetrical=False, null=True,
+ blank=True, related_name='tre+')
+
+ def get_tags(self):
+ """Get a sorted tag list"""
+
+ return self.tags.order_by('name')
+
+ def bump(self):
+ """Bump (move to up) thread"""
+
+ if self.can_bump():
+ self.bump_time = timezone.now()
+
def get_reply_count(self):
return self.replies.count()
def get_images_count(self):
- images_count = 1 if self.image else 0
- images_count += self.replies.filter(image_width__gt=0).count()
-
- return images_count
+ return self.replies.filter(image_width__gt=0).count()
def can_bump(self):
"""Check if the thread can be bumped by replying"""
@@ -242,31 +259,38 @@ class Post(models.Model):
return post_count <= settings.MAX_POSTS_PER_THREAD
- def bump(self):
- """Bump (move to up) thread"""
+ def delete_with_posts(self):
+ """Completely delete thread"""
- if self.can_bump():
- self.bump_time = timezone.now()
+ if self.replies.count() > 0:
+ map(Post.objects.delete_post, self.replies.all())
+
+ self.delete()
def get_last_replies(self):
+ """Get last replies, not including opening post"""
+
if settings.LAST_REPLIES_COUNT > 0:
reply_count = self.get_reply_count()
if reply_count > 0:
reply_count_to_show = min(settings.LAST_REPLIES_COUNT,
- reply_count)
+ reply_count - 1)
last_replies = self.replies.all().order_by('pub_time')[
reply_count - reply_count_to_show:]
return last_replies
- def get_tags(self):
- """Get a sorted tag list"""
+ def get_replies(self):
+ """Get sorted thread posts"""
- return self.tags.order_by('name')
+ return self.replies.all().order_by('pub_time')
- def get_sorted_referenced_posts(self):
- return self.referenced_posts.order_by('id')
+ def add_tag(self, tag):
+ """Connect thread to a tag and tag to a thread"""
- def is_referenced(self):
- return self.referenced_posts.all().exists()
+ self.tags.add(tag)
+ tag.threads.add(self)
+
+ def __unicode__(self):
+ return str(self.get_replies()[0].id)
\ No newline at end of file
diff --git a/boards/models/tag.py b/boards/models/tag.py
--- a/boards/models/tag.py
+++ b/boards/models/tag.py
@@ -1,4 +1,4 @@
-from boards.models import Post
+from boards.models import Thread
from django.db import models
from django.db.models import Count
@@ -20,8 +20,8 @@ class TagManager(models.Manager):
class Tag(models.Model):
"""
- A tag is a text node assigned to the post. The tag serves as a board
- section. There can be multiple tags for each message
+ A tag is a text node assigned to the thread. The tag serves as a board
+ section. There can be multiple tags for each thread
"""
objects = TagManager()
@@ -30,7 +30,7 @@ class Tag(models.Model):
app_label = 'boards'
name = models.CharField(max_length=100)
- threads = models.ManyToManyField('Post', null=True,
+ threads = models.ManyToManyField(Thread, null=True,
blank=True, related_name='tag+')
linked = models.ForeignKey('Tag', null=True, blank=True)
@@ -43,14 +43,15 @@ class Tag(models.Model):
def get_post_count(self):
return self.threads.count()
- def get_popularity(self):
- posts_with_tag = Post.objects.get_threads(tag=self)
- reply_count = 0
- for post in posts_with_tag:
- reply_count += post.get_reply_count()
- reply_count += OPENING_POST_POPULARITY_WEIGHT
-
- return reply_count
+ # TODO Reenable this method after migration
+ # def get_popularity(self):
+ # posts_with_tag = Thread.objects.get_threads(tag=self)
+ # reply_count = 0
+ # for post in posts_with_tag:
+ # reply_count += post.get_reply_count()
+ # reply_count += OPENING_POST_POPULARITY_WEIGHT
+ #
+ # return reply_count
def get_linked_tags(self):
tag_list = []
diff --git a/boards/static/css/md/base_page.css b/boards/static/css/md/base_page.css
--- a/boards/static/css/md/base_page.css
+++ b/boards/static/css/md/base_page.css
@@ -104,7 +104,7 @@ p {
border: solid 1px #888;
color: #fff;
padding: 10px;
- margin: 5;
+ margin: 5px;
}
.form-row {
diff --git a/boards/templates/boards/post.html b/boards/templates/boards/post.html
--- a/boards/templates/boards/post.html
+++ b/boards/templates/boards/post.html
@@ -55,10 +55,10 @@
{% endif %}
-{% if post.tags.exists %}
+{% if post.thread.tags.exists %}