From b2afa77e25cbaea049dfa912a377f38d65485bd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Norman=20J=C3=A4ckel?= Date: Thu, 24 Oct 2013 18:48:16 +0200 Subject: [PATCH] Add error message if a invalid answer was send via POST to a QuestionView. Fix #940. --- CHANGELOG | 8 +++--- openslides/agenda/views.py | 37 +++++++++++++++--------- openslides/utils/views.py | 59 ++++++++++++++++++++++++-------------- tests/agenda/tests.py | 7 +++++ 4 files changed, 71 insertions(+), 40 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8778e1a52..cd6d9772f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -22,8 +22,8 @@ Other: - Full text search integration (with Haystack and Whoosh). - New start script with new command line options. - Fixed keyerror on user settings view. -- New message on success of many actions like creating or editing objects. -- Added Feature to config app to return the default value for a key. +- New messages on success or error of many actions like creating or editing objects. +- Added feature to config app to return the default value for a key. - Cleaned up OpenSlides utils views. - Used flake8 instead of pep8 for style check, sort all import statements with isort. - Added Portuguese translation (Thanks to Marco A.G.Pinto). @@ -60,7 +60,7 @@ Version 1.4.1 (2013-07-29) Version 1.4 (2013-07-10) -======================== +======================== [https://github.com/OpenSlides/OpenSlides/issues?milestone=7] Agenda: @@ -121,7 +121,7 @@ Version 1.3.1 (2013-01-09) ========================== [http://dev.openslides.org/milestone/1.3.1] -- Fixed unwanted automatical language switching on projector view if more than +- Fixed unwanted automatical language switching on projector view if more than one browser languages send projector request to OpenSlides (#434) diff --git a/openslides/agenda/views.py b/openslides/agenda/views.py index 61c985bb2..96c13ce78 100644 --- a/openslides/agenda/views.py +++ b/openslides/agenda/views.py @@ -270,20 +270,29 @@ class ItemDelete(DeleteView): self.item_delete_answer_options = options return options - def pre_post_redirect(self, request, *args, **kwargs): - # TODO: rewrite this method with on_case_all and on_case_yes - if self.get_answer() == 'all': - self.object.delete(with_children=True) - messages.success( - request, - _("Item %s and his children were successfully deleted.") - % html_strong(self.object)) - elif self.get_answer() == 'yes': - self.object.delete(with_children=False) - messages.success( - request, - _("Item %s was successfully deleted.") - % html_strong(self.object)) + def on_clicked_yes(self): + """ + Deletes the item but not its children. + """ + self.object.delete(with_children=False) + + def on_clicked_all(self): + """ + Deletes the item and its children. + """ + self.object.delete(with_children=True) + + def get_final_message(self): + """ + Prints the success message to the user. + """ + # OpenSlidesError (invalid answer) should never be raised here because + # this method should only be called if the answer is 'yes' or 'all'. + if self.get_answer() == 'yes': + message = _('Item %s was successfully deleted.') % html_strong(self.object) + else: + message = _('Item %s and its children were successfully deleted.') % html_strong(self.object) + return message class CreateRelatedAgendaItemView(SingleObjectMixin, RedirectView): diff --git a/openslides/utils/views.py b/openslides/utils/views.py index 6cd3d9485..7af379ad9 100644 --- a/openslides/utils/views.py +++ b/openslides/utils/views.py @@ -33,6 +33,7 @@ from django.views.generic.detail import SingleObjectMixin from reportlab.lib.units import cm from reportlab.platypus import SimpleDocTemplate, Spacer +from .exceptions import OpenSlidesError from .pdf import firstPage, laterPages from .signals import template_manipulation from .utils import html_strong @@ -400,32 +401,38 @@ class QuestionView(RedirectView): """ Calls the method for the answer the user clicked. - The method name is on_clicked_ANSWER where ANSWER is the key from the - clicked answer. See get_answer_options. If this method is not defined, - raises a NotImplementedError. - - If the method returns True, then the success message is printed to the - user. + The method name is on_clicked_ANSWER where ANSWER is the key from + the clicked answer. See get_answer_options. Prints an error + message, if no valid answer was given. If this method is not + defined, nothing happens, else it is called and the success message + is printed to the user. """ - method_name = 'on_clicked_%s' % self.get_answer() - method = getattr(self, method_name, None) - if method is None: - pass + try: + answer = self.get_answer() + except OpenSlidesError as error: + messages.error(self.request, error) else: - method() - self.create_final_message() + method_name = 'on_clicked_%s' % answer + method = getattr(self, method_name, None) + if method is None: + pass + else: + method() + self.create_final_message() def get_answer(self): """ Returns the key of the clicked answer. - Raises ImproperlyConfigured, if the answer is not one of - get_answer_options. + Raises OpenSlidesError if the answer is not one of get_answer_options. """ for option_key, option_name in self.get_answer_options(): if option_key in self.request.POST: - return option_key - raise ImproperlyConfigured('%s is not a valid answer' % self.request.POST) + answer = option_key + break + else: + raise OpenSlidesError(ugettext_lazy('You did not send a valid answer.')) + return answer def get_final_message(self): """ @@ -493,17 +500,25 @@ class DeleteView(SingleObjectMixin, QuestionView): def get_redirect_url(self, **kwargs): """ Returns the url on which the delete dialog is shown and the url after - the deleten. + the deleting. - On GET-requests and on aborted POST-requests, redirect to the detail + On GET-requests and on aborted or failed POST-requests, redirects to the detail view as default. The attributes question_url_name or question_url can define other urls. """ - if self.request.method == 'GET' or self.get_answer() == 'no': - url = self.get_url(self.question_url_name, self.question_url, - args=self.get_url_name_args()) + if self.request.method == 'POST': + try: + answer = self.get_answer() + except OpenSlidesError: + answer = 'no' + if answer == 'no': + url = self.get_url(self.question_url_name, self.question_url, + args=self.get_url_name_args()) + else: + url = self.get_url(self.success_url_name, self.success_url, + args=self.get_url_name_args()) else: - url = self.get_url(self.success_url_name, self.success_url, + url = self.get_url(self.question_url_name, self.question_url, args=self.get_url_name_args()) return url diff --git a/tests/agenda/tests.py b/tests/agenda/tests.py index 4b5c9fd04..b690145cd 100644 --- a/tests/agenda/tests.py +++ b/tests/agenda/tests.py @@ -222,6 +222,13 @@ class ViewTest(TestCase): query = Item.objects.filter(pk__in=[item1.pk, item2.pk]) self.assertFalse(query) + def test_delete_item_with_wrong_answer(self): + response = self.adminClient.post( + '/agenda/%s/del/' % self.item1.pk, + {'unknown_answer_aicipohc1Eeph2chaeng': 1}) + self.assertRedirects(response, '/agenda/') + self.assertTrue(Item.objects.filter(pk=self.item1.pk).exists()) + class ConfigTest(TestCase): def setUp(self):