diff options
-rw-r--r-- | askbot/migrations/0050_move_qa_revisions_to_postrevision.py | 28 | ||||
-rw-r--r-- | askbot/models/post.py | 27 | ||||
-rw-r--r-- | askbot/tests/__init__.py | 2 | ||||
-rw-r--r-- | askbot/tests/misc_tests.py | 50 | ||||
-rw-r--r-- | askbot/tests/page_load_tests.py | 28 | ||||
-rw-r--r-- | askbot/tests/post_model_tests.py | 55 |
6 files changed, 174 insertions, 16 deletions
diff --git a/askbot/migrations/0050_move_qa_revisions_to_postrevision.py b/askbot/migrations/0050_move_qa_revisions_to_postrevision.py index 3067a87c..2ba427bb 100644 --- a/askbot/migrations/0050_move_qa_revisions_to_postrevision.py +++ b/askbot/migrations/0050_move_qa_revisions_to_postrevision.py @@ -1,8 +1,11 @@ # encoding: utf-8 import datetime + +from django.contrib.contenttypes import generic +from django.db import models + from south.db import db from south.v2 import DataMigration -from django.db import models class Migration(DataMigration): @@ -16,7 +19,7 @@ class Migration(DataMigration): if (question and source_revision.revision_type != 1) or (answer and source_revision.revision_type != 2): raise ValueError('Data problem! Check this manually') - orm.PostRevision.objects.create( + post_revision = orm.PostRevision.objects.create( question=question, answer=answer, @@ -33,17 +36,30 @@ class Migration(DataMigration): is_anonymous=source_revision.is_anonymous ) + # Update the related activities + for activity in source_revision.activity_set.all(): + activity.content_object = post_revision + activity.save() + + def forwards(self, orm): + # Set up generic links + gfk = generic.GenericForeignKey('content_type', 'object_id') + gfk.contribute_to_class(orm.Activity, 'content_object') + + gr1 = generic.GenericRelation(orm.Activity) + gr1.contribute_to_class(orm.QuestionRevision, 'activity_set') + + gr2 = generic.GenericRelation(orm.Activity) + gr2.contribute_to_class(orm.AnswerRevision, 'activity_set') + + # Process revisions for qr in orm.QuestionRevision.objects.all(): self.copy_revision(orm=orm, source_revision=qr) for ar in orm.AnswerRevision.objects.all(): self.copy_revision(orm=orm, source_revision=ar) - # TODO: - # In the next migration (0050) QuestionRevision and AnswerRevision tables are dropped. - # So if there is anything else to migrate here, we have to figure that out before merging this to trunk. - def backwards(self, orm): "Write your backwards methods here." diff --git a/askbot/models/post.py b/askbot/models/post.py index c61e8877..343ffd87 100644 --- a/askbot/models/post.py +++ b/askbot/models/post.py @@ -1,4 +1,5 @@ from django.db import models +from django.core.exceptions import ValidationError from askbot.utils import markup from askbot.utils.html import sanitize_html @@ -7,13 +8,19 @@ from askbot.utils.html import sanitize_html # pass class PostRevisionManager(models.Manager): + # TODO: Make sure this manager /with the "blocked" .create() method/ is used also as a `related` manager: + # - https://docs.djangoproject.com/en/1.3/topics/db/managers/#controlling-automatic-manager-types + # - use_for_related_fields + 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 self.create(*kargs, **kwargs) + return super(PostRevisionManager, self).create(*kargs, **kwargs) def create_answer_revision(self, *kargs, **kwargs): kwargs['revision_type'] = self.model.ANSWER_REVISION - return self.create(*kargs, **kwargs) + return super(PostRevisionManager, self).create(*kargs, **kwargs) def question_revisions(self): return self.filter(revision_type=self.model.QUESTION_REVISION) @@ -74,15 +81,21 @@ class PostRevision(models.Model): 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.""" + 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? - # TODO: Handle IntegrityError if revision id is already occupied? + # TODO: Maybe use Max() aggregation? Or `revisions.count() + 1` 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 + # 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) diff --git a/askbot/tests/__init__.py b/askbot/tests/__init__.py index b06c2b06..a9fa761b 100644 --- a/askbot/tests/__init__.py +++ b/askbot/tests/__init__.py @@ -11,3 +11,5 @@ from askbot.tests.form_tests import * from askbot.tests.follow_tests import * from askbot.tests.templatefilter_tests import * from askbot.tests.markup_test import * +from askbot.tests.misc_tests import * +from askbot.tests.post_model_tests import * diff --git a/askbot/tests/misc_tests.py b/askbot/tests/misc_tests.py new file mode 100644 index 00000000..ddf16360 --- /dev/null +++ b/askbot/tests/misc_tests.py @@ -0,0 +1,50 @@ +import datetime +from django.contrib.contenttypes.models import ContentType +from django.test.client import Client +from askbot.tests.utils import AskbotTestCase +from askbot.conf import settings +from askbot import models +from askbot.models.badges import award_badges_signal + +from askbot.views.users import get_related_object_type_name + +class MiscTests(AskbotTestCase): + + def setUp(self): + self.u1 = self.create_user(username='user1') + self.u2 = self.create_user(username='user2') + self.u3 = self.create_user(username='user3') + + def test_get_related_object_type_name_for_question(self): + question = self.post_question(user=self.u1) + ct = ContentType.objects.get_for_model(question) + self.assertEqual('question', get_related_object_type_name(ct.id, question.id)) + + def test_get_related_object_type_name_for_question_revision(self): + question = self.post_question(user=self.u1) + revision = question.revisions.all()[0] + ct = ContentType.objects.get_for_model(revision) + self.assertEqual('question', get_related_object_type_name(ct.id, revision.id)) + + def test_get_related_object_type_name_for_answer(self): + question = self.post_question(user=self.u1) + answer = self.post_answer(user=self.u1, question=question) + ct = ContentType.objects.get_for_model(answer) + self.assertEqual('answer', get_related_object_type_name(ct.id, answer.id)) + + def test_get_related_object_type_name_for_answer_revision(self): + question = self.post_question(user=self.u1) + answer = self.post_answer(user=self.u1, question=question) + revision = answer.revisions.all()[0] + ct = ContentType.objects.get_for_model(revision) + self.assertEqual('answer', get_related_object_type_name(ct.id, revision.id)) + + def test_get_related_object_type_name_for_anything_else_1(self): + ct = ContentType.objects.get_for_model(self.u2) + self.assertIsNone(get_related_object_type_name(ct.id, self.u2.id)) + + def test_get_related_object_type_name_for_anything_else_2(self): + question = self.post_question(user=self.u1) + comment = self.post_comment(user=self.u1, parent_post=question) + ct = ContentType.objects.get_for_model(comment) + self.assertIsNone(get_related_object_type_name(ct.id, comment.id)) diff --git a/askbot/tests/page_load_tests.py b/askbot/tests/page_load_tests.py index 9c107112..442b1bd7 100644 --- a/askbot/tests/page_load_tests.py +++ b/askbot/tests/page_load_tests.py @@ -25,9 +25,10 @@ def patch_jinja2(): (CMAJOR, CMINOR, CMICRO) = package_utils.get_coffin_version() if CMAJOR == 0 and CMINOR == 3 and CMICRO < 4: + import ipdb; ipdb.set_trace() patch_jinja2() -class PageLoadTestCase(TestCase): +class PageLoadTestCase(AskbotTestCase): def try_url( self, url_name, status_code=200, template=None, @@ -66,8 +67,29 @@ class PageLoadTestCase(TestCase): else: raise Exception('unexpected error while runnig test') -class PageLoadTests(PageLoadTestCase): - fixtures = ['tmp/fixture2.json', ] + def setUp(self): + self.u1 = self.create_user(username='user1') + self.u2 = self.create_user(username='user2') + self.u3 = self.create_user(username='user3') + + self.question = self.post_question(user=self.u1) + + self.answer = self.post_answer(user=self.u1, question=self.question) + self.answer.id = 38 # one of the tests tries this id + self.answer.save() + + self.question2 = self.post_question(user=self.u2) + self.question2.id = 2 + self.question2.save() + + self.question3 = self.post_question(user=self.u3) + self.question3.id = 3 + self.question3.save() + + self.question17 = self.post_question(user=self.u1) + self.question17.id = 17 + self.question17.save() + def test_index(self): #todo: merge this with all reader url tests diff --git a/askbot/tests/post_model_tests.py b/askbot/tests/post_model_tests.py new file mode 100644 index 00000000..7ea8621a --- /dev/null +++ b/askbot/tests/post_model_tests.py @@ -0,0 +1,55 @@ +import datetime + +from django.core.exceptions import ValidationError +from askbot.tests.utils import AskbotTestCase +from askbot.models import PostRevision + + +class PostModelTests(AskbotTestCase): + + def setUp(self): + self.u1 = self.create_user(username='user1') + self.u2 = self.create_user(username='user2') + self.u3 = self.create_user(username='user3') + + def test_model_validation(self): + with self.assertRaises(NotImplementedError): + PostRevision.objects.create(text='blah', author=self.u1, revised_at=datetime.datetime.now(), revision_type=PostRevision.QUESTION_REVISION) + + with self.assertRaisesRegexp(AttributeError, r"'NoneType' object has no attribute 'revisions'"): + # cannot set `revision` without a parent + PostRevision.objects.create_answer_revision(text='blah', author=self.u1, revised_at=datetime.datetime.now()) + + with self.assertRaisesRegexp(ValidationError, r"{'__all__': \[u'One \(and only one\) of question/answer fields has to be set.'\], 'revision_type': \[u'Value 4 is not a valid choice.'\]}"): + # revision_type not in (1,2) + PostRevision(text='blah', author=self.u1, revised_at=datetime.datetime.now(), revision=1, revision_type=4).save() + + question = self.post_question(user=self.u1) + + rev2 = PostRevision(question=question, text='blah', author=self.u1, revised_at=datetime.datetime.now(), revision=2, revision_type=PostRevision.QUESTION_REVISION) + rev2.save() + self.assertIsNotNone(rev2.id) + + with self.assertRaisesRegexp(ValidationError, r"{'__all__': \[u'Revision_type doesn`t match values in question/answer fields.', u'Post revision with this Question and Revision already exists.'\]}"): + PostRevision(question=question, text='blah', author=self.u1, revised_at=datetime.datetime.now(), revision=2, revision_type=PostRevision.ANSWER_REVISION).save() + + with self.assertRaisesRegexp(ValidationError, r"{'__all__': \[u'Revision_type doesn`t match values in question/answer fields.'\]}"): + PostRevision(question=question, text='blah', author=self.u1, revised_at=datetime.datetime.now(), revision=3, revision_type=PostRevision.ANSWER_REVISION).save() + + rev3 = PostRevision.objects.create_question_revision(question=question, text='blah', author=self.u1, revised_at=datetime.datetime.now(), revision_type=123) # revision_type + self.assertIsNotNone(rev3.id) + self.assertEqual(3, rev3.revision) # By the way: let's test the auto-increase of revision number + self.assertEqual(PostRevision.QUESTION_REVISION, rev3.revision_type) + + def test_post_revision_autoincrease(self): + question = self.post_question(user=self.u1) + self.assertEqual(1, question.revisions.all()[0].revision) + self.assertEqual(1, question.revisions.count()) + + question.apply_edit(edited_by=self.u1, text="blah2", comment="blahc2") + self.assertEqual(2, question.revisions.all()[0].revision) + self.assertEqual(2, question.revisions.count()) + + question.apply_edit(edited_by=self.u1, text="blah3", comment="blahc3") + self.assertEqual(3, question.revisions.all()[0].revision) + self.assertEqual(3, question.revisions.count()) |