summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-08-04 21:08:10 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-08-04 21:08:10 -0400
commitd99947cc63fdd650434e5dbfe0462cd8a2a28233 (patch)
tree823f3e51bd3efbd5649c3630a0d2e1af543747ee
parentcedfb1fdd686441dbb0ae41bfbe96fb3a275c4a5 (diff)
downloadaskbot-d99947cc63fdd650434e5dbfe0462cd8a2a28233.tar.gz
askbot-d99947cc63fdd650434e5dbfe0462cd8a2a28233.tar.bz2
askbot-d99947cc63fdd650434e5dbfe0462cd8a2a28233.zip
moderation rules apply to closing questions
-rw-r--r--askbot/auth.py6
-rw-r--r--askbot/models/__init__.py29
-rw-r--r--askbot/skins/default/templates/question.html4
-rw-r--r--askbot/templatetags/extra_filters.py56
-rw-r--r--askbot/tests/permission_assertion_tests.py205
-rw-r--r--askbot/tests/utils.py4
-rw-r--r--askbot/views/commands.py42
7 files changed, 302 insertions, 44 deletions
diff --git a/askbot/auth.py b/askbot/auth.py
index 1ab24f52..fb1832ce 100644
--- a/askbot/auth.py
+++ b/askbot/auth.py
@@ -45,12 +45,6 @@ def can_edit_post(user, post):
return True
return False
-def can_view_offensive_flags(user):
- """Determines if a User can view offensive flag counts."""
- return user.is_authenticated() and (
- user.reputation >= askbot_settings.MIN_REP_TO_VIEW_OFFENSIVE_FLAGS or
- user.is_superuser or user.is_moderator())
-
def can_close_question(user, question):
"""Determines if a User can close the given Question."""
return user.is_authenticated() and (
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
index a59448c1..e4e1b2b9 100644
--- a/askbot/models/__init__.py
+++ b/askbot/models/__init__.py
@@ -323,7 +323,7 @@ def user_assert_can_close_question(self, question = None):
'you cannot close questions'
)
low_rep_error_message = _(
- 'Sorry, to deleted other people\' posts, a minimum ' + \
+ 'Sorry, to close other people\' posts, a minimum ' + \
'reputation of %(min_rep)s is required'
) % \
{'min_rep': askbot_settings.MIN_REP_TO_CLOSE_OTHERS_QUESTIONS}
@@ -331,13 +331,25 @@ def user_assert_can_close_question(self, question = None):
_assert_user_can(
user = self,
- post = post,
+ post = question,
+ owner_can = True,
blocked_error_message = blocked_error_message,
suspended_error_message = suspended_error_message,
low_rep_error_message = low_rep_error_message,
min_rep_setting = min_rep_setting
)
+ #exception - owner needs some rep to do this
+ if self == question.get_owner():
+ if self.is_suspended():
+ raise django_exceptions.PermissionDenied(suspended_error_message)
+ if self.reputation < askbot_settings.MIN_REP_TO_CLOSE_OWN_QUESTIONS:
+ error_message = _(
+ 'Sorry, to close own question ' +\
+ 'minimum reputation of %(min_rep)s is required'
+ )
+ raise askbot_exceptions.InsufficientReputation(error_message)
+
def user_assert_can_flag_offensive(self, post = None):
@@ -514,6 +526,18 @@ def user_delete_question(
#todo - move onDeleted method to a fitting class
auth.onDeleted(question, self, timestamp = timestamp)
+def user_close_question(
+ self,
+ question = None,
+ reason = None,
+ ):
+ self.assert_can_close_question(question)
+ question.closed = True
+ question.closed_by = self
+ question.closed_at = datetime.datetime.now()
+ question.close_reason = reason
+ question.save()
+
def user_delete_post(
self,
post = None,
@@ -1016,6 +1040,7 @@ User.add_to_class('get_unused_votes_today', user_get_unused_votes_today)
User.add_to_class('delete_comment', user_delete_comment)
User.add_to_class('delete_question', user_delete_question)
User.add_to_class('delete_answer', user_delete_answer)
+User.add_to_class('close_question', user_close_question)
#assertions
User.add_to_class('assert_can_vote_for_post', user_assert_can_vote_for_post)
diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html
index 3cb7fb9c..ad24fe6f 100644
--- a/askbot/skins/default/templates/question.html
+++ b/askbot/skins/default/templates/question.html
@@ -157,7 +157,7 @@
<span id="question-offensive-flag-{{ question.id }}" class="offensive-flag"
title="{% trans "report as offensive (i.e containing spam, advertising, malicious text, etc.)" %}">
<a>{% trans "flag offensive" %}</a>
- {% if request.user|can_view_offensive_flags %}
+ {% if request.user|can_see_offensive_flags:question %}
<span class="darkred">{% if question.offensive_flag_count %}({{ question.offensive_flag_count }}){% endif %}</span>
{% endif %}
</span>
@@ -294,7 +294,7 @@
<span id="answer-offensive-flag-{{ answer.id }}" class="offensive-flag"
title="{% trans "report as offensive (i.e containing spam, advertising, malicious text, etc.)" %}">
<a>{% trans "flag offensive" %}</a>
- {% if request.user|can_view_offensive_flags %}
+ {% if request.user|can_see_offensive_flags:answer %}
<span class="darkred">{% if answer.offensive_flag_count %}({{ answer.offensive_flag_count }}){% endif %}</span>
{% endif %}
</span>
diff --git a/askbot/templatetags/extra_filters.py b/askbot/templatetags/extra_filters.py
index 383c8f7c..688c539e 100644
--- a/askbot/templatetags/extra_filters.py
+++ b/askbot/templatetags/extra_filters.py
@@ -4,6 +4,7 @@ from askbot import exceptions as askbot_exceptions
from askbot import auth
from askbot import models
from askbot.deps.grapefruit import Color
+from askbot.conf import settings as askbot_settings
from django.utils.translation import ugettext as _
import logging
@@ -14,14 +15,15 @@ register = template.Library()
def collapse(input):
return ' '.join(input.split())
-def make_test_from_permission_assertion(
+def make_template_filter_from_permission_assertion(
assertion_name = None,
+ filter_name = None,
allowed_exception = None
):
"""a decorator-like function that will create a True/False test from
permission assertion
"""
- def test_function(user, post):
+ def filter_function(user, post):
if user.is_anonymous():
return False
@@ -41,7 +43,8 @@ def make_test_from_permission_assertion(
except django_exceptions.PermissionDenied:
return False
- return test_function
+ register.filter(filter_name, filter_function)
+ return filter_function
@register.filter
@@ -50,21 +53,26 @@ def can_moderate_user(user, other_user):
return True
return False
-can_flag_offensive = make_test_from_permission_assertion(
+can_flag_offensive = make_template_filter_from_permission_assertion(
assertion_name = 'assert_can_flag_offensive',
+ filter_name = 'can_flag_offensive',
allowed_exception = askbot_exceptions.DuplicateCommand
)
-register.filter('can_flag_offensive', can_flag_offensive)
-can_post_comment = make_test_from_permission_assertion(
- assertion_name = 'assert_can_post_comment'
+can_post_comment = make_template_filter_from_permission_assertion(
+ assertion_name = 'assert_can_post_comment',
+ filter_name = 'can_post_comment'
)
-register.filter('can_post_comment', can_post_comment)
-can_delete_comment = make_test_from_permission_assertion(
- assertion_name = 'assert_can_delete_comment'
+can_delete_comment = make_template_filter_from_permission_assertion(
+ assertion_name = 'assert_can_delete_comment',
+ filter_name = 'can_delete_comment'
+ )
+
+can_close_question = make_template_filter_from_permission_assertion(
+ assertion_name = 'assert_can_close_question',
+ filter_name = 'can_close_question'
)
-register.filter('can_delete_comment', can_delete_comment)
@register.filter
def can_retag_questions(user):
@@ -75,12 +83,28 @@ def can_edit_post(user, post):
return auth.can_edit_post(user, post)
@register.filter
-def can_view_offensive_flags(user):
- return auth.can_view_offensive_flags(user)
+def can_see_offensive_flags(user, post):
+ """Determines if a User can view offensive flag counts.
+ there is no assertion like this User.assert_can...
+ so all of the code is here
-@register.filter
-def can_close_question(user, question):
- return auth.can_close_question(user, question)
+ user can see flags on own posts
+ otherwise enough rep is required
+ or being a moderator or administrator
+
+ suspended or blocked users cannot see flags
+ """
+ if user.is_authenticated():
+ if user == post.get_owner():
+ return True
+ if user.reputation >= askbot_settings.MIN_REP_TO_VIEW_OFFENSIVE_FLAGS:
+ return True
+ elif user.is_administrator() or user.is_moderator():
+ return True
+ else:
+ return False
+ else:
+ return False
@register.filter
def can_lock_posts(user):
diff --git a/askbot/tests/permission_assertion_tests.py b/askbot/tests/permission_assertion_tests.py
index dfef0ca9..884f3f0e 100644
--- a/askbot/tests/permission_assertion_tests.py
+++ b/askbot/tests/permission_assertion_tests.py
@@ -45,6 +45,211 @@ class PermissionAssertionTestCase(TestCase):
body_text = 'test answer'
)
+class SeeOffensiveFlagsPermissionAssertionTests(utils.AskbotTestCase):
+
+ def setUp(self):
+ super(SeeOffensiveFlagsPermissionAssertionTests, self).setUp()
+ self.create_user()
+ self.create_user(username = 'other_user')
+ self.min_rep = askbot_settings.MIN_REP_TO_VIEW_OFFENSIVE_FLAGS
+
+ def setup_answer(self):
+ question = self.post_question()
+ answer = self.post_answer(question = question)
+ return answer
+
+ def test_low_rep_user_cannot_see_flags(self):
+ question = self.post_question()
+ assert(self.other_user.reputation < self.min_rep)
+ self.assertFalse(
+ template_filters.can_see_offensive_flags(
+ self.other_user,
+ question
+ )
+ )
+
+ def test_high_rep_user_can_see_flags(self):
+ question = self.post_question()
+ self.other_user.reputation = self.min_rep
+ self.assertTrue(
+ template_filters.can_see_offensive_flags(
+ self.other_user,
+ question
+ )
+ )
+
+ def test_low_rep_owner_can_see_flags(self):
+ question = self.post_question()
+ assert(self.user.reputation < self.min_rep)
+ self.assertTrue(
+ template_filters.can_see_offensive_flags(
+ self.user,
+ question
+ )
+ )
+
+ def test_admin_can_see_flags(self):
+ question = self.post_question()
+ self.other_user.is_superuser = True
+ assert(self.other_user.reputation < self.min_rep)
+ self.assertTrue(
+ template_filters.can_see_offensive_flags(
+ self.other_user,
+ question
+ )
+ )
+
+ def test_moderator_can_see_flags(self):
+ question = self.post_question()
+ self.other_user.set_status('m')
+ assert(self.other_user.reputation < self.min_rep)
+ self.assertTrue(
+ template_filters.can_see_offensive_flags(
+ self.other_user,
+ question
+ )
+ )
+
+ #tests below test answers only
+ def test_suspended_owner_can_see_flags(self):
+ answer = self.setup_answer()
+ self.user.set_status('s')
+ assert(self.user.reputation < self.min_rep)
+ self.assertTrue(
+ template_filters.can_see_offensive_flags(
+ self.user,
+ answer
+ )
+ )
+
+ def test_blocked_owner_can_see_flags(self):
+ answer = self.setup_answer()
+ self.user.set_status('b')
+ assert(self.user.reputation < self.min_rep)
+ self.assertTrue(
+ template_filters.can_see_offensive_flags(
+ self.user,
+ answer
+ )
+ )
+
+ def test_suspended_user_cannot_see_flags(self):
+ answer = self.setup_answer()
+ self.other_user.set_status('s')
+ self.assertFalse(
+ template_filters.can_see_offensive_flags(
+ self.other_user,
+ answer
+ )
+ )
+
+ def test_blocked_user_cannot_see_flags(self):
+ answer = self.setup_answer()
+ self.other_user.set_status('b')
+ self.assertFalse(
+ template_filters.can_see_offensive_flags(
+ self.other_user,
+ answer
+ )
+ )
+
+
+class CloseQuestionPermissionAssertionTests(utils.AskbotTestCase):
+
+ def setUp(self):
+ super(CloseQuestionPermissionAssertionTests, self).setUp()
+ self.create_user()
+ self.create_user(username = 'other_user')
+ self.question = self.post_question()
+ self.min_rep = askbot_settings.MIN_REP_TO_CLOSE_OTHERS_QUESTIONS
+ self.min_rep_own = askbot_settings.MIN_REP_TO_CLOSE_OWN_QUESTIONS
+
+ def assert_can_close(self, user = None):
+ user.assert_can_close_question(self.question)
+ self.assertTrue(
+ template_filters.can_close_question(
+ user,
+ self.question
+ )
+ )
+
+ def assert_cannot_close(self, user = None):
+ self.assertRaises(
+ exceptions.PermissionDenied,
+ user.assert_can_close_question,
+ self.question
+ )
+ self.assertFalse(
+ template_filters.can_close_question(
+ user,
+ self.question
+ )
+ )
+
+ def test_low_rep_admin_can_close(self):
+ self.other_user.is_superuser = True
+ assert(self.other_user.reputation < self.min_rep)
+ self.assert_can_close(user = self.other_user)
+
+ def test_low_rep_moderator_can_close(self):
+ self.other_user.set_status('m')
+ assert(self.other_user.reputation < self.min_rep)
+ self.assert_can_close(user = self.other_user)
+
+ def test_low_rep_owner_cannot_close(self):
+ assert(self.user.reputation < self.min_rep)
+ assert(self.user.reputation < self.min_rep_own)
+ self.assert_cannot_close(user = self.user)
+
+ def test_high_rep_owner_can_close(self):
+ self.user.reputation = self.min_rep_own
+ self.assert_can_close(user = self.user)
+
+ def test_high_rep_other_can_close(self):
+ self.other_user.reputation = self.min_rep
+ self.assert_can_close(user = self.other_user)
+
+ def test_low_rep_blocked_cannot_close(self):
+ self.other_user.set_status('b')
+ assert(self.other_user.reputation < self.min_rep)
+ self.assert_cannot_close(user = self.other_user)
+
+ def test_high_rep_blocked_cannot_close(self):
+ self.other_user.set_status('b')
+ self.other_user.reputation = self.min_rep
+ self.assert_cannot_close(user = self.other_user)
+
+ def test_medium_rep_blocked_owner_cannot_close(self):
+ self.user.set_status('b')
+ self.user.reputation = self.min_rep_own
+ self.assert_cannot_close(user = self.user)
+
+ def test_high_rep_blocked_owner_cannot_close(self):
+ self.user.set_status('b')
+ self.user.reputation = self.min_rep
+ self.assert_cannot_close(user = self.user)
+
+ def test_low_rep_suspended_cannot_close(self):
+ self.other_user.set_status('s')
+ assert(self.other_user.reputation < self.min_rep)
+ self.assert_cannot_close(user = self.other_user)
+
+ def test_high_rep_suspended_cannot_close(self):
+ self.other_user.set_status('s')
+ self.other_user.reputation = self.min_rep
+ self.assert_cannot_close(user = self.other_user)
+
+ def test_medium_rep_suspended_owner_cannot_close(self):
+ self.user.set_status('s')
+ self.user.reputation = self.min_rep_own
+ self.assert_cannot_close(user = self.user)
+
+ def test_high_rep_suspended_owner_cannot_close(self):
+ self.user.set_status('s')
+ self.user.reputation = self.min_rep
+ self.assert_cannot_close(user = self.user)
+
+
class FlagOffensivePermissionAssertionTests(PermissionAssertionTestCase):
def extraSetUp(self):
diff --git a/askbot/tests/utils.py b/askbot/tests/utils.py
index b8f81717..6942ce29 100644
--- a/askbot/tests/utils.py
+++ b/askbot/tests/utils.py
@@ -8,11 +8,13 @@ def create_user(
email = None,
notification_schedule = None,
date_joined = None,
- status = 'a'
+ status = 'a',
+ reputation = 1
):
"""Creates a user and sets default update subscription
settings"""
user = models.User.objects.create_user(username, email)
+ user.reputation = reputation
if date_joined is not None:
user.date_joined = date_joined
user.save()
diff --git a/askbot/views/commands.py b/askbot/views/commands.py
index ba5c4bd1..81a93be7 100644
--- a/askbot/views/commands.py
+++ b/askbot/views/commands.py
@@ -329,24 +329,32 @@ def close(request, id):#close question
question close
"""
question = get_object_or_404(Question, id=id)
- if not auth.can_close_question(request.user, question):
- return HttpResponse('Permission denied.')
- if request.method == 'POST':
- form = CloseForm(request.POST)
- if form.is_valid():
- reason = form.cleaned_data['reason']
- question.closed = True
- question.closed_by = request.user
- question.closed_at = datetime.datetime.now()
- question.close_reason = reason
- question.save()
+ try:
+ if request.method == 'POST':
+ form = CloseForm(request.POST)
+ if form.is_valid():
+ reason = form.cleaned_data['reason']
+
+ request.user.close_question(
+ question = question,
+ reason = reason
+ )
+ return HttpResponseRedirect(question.get_absolute_url())
+ else:
+ request.user.assert_can_close_question(question)
+ form = CloseForm()
+ response = render_to_response(
+ 'close.html',
+ {
+ 'form' : form,
+ 'question' : question,
+ },
+ context_instance=RequestContext(request)
+ )
+ return response
+ except exceptions.PermissionDenied, e:
+ request.user.message_set.create(message = str(e))
return HttpResponseRedirect(question.get_absolute_url())
- else:
- form = CloseForm()
- return render_to_response('close.html', {
- 'form' : form,
- 'question' : question,
- }, context_instance=RequestContext(request))
@login_required
def reopen(request, id):#re-open question