diff options
author | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2010-08-04 21:08:10 -0400 |
---|---|---|
committer | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2010-08-04 21:08:10 -0400 |
commit | d99947cc63fdd650434e5dbfe0462cd8a2a28233 (patch) | |
tree | 823f3e51bd3efbd5649c3630a0d2e1af543747ee | |
parent | cedfb1fdd686441dbb0ae41bfbe96fb3a275c4a5 (diff) | |
download | askbot-d99947cc63fdd650434e5dbfe0462cd8a2a28233.tar.gz askbot-d99947cc63fdd650434e5dbfe0462cd8a2a28233.tar.bz2 askbot-d99947cc63fdd650434e5dbfe0462cd8a2a28233.zip |
moderation rules apply to closing questions
-rw-r--r-- | askbot/auth.py | 6 | ||||
-rw-r--r-- | askbot/models/__init__.py | 29 | ||||
-rw-r--r-- | askbot/skins/default/templates/question.html | 4 | ||||
-rw-r--r-- | askbot/templatetags/extra_filters.py | 56 | ||||
-rw-r--r-- | askbot/tests/permission_assertion_tests.py | 205 | ||||
-rw-r--r-- | askbot/tests/utils.py | 4 | ||||
-rw-r--r-- | askbot/views/commands.py | 42 |
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 |