Merge pull request #956 from normanjaeckel/Fix940

Add error message if a invalid answer was send via POST to a QuestionVie...
This commit is contained in:
Oskar Hahn 2013-10-28 09:21:58 -07:00
commit 055f73a995
4 changed files with 71 additions and 40 deletions

View File

@ -22,8 +22,8 @@ Other:
- Full text search integration (with Haystack and Whoosh). - Full text search integration (with Haystack and Whoosh).
- New start script with new command line options. - New start script with new command line options.
- Fixed keyerror on user settings view. - Fixed keyerror on user settings view.
- New message on success of many actions like creating or editing objects. - 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. - Added feature to config app to return the default value for a key.
- Cleaned up OpenSlides utils views. - Cleaned up OpenSlides utils views.
- Used flake8 instead of pep8 for style check, sort all import statements with isort. - Used flake8 instead of pep8 for style check, sort all import statements with isort.
- Added Portuguese translation (Thanks to Marco A.G.Pinto). - 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) Version 1.4 (2013-07-10)
======================== ========================
[https://github.com/OpenSlides/OpenSlides/issues?milestone=7] [https://github.com/OpenSlides/OpenSlides/issues?milestone=7]
Agenda: Agenda:
@ -121,7 +121,7 @@ Version 1.3.1 (2013-01-09)
========================== ==========================
[http://dev.openslides.org/milestone/1.3.1] [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) one browser languages send projector request to OpenSlides (#434)

View File

@ -270,20 +270,29 @@ class ItemDelete(DeleteView):
self.item_delete_answer_options = options self.item_delete_answer_options = options
return options return options
def pre_post_redirect(self, request, *args, **kwargs): def on_clicked_yes(self):
# TODO: rewrite this method with on_case_all and on_case_yes """
if self.get_answer() == 'all': Deletes the item but not its children.
self.object.delete(with_children=True) """
messages.success( self.object.delete(with_children=False)
request,
_("Item %s and his children were successfully deleted.") def on_clicked_all(self):
% html_strong(self.object)) """
elif self.get_answer() == 'yes': Deletes the item and its children.
self.object.delete(with_children=False) """
messages.success( self.object.delete(with_children=True)
request,
_("Item %s was successfully deleted.") def get_final_message(self):
% html_strong(self.object)) """
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): class CreateRelatedAgendaItemView(SingleObjectMixin, RedirectView):

View File

@ -33,6 +33,7 @@ from django.views.generic.detail import SingleObjectMixin
from reportlab.lib.units import cm from reportlab.lib.units import cm
from reportlab.platypus import SimpleDocTemplate, Spacer from reportlab.platypus import SimpleDocTemplate, Spacer
from .exceptions import OpenSlidesError
from .pdf import firstPage, laterPages from .pdf import firstPage, laterPages
from .signals import template_manipulation from .signals import template_manipulation
from .utils import html_strong from .utils import html_strong
@ -400,32 +401,38 @@ class QuestionView(RedirectView):
""" """
Calls the method for the answer the user clicked. Calls the method for the answer the user clicked.
The method name is on_clicked_ANSWER where ANSWER is the key from the The method name is on_clicked_ANSWER where ANSWER is the key from
clicked answer. See get_answer_options. If this method is not defined, the clicked answer. See get_answer_options. Prints an error
raises a NotImplementedError. message, if no valid answer was given. If this method is not
defined, nothing happens, else it is called and the success message
If the method returns True, then the success message is printed to the is printed to the user.
user.
""" """
method_name = 'on_clicked_%s' % self.get_answer() try:
method = getattr(self, method_name, None) answer = self.get_answer()
if method is None: except OpenSlidesError as error:
pass messages.error(self.request, error)
else: else:
method() method_name = 'on_clicked_%s' % answer
self.create_final_message() method = getattr(self, method_name, None)
if method is None:
pass
else:
method()
self.create_final_message()
def get_answer(self): def get_answer(self):
""" """
Returns the key of the clicked answer. Returns the key of the clicked answer.
Raises ImproperlyConfigured, if the answer is not one of Raises OpenSlidesError if the answer is not one of get_answer_options.
get_answer_options.
""" """
for option_key, option_name in self.get_answer_options(): for option_key, option_name in self.get_answer_options():
if option_key in self.request.POST: if option_key in self.request.POST:
return option_key answer = option_key
raise ImproperlyConfigured('%s is not a valid answer' % self.request.POST) break
else:
raise OpenSlidesError(ugettext_lazy('You did not send a valid answer.'))
return answer
def get_final_message(self): def get_final_message(self):
""" """
@ -493,17 +500,25 @@ class DeleteView(SingleObjectMixin, QuestionView):
def get_redirect_url(self, **kwargs): def get_redirect_url(self, **kwargs):
""" """
Returns the url on which the delete dialog is shown and the url after 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 view as default. The attributes question_url_name or question_url can
define other urls. define other urls.
""" """
if self.request.method == 'GET' or self.get_answer() == 'no': if self.request.method == 'POST':
url = self.get_url(self.question_url_name, self.question_url, try:
args=self.get_url_name_args()) 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: 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()) args=self.get_url_name_args())
return url return url

View File

@ -222,6 +222,13 @@ class ViewTest(TestCase):
query = Item.objects.filter(pk__in=[item1.pk, item2.pk]) query = Item.objects.filter(pk__in=[item1.pk, item2.pk])
self.assertFalse(query) 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): class ConfigTest(TestCase):
def setUp(self): def setUp(self):