diff options
author | Tomasz Zielinski <tomasz.zielinski@pyconsultant.eu> | 2011-11-26 15:17:56 +0100 |
---|---|---|
committer | Tomasz Zielinski <tomasz.zielinski@pyconsultant.eu> | 2011-11-26 15:17:56 +0100 |
commit | 892a224c14c6dc23f2ac987a4e6857abecca5d38 (patch) | |
tree | f4ed19a0788e199a176f2734dd348671324ec5bb | |
parent | 0eb019d50b0703c41d75afecb3fb5ede03628dd4 (diff) | |
download | askbot-892a224c14c6dc23f2ac987a4e6857abecca5d38.tar.gz askbot-892a224c14c6dc23f2ac987a4e6857abecca5d38.tar.bz2 askbot-892a224c14c6dc23f2ac987a4e6857abecca5d38.zip |
Moved all methods "shared" by Answer and Question models to Content
-rw-r--r-- | askbot/models/answer.py | 151 | ||||
-rw-r--r-- | askbot/models/content.py | 316 | ||||
-rw-r--r-- | askbot/models/question.py | 153 |
3 files changed, 323 insertions, 297 deletions
diff --git a/askbot/models/answer.py b/askbot/models/answer.py index 35701ff1..13b4884b 100644 --- a/askbot/models/answer.py +++ b/askbot/models/answer.py @@ -1,19 +1,8 @@ import datetime from django.db import models -from django.utils.http import urlquote as django_urlquote -from django.utils.translation import ugettext as _ -from django.core.urlresolvers import reverse -from django.core import exceptions as django_exceptions -from django.conf import settings -from askbot import exceptions -from askbot.models.base import AnonymousContent, DeletableContent -from askbot.models.post import PostRevision -from askbot.models.base import parse_post_text, parse_and_save_post +from askbot.models.base import AnonymousContent from askbot.models import content from askbot import const -from askbot.utils.slug import slugify -from askbot.utils import markup -from askbot.utils.html import sanitize_html class AnswerManager(models.Manager): def create_new( @@ -66,11 +55,12 @@ class AnswerManager(models.Manager): pass return answer - def get_author_list(self, **kwargs): - authors = set() - for answer in self: - authors.update(answer.get_author_list(**kwargs)) - return list(authors) + #todo: I think this method is not being used anymore, I'll just comment it for now +# def get_author_list(self, **kwargs): +# authors = set() +# for answer in self: +# authors.update(answer.get_author_list(**kwargs)) +# return list(authors) #todo: I think this method is not being used anymore, I'll just comment it for now #def get_answers_from_questions(self, user_id): @@ -94,133 +84,6 @@ class Answer(content.Content): is_anonymous = False #answers are never anonymous - may change - def assert_is_visible_to(self, user): - """raises QuestionHidden or AnswerHidden""" - try: - self.question.assert_is_visible_to(user) - except exceptions.QuestionHidden: - message = _( - 'Sorry, the answer you are looking for is ' - 'no longer available, because the parent ' - 'question has been removed' - ) - raise exceptions.QuestionHidden(message) - if self.deleted: - message = _( - 'Sorry, this answer has been ' - 'removed and is no longer accessible' - ) - if user.is_anonymous(): - raise exceptions.AnswerHidden(message) - try: - user.assert_can_see_deleted_post(self) - except django_exceptions.PermissionDenied: - raise exceptions.AnswerHidden(message) - - def get_updated_activity_data(self, created = False): - #todo: simplify this to always return latest revision for the second - #part - if created: - return const.TYPE_ACTIVITY_ANSWER, self - else: - latest_revision = self.get_latest_revision() - return const.TYPE_ACTIVITY_UPDATE_ANSWER, latest_revision - - def get_tag_names(self): - """return tag names on the question""" - return self.question.get_tag_names() - - def apply_edit(self, edited_at=None, edited_by=None, text=None, comment=None, wiki=False): - - if text is None: - text = self.get_latest_revision().text - if edited_at is None: - edited_at = datetime.datetime.now() - if edited_by is None: - raise Exception('edited_by is required') - - self.last_edited_at = edited_at - self.last_edited_by = edited_by - #self.html is denormalized in save() - self.text = text - #todo: bug wiki has no effect here - - #must add revision before saving the answer - self.add_revision( - author = edited_by, - revised_at = edited_at, - text = text, - comment = comment - ) - - self.parse_and_save(author = edited_by) - - self.question.last_activity_at = edited_at - self.question.last_activity_by = edited_by - self.question.save() - - - def add_revision(self, author=None, revised_at=None, text=None, comment=None): - #todo: this may be identical to Question.add_revision - if None in (author, revised_at, text): - raise Exception('arguments author, revised_at and text are required') - rev_no = self.revisions.all().count() + 1 - if comment in (None, ''): - if rev_no == 1: - comment = const.POST_STATUS['default_version'] - else: - comment = 'No.%s Revision' % rev_no - return PostRevision.objects.create_answer_revision( - answer=self, - author=author, - revised_at=revised_at, - text=text, - summary=comment, - revision=rev_no - ) - - def get_response_receivers(self, exclude_list = None): - """get list of users interested in this response - update based on their participation in the question - activity - - exclude_list is required and normally should contain - author of the updated so that he/she is not notified of - the response - """ - assert(exclude_list is not None) - recipients = set() - recipients.update( - self.get_author_list( - include_comments = True - ) - ) - recipients.update( - self.question.get_author_list( - include_comments = True - ) - ) - for answer in self.question.answers.all(): - recipients.update(answer.get_author_list()) - - recipients -= set(exclude_list) - - return list(recipients) - - def get_question_title(self): - return self.question.title - - def get_absolute_url(self): - return u'%(base)s%(slug)s?answer=%(id)d#answer-container-%(id)d' % \ - { - 'base': reverse('question', args=[self.question.id]), - 'slug': django_urlquote(slugify(self.question.title)), - 'id': self.id - } - - def __unicode__(self): - return self.html - class AnonymousAnswer(AnonymousContent): question = models.ForeignKey('Question', related_name='anonymous_answers') diff --git a/askbot/models/content.py b/askbot/models/content.py index 56c7b6aa..f2645cc2 100644 --- a/askbot/models/content.py +++ b/askbot/models/content.py @@ -3,15 +3,23 @@ from django.conf import settings from django.contrib.auth.models import User from django.contrib.contenttypes import generic from django.contrib.contenttypes.models import ContentType +from django.core import urlresolvers from django.db import models from django.utils import html as html_utils from django.utils.datastructures import SortedDict +from django.utils.translation import ugettext as _ +from django.utils.http import urlquote as django_urlquote +from django.core import exceptions as django_exceptions + +from askbot.utils.slug import slugify from askbot import const from askbot.models.meta import Comment, Vote from askbot.models.user import EmailFeedSetting from askbot.models.tag import Tag, MarkedTag, tags_match_some_wildcard +from askbot.models.post import PostRevision from askbot.models.base import parse_post_text, parse_and_save_post from askbot.conf import settings as askbot_settings +from askbot import exceptions class Content(models.Model): """ @@ -57,6 +65,30 @@ class Content(models.Model): parse = parse_post_text parse_and_save = parse_and_save_post + def __unicode__(self): + if self.is_question(): + return self.title + elif self.is_answer(): + return self.html + raise NotImplementedError + + def get_absolute_url(self, no_slug = False): + if self.is_answer(): + return u'%(base)s%(slug)s?answer=%(id)d#answer-container-%(id)d' % \ + { + 'base': urlresolvers.reverse('question', args=[self.question.id]), + 'slug': django_urlquote(slugify(self.question.title)), + 'id': self.id + } + elif self.is_question(): + url = urlresolvers.reverse('question', args=[self.id]) + if no_slug == True: + return url + else: + return url + django_urlquote(self.slug) + raise NotImplementedError + + def is_answer(self): return self.post_type == 'answer' @@ -508,3 +540,287 @@ class Content(models.Model): return votes[0] else: return None + + + def _question__assert_is_visible_to(self, user): + """raises QuestionHidden""" + if self.deleted: + message = _( + 'Sorry, this question has been ' + 'deleted and is no longer accessible' + ) + if user.is_anonymous(): + raise exceptions.QuestionHidden(message) + try: + user.assert_can_see_deleted_post(self) + except django_exceptions.PermissionDenied: + raise exceptions.QuestionHidden(message) + + def _answer__assert_is_visible_to(self, user): + """raises QuestionHidden or AnswerHidden""" + try: + self.question.assert_is_visible_to(user) + except exceptions.QuestionHidden: + message = _( + 'Sorry, the answer you are looking for is ' + 'no longer available, because the parent ' + 'question has been removed' + ) + raise exceptions.QuestionHidden(message) + if self.deleted: + message = _( + 'Sorry, this answer has been ' + 'removed and is no longer accessible' + ) + if user.is_anonymous(): + raise exceptions.AnswerHidden(message) + try: + user.assert_can_see_deleted_post(self) + except django_exceptions.PermissionDenied: + raise exceptions.AnswerHidden(message) + + def assert_is_visible_to(self, user): + if self.is_question(): + return self._question__assert_is_visible_to(user) + elif self.is_answer(): + return self._answer__assert_is_visible_to(user) + raise NotImplementedError + + def get_updated_activity_data(self, created = False): + if self.is_answer(): + #todo: simplify this to always return latest revision for the second + #part + if created: + return const.TYPE_ACTIVITY_ANSWER, self + else: + latest_revision = self.get_latest_revision() + return const.TYPE_ACTIVITY_UPDATE_ANSWER, latest_revision + elif self.is_question(): + if created: + return const.TYPE_ACTIVITY_ASK_QUESTION, self + else: + latest_revision = self.get_latest_revision() + return const.TYPE_ACTIVITY_UPDATE_QUESTION, latest_revision + raise NotImplementedError + + def get_tag_names(self): + if self.is_question(): + """Creates a list of Tag names from the ``tagnames`` attribute.""" + return self.tagnames.split(u' ') + elif self.is_answer(): + """return tag names on the question""" + return self.question.get_tag_names() + raise NotImplementedError + + + def _answer__apply_edit(self, edited_at=None, edited_by=None, text=None, comment=None, wiki=False): + + if text is None: + text = self.get_latest_revision().text + if edited_at is None: + edited_at = datetime.datetime.now() + if edited_by is None: + raise Exception('edited_by is required') + + self.last_edited_at = edited_at + self.last_edited_by = edited_by + #self.html is denormalized in save() + self.text = text + #todo: bug wiki has no effect here + + #must add revision before saving the answer + self.add_revision( + author = edited_by, + revised_at = edited_at, + text = text, + comment = comment + ) + + self.parse_and_save(author = edited_by) + + self.question.last_activity_at = edited_at + self.question.last_activity_by = edited_by + self.question.save() + + def _question__apply_edit(self, edited_at=None, edited_by=None, title=None,\ + text=None, comment=None, tags=None, wiki=False, \ + edit_anonymously = False): + + latest_revision = self.get_latest_revision() + #a hack to allow partial edits - important for SE loader + if title is None: + title = self.title + if text is None: + text = latest_revision.text + if tags is None: + tags = latest_revision.tagnames + + if edited_by is None: + raise Exception('parameter edited_by is required') + + if edited_at is None: + edited_at = datetime.datetime.now() + + # Update the Question itself + self.title = title + self.last_edited_at = edited_at + self.last_activity_at = edited_at + self.last_edited_by = edited_by + self.last_activity_by = edited_by + self.tagnames = tags + self.text = text + self.is_anonymous = edit_anonymously + + #wiki is an eternal trap whence there is no exit + if self.wiki == False and wiki == True: + self.wiki = True + + # Update the Question tag associations + if latest_revision.tagnames != tags: + self.update_tags(tagnames = tags, user = edited_by, timestamp = edited_at) + + # Create a new revision + self.add_revision( + author = edited_by, + text = text, + revised_at = edited_at, + is_anonymous = edit_anonymously, + comment = comment, + ) + + self.parse_and_save(author = edited_by) + + def apply_edit(self, *kargs, **kwargs): + if self.is_answer(): + return self._answer__apply_edit(*kargs, **kwargs) + elif self.is_question(): + return self._question__apply_edit(*kargs, **kwargs) + raise NotImplementedError + + def _answer__add_revision(self, author=None, revised_at=None, text=None, comment=None): + #todo: this may be identical to Question.add_revision + if None in (author, revised_at, text): + raise Exception('arguments author, revised_at and text are required') + rev_no = self.revisions.all().count() + 1 + if comment in (None, ''): + if rev_no == 1: + comment = const.POST_STATUS['default_version'] + else: + comment = 'No.%s Revision' % rev_no + return PostRevision.objects.create_answer_revision( + answer=self, + author=author, + revised_at=revised_at, + text=text, + summary=comment, + revision=rev_no + ) + + def _question__add_revision( + self, + author = None, + is_anonymous = False, + text = None, + comment = None, + revised_at = None + ): + if None in (author, text, comment): + raise Exception('author, text and comment are required arguments') + rev_no = self.revisions.all().count() + 1 + if comment in (None, ''): + if rev_no == 1: + comment = const.POST_STATUS['default_version'] + else: + comment = 'No.%s Revision' % rev_no + + return PostRevision.objects.create_question_revision( + question = self, + revision = rev_no, + title = self.title, + author = author, + is_anonymous = is_anonymous, + revised_at = revised_at, + tagnames = self.tagnames, + summary = comment, + text = text + ) + + def add_revision(self, *kargs, **kwargs): + if self.is_answer(): + return self._answer__add_revision(*kargs, **kwargs) + elif self.is_question(): + return self._question__add_revision(*kargs, **kwargs) + raise NotImplementedError + + def _answer__get_response_receivers(self, exclude_list = None): + """get list of users interested in this response + update based on their participation in the question + activity + + exclude_list is required and normally should contain + author of the updated so that he/she is not notified of + the response + """ + assert(exclude_list is not None) + recipients = set() + recipients.update( + self.get_author_list( + include_comments = True + ) + ) + recipients.update( + self.question.get_author_list( + include_comments = True + ) + ) + for answer in self.question.answers.all(): + recipients.update(answer.get_author_list()) + + recipients -= set(exclude_list) + + return list(recipients) + + def _question__get_response_receivers(self, exclude_list = None): + """returns list of users who might be interested + in the question update based on their participation + in the question activity + + exclude_list is mandatory - it normally should have the + author of the update so the he/she is not notified about the update + """ + assert(exclude_list != None) + recipients = set() + recipients.update( + self.get_author_list( + include_comments = True + ) + ) + #do not include answer commenters here + for a in self.answers.all(): + recipients.update(a.get_author_list()) + + recipients -= set(exclude_list) + return recipients + + def get_response_receivers(self, exclude_list = None): + if self.is_answer(): + return self._answer__get_response_receivers(exclude_list) + elif self.is_question(): + return self._question__get_response_receivers(exclude_list) + raise NotImplementedError + + def get_question_title(self): + if self.is_answer(): + return self.question.title + elif self.is_question(): + if self.closed: + attr = const.POST_STATUS['closed'] + elif self.deleted: + attr = const.POST_STATUS['deleted'] + else: + attr = None + if attr is not None: + return u'%s %s' % (self.title, attr) + else: + return self.title + raise NotImplementedError diff --git a/askbot/models/question.py b/askbot/models/question.py index 3f3e62c1..4d42f912 100644 --- a/askbot/models/question.py +++ b/askbot/models/question.py @@ -4,21 +4,14 @@ from django.conf import settings from django.utils.datastructures import SortedDict from django.db import models from django.contrib.auth.models import User -from django.utils.http import urlquote as django_urlquote -from django.core.urlresolvers import reverse -from django.core import exceptions as django_exceptions from django.contrib.sitemaps import ping_google from django.utils.translation import ugettext as _ import askbot import askbot.conf -from askbot import exceptions from askbot.models.tag import Tag from askbot.models.base import AnonymousContent -from askbot.models.base import DeletableContent from askbot.models.post import PostRevision from askbot.models.base import BaseQuerySetManager -from askbot.models.base import parse_post_text -from askbot.models.base import parse_and_save_post from askbot.models import content from askbot.models import signals from askbot import const @@ -482,20 +475,6 @@ class Question(content.Content): class Meta(content.Content.Meta): db_table = u'question' - def assert_is_visible_to(self, user): - """raises QuestionHidden""" - if self.deleted: - message = _( - 'Sorry, this question has been ' - 'deleted and is no longer accessible' - ) - if user.is_anonymous(): - raise exceptions.QuestionHidden(message) - try: - user.assert_can_see_deleted_post(self) - except django_exceptions.PermissionDenied: - raise exceptions.QuestionHidden(message) - def remove_author_anonymity(self): """removes anonymous flag from the question and all its revisions @@ -702,35 +681,6 @@ class Question(content.Content): | models.Q(deleted_by = user) ) - def get_updated_activity_data(self, created = False): - if created: - return const.TYPE_ACTIVITY_ASK_QUESTION, self - else: - latest_revision = self.get_latest_revision() - return const.TYPE_ACTIVITY_UPDATE_QUESTION, latest_revision - - def get_response_receivers(self, exclude_list = None): - """returns list of users who might be interested - in the question update based on their participation - in the question activity - - exclude_list is mandatory - it normally should have the - author of the update so the he/she is not notified about the update - """ - assert(exclude_list != None) - recipients = set() - recipients.update( - self.get_author_list( - include_comments = True - ) - ) - #do not include answer commenters here - for a in self.answers.all(): - recipients.update(a.get_author_list()) - - recipients -= set(exclude_list) - return recipients - def retag(self, retagged_by=None, retagged_at=None, tagnames=None, silent=False): if None in (retagged_by, retagged_at, tagnames): raise Exception('arguments retagged_at, retagged_by and tagnames are required') @@ -758,87 +708,6 @@ class Question(content.Content): text = latest_revision.text ) - def apply_edit(self, edited_at=None, edited_by=None, title=None,\ - text=None, comment=None, tags=None, wiki=False, \ - edit_anonymously = False): - - latest_revision = self.get_latest_revision() - #a hack to allow partial edits - important for SE loader - if title is None: - title = self.title - if text is None: - text = latest_revision.text - if tags is None: - tags = latest_revision.tagnames - - if edited_by is None: - raise Exception('parameter edited_by is required') - - if edited_at is None: - edited_at = datetime.datetime.now() - - # Update the Question itself - self.title = title - self.last_edited_at = edited_at - self.last_activity_at = edited_at - self.last_edited_by = edited_by - self.last_activity_by = edited_by - self.tagnames = tags - self.text = text - self.is_anonymous = edit_anonymously - - #wiki is an eternal trap whence there is no exit - if self.wiki == False and wiki == True: - self.wiki = True - - # Update the Question tag associations - if latest_revision.tagnames != tags: - self.update_tags(tagnames = tags, user = edited_by, timestamp = edited_at) - - # Create a new revision - self.add_revision( - author = edited_by, - text = text, - revised_at = edited_at, - is_anonymous = edit_anonymously, - comment = comment, - ) - - self.parse_and_save(author = edited_by) - - def add_revision( - self, - author = None, - is_anonymous = False, - text = None, - comment = None, - revised_at = None - ): - if None in (author, text, comment): - raise Exception('author, text and comment are required arguments') - rev_no = self.revisions.all().count() + 1 - if comment in (None, ''): - if rev_no == 1: - comment = const.POST_STATUS['default_version'] - else: - comment = 'No.%s Revision' % rev_no - - return PostRevision.objects.create_question_revision( - question = self, - revision = rev_no, - title = self.title, - author = author, - is_anonymous = is_anonymous, - revised_at = revised_at, - tagnames = self.tagnames, - summary = comment, - text = text - ) - - def get_tag_names(self): - """Creates a list of Tag names from the ``tagnames`` attribute.""" - return self.tagnames.split(u' ') - def set_tag_names(self, tag_names): """expects some iterable of unicode string tag names joins the names with a space and assigns to self.tagnames @@ -846,13 +715,6 @@ class Question(content.Content): """ self.tagnames = u' '.join(tag_names) - def get_absolute_url(self, no_slug = False): - url = reverse('question', args=[self.id]) - if no_slug == True: - return url - else: - return url + django_urlquote(self.slug) - def _get_slug(self): return slugify(self.title) @@ -864,18 +726,6 @@ class Question(content.Content): return FavoriteQuestion.objects.filter(question=self, user=user).count() > 0 - def get_question_title(self): - if self.closed: - attr = const.POST_STATUS['closed'] - elif self.deleted: - attr = const.POST_STATUS['deleted'] - else: - attr = None - if attr is not None: - return u'%s %s' % (self.title, attr) - else: - return self.title - def get_last_update_info(self): when, who = self.post_get_last_update_info() @@ -946,9 +796,6 @@ class Question(content.Content): else: return None - def __unicode__(self): - return self.title - if getattr(settings, 'USE_SPHINX_SEARCH', False): from djangosphinx.models import SphinxSearch Question.add_to_class( |