summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Zielinski <tomasz.zielinski@pyconsultant.eu>2011-11-26 15:17:56 +0100
committerTomasz Zielinski <tomasz.zielinski@pyconsultant.eu>2011-11-26 15:17:56 +0100
commit892a224c14c6dc23f2ac987a4e6857abecca5d38 (patch)
treef4ed19a0788e199a176f2734dd348671324ec5bb
parent0eb019d50b0703c41d75afecb3fb5ede03628dd4 (diff)
downloadaskbot-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.py151
-rw-r--r--askbot/models/content.py316
-rw-r--r--askbot/models/question.py153
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(