summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-12-10 03:21:56 -0500
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-12-10 03:21:56 -0500
commit73efdec429ffa9fbf4b19d75dd719c8dbcd94d60 (patch)
treeec77d0c4be957629a4b159780e386621a667a283
parent39309f87bb6bce560e4060be280db9eb2551ac16 (diff)
downloadaskbot-73efdec429ffa9fbf4b19d75dd719c8dbcd94d60.tar.gz
askbot-73efdec429ffa9fbf4b19d75dd719c8dbcd94d60.tar.bz2
askbot-73efdec429ffa9fbf4b19d75dd719c8dbcd94d60.zip
finished permalinks
-rw-r--r--askbot/exceptions.py9
-rw-r--r--askbot/models/__init__.py2
-rw-r--r--askbot/models/answer.py28
-rw-r--r--askbot/models/meta.py21
-rw-r--r--askbot/models/question.py16
-rw-r--r--askbot/skins/default/templates/question.html4
-rw-r--r--askbot/views/readers.py122
7 files changed, 137 insertions, 65 deletions
diff --git a/askbot/exceptions.py b/askbot/exceptions.py
index ed60cc8a..a1d76a67 100644
--- a/askbot/exceptions.py
+++ b/askbot/exceptions.py
@@ -27,3 +27,12 @@ class EmailNotSent(exceptions.ImproperlyConfigured):
"""
pass
+class QuestionHidden(exceptions.PermissionDenied):
+ """raised when user cannot see deleted question
+ """
+ pass
+
+class AnswerHidden(exceptions.PermissionDenied):
+ """raised when user cannot see deleted answer
+ """
+ pass
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
index 722b4164..098271e0 100644
--- a/askbot/models/__init__.py
+++ b/askbot/models/__init__.py
@@ -348,7 +348,7 @@ def user_assert_can_see_deleted_post(self, post = None):
error_message = _(
'This post has been deleted and can be seen only '
- 'by post ownwers, site administrators and moderators'
+ 'by post owners, site administrators and moderators'
)
_assert_user_can(
user = self,
diff --git a/askbot/models/answer.py b/askbot/models/answer.py
index b466fd2c..885b0e73 100644
--- a/askbot/models/answer.py
+++ b/askbot/models/answer.py
@@ -1,8 +1,11 @@
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.base import ContentRevision
from askbot.models.base import parse_post_text, parse_and_save_post
@@ -93,6 +96,29 @@ class Answer(content.Content, DeletableContent):
parse = parse_post_text
parse_and_save = parse_and_save_post
+ 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
@@ -164,7 +190,7 @@ class Answer(content.Content, DeletableContent):
paginated. This function returns number of the page
on which the answer will be shown, using the default
sort order. The result may depend on the visitor."""
- order_number = 1
+ order_number = 0
for answer in answers:
if self == answer:
break
diff --git a/askbot/models/meta.py b/askbot/models/meta.py
index 59eeae0b..392cce24 100644
--- a/askbot/models/meta.py
+++ b/askbot/models/meta.py
@@ -2,7 +2,9 @@ import datetime
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils import html as html_utils
+from django.utils.translation import ugettext as _
from askbot import const
+from askbot import exceptions
from askbot.models import base
from askbot.models.user import EmailFeedSetting
@@ -99,6 +101,25 @@ class Comment(base.MetaContent, base.UserContent):
parse = base.parse_post_text
parse_and_save = base.parse_and_save_post
+ def assert_is_visible_to(self, user):
+ """raises QuestionHidden or AnswerHidden"""
+ try:
+ self.content_object.assert_is_visible_to(user)
+ except exceptions.QuestionHidden:
+ message = _(
+ 'Sorry, the comment you are looking for is no '
+ 'longer accessible, because the parent question '
+ 'has been removed'
+ )
+ raise exceptions.QuestionHidden(message)
+ except exceptions.AnswerHidden:
+ message = _(
+ 'Sorry, the comment you are looking for is no '
+ 'longer accessible, because the parent answer '
+ 'has been removed'
+ )
+ raise exceptions.AnswerHidden(message)
+
def get_origin_post(self):
return self.content_object.get_origin_post()
diff --git a/askbot/models/question.py b/askbot/models/question.py
index 9afbf8e7..d8d60c6e 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -7,10 +7,12 @@ 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, MarkedTag
from askbot.models.base import AnonymousContent, DeletableContent, ContentRevision
from askbot.models.base import parse_post_text, parse_and_save_post
@@ -316,6 +318,20 @@ class Question(content.Content, DeletableContent):
parse = parse_post_text
parse_and_save = parse_and_save_post
+ 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 update_answer_count(self, save = True):
"""updates the denormalized field 'answer_count'
on the question
diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html
index 740ca999..4ba93263 100644
--- a/askbot/skins/default/templates/question.html
+++ b/askbot/skins/default/templates/question.html
@@ -118,7 +118,7 @@
</span>
{% endif %}
{% if request.user|can_delete_post(question) %}{{ pipe() }}
- <a id="question-delete-link-{{question.id}}">{% trans %}delete{% endtrans %}</a>
+ <a id="question-delete-link-{{question.id}}">{% if question.deleted %}{% trans %}undelete{% endtrans %}{% else %}{% trans %}delete{% endtrans %}{% endif %}</a>
{% endif %}
</div>
</div>
@@ -241,7 +241,7 @@
{% set pipe=joiner('<span class="sep">|</span>') %}
<span class="linksopt">{{ pipe() }}
<a
- href="#{{ answer.id }}"
+ href="{{ answer.get_absolute_url() }}"
title="{% trans %}answer permanent link{% endtrans %}">
{% trans %}permanent link{% endtrans %}
</a>
diff --git a/askbot/views/readers.py b/askbot/views/readers.py
index 317b0805..6fb2fd43 100644
--- a/askbot/views/readers.py
+++ b/askbot/views/readers.py
@@ -27,6 +27,7 @@ from django.core import exceptions as django_exceptions
from django.contrib.humanize.templatetags import humanize
import askbot
+from askbot import exceptions
from askbot.utils.html import sanitize_html
#from lxml.html.diff import htmldiff
from askbot.utils.diff import textDiff as htmldiff
@@ -392,8 +393,6 @@ def question(request, id):#refactor - long subroutine. display question body, an
"""view that displays body of the question and
all answers to it
"""
- question = get_object_or_404(models.Question, id=id)
-
#todo: fix inheritance of sort method from questions
default_sort_method = request.session.get('questions_sort_method', 'votes')
form = ShowQuestionForm(request.GET, default_sort_method)
@@ -404,10 +403,59 @@ def question(request, id):#refactor - long subroutine. display question body, an
is_permalink = form.cleaned_data['is_permalink']
answer_sort_method = form.cleaned_data['answer_sort_method']
- #redirect if slug in the url is wrong
+ #resolve comment and answer permalinks
+ #they go first because in theory both can be moved to another question
+ #this block "returns" show_post and assigns actual comment and answer
+ #to show_comment and show_answer variables
+ #in the case if the permalinked items or their parents are gone - redirect
+ #redirect also happens if id of the object's origin post != requested id
+ show_post = None #used for permalinks
+ #import pdb
+ #pdb.set_trace()
+ if show_comment is not None:
+ #comments
+ try:
+ show_comment = models.Comment.objects.get(id = show_comment)
+ if str(show_comment.get_origin_post().id) != id:
+ return HttpResponseRedirect(show_comment.get_absolute_url())
+ show_post = show_comment.content_object
+ show_comment.assert_is_visible_to(request.user)
+ except models.Comment.DoesNotExist:
+ error_message = _(
+ 'Sorry, the comment you are looking for has been '
+ 'deleted and is no longer accessible'
+ )
+ request.user.message_set.create(message = error_message)
+ return HttpResponseRedirect(reverse('question', kwargs = {'id': id}))
+ except exceptions.AnswerHidden, error:
+ request.user.message_set.create(message = unicode(error))
+ #use reverse function here because question is not yet loaded
+ return HttpResponseRedirect(reverse('question', kwargs = {'id': id}))
+ except exceptions.QuestionHidden, error:
+ request.user.message_set.create(message = unicode(error))
+ return HttpResponseRedirect(reverse('index'))
+
+ elif show_answer is not None:
+ #answers
+ try:
+ show_post = get_object_or_404(models.Answer, id = show_answer)
+ if str(show_post.question.id) != id:
+ return HttpResponseRedirect(show_post.get_absolute_url())
+ show_post.assert_is_visible_to(request.user)
+ except django_exceptions.PermissionDenied, error:
+ request.user.message_set.create(message = unicode(error))
+ return HttpResponseRedirect(reverse('question', kwargs = {'id': id}))
+
+ #load question and maybe refuse showing deleted question
try:
- assert(request.path == question.get_absolute_url())
- except AssertionError:
+ question = get_object_or_404(models.Question, id=id)
+ question.assert_is_visible_to(request.user)
+ except exceptions.QuestionHidden, error:
+ request.user.message_set.create(message = unicode(error))
+ return HttpResponseRedirect(reverse('index'))
+
+ #redirect if slug in the url is wrong
+ if request.path != question.get_absolute_url():
logging.debug('no slug match!')
question_url = '?'.join((
question.get_absolute_url(),
@@ -415,19 +463,6 @@ def question(request, id):#refactor - long subroutine. display question body, an
))
return HttpResponseRedirect(question_url)
- #maybe refuse showing deleted question
- if question.deleted:
- try:
- if request.user.is_anonymous():
- msg = _(
- 'Sorry, this question has been '
- 'deleted and is no longer accessible'
- )
- raise django_exceptions.PermissionDenied(msg)
- request.user.assert_can_see_deleted_post(question)
- except django_exceptions.PermissionDenied, e:
- request.user.message_set.create(message = unicode(e))
- return HttpResponseRedirect(reverse('index'))
logging.debug('answer_sort_method=' + unicode(answer_sort_method))
#load answers
@@ -456,52 +491,17 @@ def question(request, id):#refactor - long subroutine. display question body, an
else:
filtered_answers.append(answer)
- #modify variables to handle permalinks to comments and answers
- linked_post_deleted = False
- missing_answer_message = _(
- 'Sorry, this answer has been '
- 'deleted and is no longer accessible'
- )
- show_post = None
+ #resolve page number and comment number for permalinks
comment_order_number = None
- if show_comment is not None:
- #comments
- try:
- show_comment = models.Comment.objects.get(id = show_comment)
- if show_comment.get_origin_post() != question:
- return HttpResponseRedirect(show_comment.get_absolute_url())
- show_page = show_comment.get_page_number(answers = filtered_answers)
- comment_order_number = show_comment.get_order_number()
- show_post = show_comment.content_object
- except models.Comment.DoesNotExist:
- missing_comment_message = _(
- 'Sorry, the comment has been '
- 'deleted and is no longer accessible'
- )
- request.user.message_set.create(message = missing_comment_message)
- return HttpResponseRedirect(question.get_absolute_url())
- elif show_answer is not None:
- #answers
- try:
- show_post = models.Answer.objects.get(id = show_answer)
- if show_post.question != question:
- return HttpResponseRedirect(show_post.get_absolute_url())
- if show_post.deleted:
- if request.user.is_anonymous():
- linked_post_deleted = True
- missing_post_message = missing_answer_message
- else:
- try:
- request.user.assert_can_see_deleted_post(show_post)
- except django_exceptions.PermissionDenied, e:
- missing_post_message = unicode(e)
- linked_post_deleted = True
- show_page = show_post.get_page_number(answers = filtered_answers)
- except models.Answer.DoesNotExist:
- request.user.message_set.create(message = missing_answer_message)
- return HttpResponseRedirect(question.get_absolute_url())
+ if show_comment:
+ show_page = show_comment.get_page_number(answers = filtered_answers)
+ comment_order_number = show_comment.get_order_number()
+ elif show_answer:
+ show_page = show_post.get_page_number(answers = filtered_answers)
objects_list = Paginator(filtered_answers, const.ANSWERS_PAGE_SIZE)
+ if show_page > objects_list.num_pages:
+ return HttpResponseRediect(question.get_absolute_url())
page_objects = objects_list.page(show_page)
#count visits