commit
840ac34c80
@ -184,16 +184,12 @@ class SetClosed(RedirectView, SingleObjectMixin):
|
|||||||
model = Item
|
model = Item
|
||||||
|
|
||||||
def get_ajax_context(self, **kwargs):
|
def get_ajax_context(self, **kwargs):
|
||||||
context = super(SetClosed, self).get_ajax_context(**kwargs)
|
closed = self.kwargs['closed']
|
||||||
closed = kwargs['closed']
|
|
||||||
if closed:
|
if closed:
|
||||||
link = reverse('item_open', args=[self.object.id])
|
link = reverse('item_open', args=[self.object.pk])
|
||||||
else:
|
else:
|
||||||
link = reverse('item_close', args=[self.object.id])
|
link = reverse('item_close', args=[self.object.pk])
|
||||||
context.update({
|
return super(SetClosed, self).get_ajax_context(closed=closed, link=link)
|
||||||
'closed': kwargs['closed'],
|
|
||||||
'link': link})
|
|
||||||
return context
|
|
||||||
|
|
||||||
def pre_redirect(self, request, *args, **kwargs):
|
def pre_redirect(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
@ -214,6 +210,7 @@ class ItemUpdate(UpdateView):
|
|||||||
model = Item
|
model = Item
|
||||||
context_object_name = 'item'
|
context_object_name = 'item'
|
||||||
success_url_name = 'item_overview'
|
success_url_name = 'item_overview'
|
||||||
|
url_name_args = []
|
||||||
|
|
||||||
def get_form_class(self):
|
def get_form_class(self):
|
||||||
if self.object.content_object:
|
if self.object.content_object:
|
||||||
@ -233,6 +230,7 @@ class ItemCreate(CreateView):
|
|||||||
context_object_name = 'item'
|
context_object_name = 'item'
|
||||||
form_class = ItemForm
|
form_class = ItemForm
|
||||||
success_url_name = 'item_overview'
|
success_url_name = 'item_overview'
|
||||||
|
url_name_args = []
|
||||||
|
|
||||||
|
|
||||||
class ItemDelete(DeleteView):
|
class ItemDelete(DeleteView):
|
||||||
|
@ -25,11 +25,10 @@ from django.utils.translation import ungettext, ugettext as _
|
|||||||
|
|
||||||
from openslides.utils.pdf import stylesheet
|
from openslides.utils.pdf import stylesheet
|
||||||
from openslides.utils.template import Tab
|
from openslides.utils.template import Tab
|
||||||
from openslides.utils.utils import gen_confirm_form
|
|
||||||
|
|
||||||
from openslides.utils.views import (
|
from openslides.utils.views import (
|
||||||
CreateView, DeleteView, RedirectView, UpdateView, ListView, PDFView,
|
CreateView, DeleteView, RedirectView, UpdateView, ListView, PDFView,
|
||||||
DetailView, View, PermissionMixin, SingleObjectMixin, QuestionMixin)
|
DetailView, View, PermissionMixin, SingleObjectMixin, QuestionView)
|
||||||
from openslides.utils.person import get_person
|
from openslides.utils.person import get_person
|
||||||
from openslides.utils.utils import html_strong
|
from openslides.utils.utils import html_strong
|
||||||
from openslides.config.api import config
|
from openslides.config.api import config
|
||||||
@ -150,8 +149,6 @@ class AssignmentRunView(SingleObjectMixin, PermissionMixin, View):
|
|||||||
class AssignmentRunDeleteView(SingleObjectMixin, RedirectView):
|
class AssignmentRunDeleteView(SingleObjectMixin, RedirectView):
|
||||||
model = Assignment
|
model = Assignment
|
||||||
url_name = 'assignment_detail'
|
url_name = 'assignment_detail'
|
||||||
success_message = _("You have withdrawn your candidature successfully. "
|
|
||||||
"You can not be nominated by other participants anymore.")
|
|
||||||
|
|
||||||
def pre_redirect(self, *args, **kwargs):
|
def pre_redirect(self, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
@ -162,54 +159,49 @@ class AssignmentRunDeleteView(SingleObjectMixin, RedirectView):
|
|||||||
except Exception, e:
|
except Exception, e:
|
||||||
messages.error(self.request, e)
|
messages.error(self.request, e)
|
||||||
else:
|
else:
|
||||||
messages.success(self.request, self.success_message)
|
messages.success(self.request, _(
|
||||||
|
'You have withdrawn your candidature successfully. '
|
||||||
|
'You can not be nominated by other participants anymore.'))
|
||||||
else:
|
else:
|
||||||
messages.error(self.request, _('The candidate list is already closed.'))
|
messages.error(self.request, _('The candidate list is already closed.'))
|
||||||
|
|
||||||
|
|
||||||
class AssignmentRunOtherDeleteView(SingleObjectMixin, QuestionMixin,
|
class AssignmentRunOtherDeleteView(SingleObjectMixin, QuestionView):
|
||||||
RedirectView):
|
|
||||||
model = Assignment
|
model = Assignment
|
||||||
permission_required = 'assignment.can_manage_assignment'
|
permission_required = 'assignment.can_manage_assignment'
|
||||||
question_url_name = 'assignment_detail'
|
|
||||||
success_url_name = 'assignment_detail'
|
|
||||||
success_message = ''
|
|
||||||
|
|
||||||
def pre_redirect(self, *args, **kwargs):
|
def get_question_message(self):
|
||||||
self._get_person_information(*args, **kwargs)
|
self._get_person_information()
|
||||||
if not self.is_blocked:
|
if not self.is_blocked:
|
||||||
message = _("Do you really want to withdraw %s from the election?") % html_strong(self.person)
|
question = _("Do you really want to withdraw %s from the election?") % html_strong(self.person)
|
||||||
else:
|
else:
|
||||||
message = _("Do you really want to unblock %s for the election?") % html_strong(self.person)
|
question = _("Do you really want to unblock %s for the election?") % html_strong(self.person)
|
||||||
gen_confirm_form(self.request, message, reverse('assignment_delother',
|
return question
|
||||||
args=[self.object.pk, kwargs['user_id']]))
|
|
||||||
|
|
||||||
def pre_post_redirect(self, *args, **kwargs):
|
def on_clicked_yes(self):
|
||||||
self._get_person_information(*args, **kwargs)
|
self._get_person_information()
|
||||||
if self.get_answer() == 'yes':
|
|
||||||
self.case_yes()
|
|
||||||
|
|
||||||
def get_answer(self):
|
|
||||||
if 'submit' in self.request.POST:
|
|
||||||
return 'yes'
|
|
||||||
|
|
||||||
def case_yes(self):
|
|
||||||
try:
|
try:
|
||||||
self.object.delrun(self.person, blocked=False)
|
self.object.delrun(self.person, blocked=False)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
messages.error(self.request, e)
|
self.error = e
|
||||||
else:
|
else:
|
||||||
messages.success(self.request, self.get_success_message())
|
self.error = False
|
||||||
|
|
||||||
def get_success_message(self):
|
def create_final_message(self):
|
||||||
success_message = _("Candidate %s was withdrawn successfully.") % html_strong(self.person)
|
if self.error:
|
||||||
|
messages.error(self.request, self.error)
|
||||||
|
else:
|
||||||
|
messages.success(self.request, self.get_final_message())
|
||||||
|
|
||||||
|
def get_final_message(self):
|
||||||
|
message = _("Candidate %s was withdrawn successfully.") % html_strong(self.person)
|
||||||
if self.is_blocked:
|
if self.is_blocked:
|
||||||
success_message = _("%s was unblocked successfully.") % html_strong(self.person)
|
message = _("%s was unblocked successfully.") % html_strong(self.person)
|
||||||
return success_message
|
return message
|
||||||
|
|
||||||
def _get_person_information(self, *args, **kwargs):
|
def _get_person_information(self):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
self.person = get_person(kwargs.get('user_id'))
|
self.person = get_person(self.kwargs.get('user_id'))
|
||||||
self.is_blocked = self.object.is_blocked(self.person)
|
self.is_blocked = self.object.is_blocked(self.person)
|
||||||
|
|
||||||
|
|
||||||
@ -310,7 +302,7 @@ class AssignmentPollDeleteView(DeleteView):
|
|||||||
def get_redirect_url(self, **kwargs):
|
def get_redirect_url(self, **kwargs):
|
||||||
return reverse('assignment_detail', args=[self.assignment.id])
|
return reverse('assignment_detail', args=[self.assignment.id])
|
||||||
|
|
||||||
def get_success_message(self):
|
def get_final_message(self):
|
||||||
return _('Ballot was successfully deleted.')
|
return _('Ballot was successfully deleted.')
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,11 +69,9 @@ STATICFILES_DIRS = (
|
|||||||
fs2unicode(os.path.join(SITE_ROOT, 'static')),
|
fs2unicode(os.path.join(SITE_ROOT, 'static')),
|
||||||
)
|
)
|
||||||
|
|
||||||
#XXX: Note this setting (as well as our workaround finder)
|
|
||||||
# can be removed again once django-bug-#18404 has been resolved
|
|
||||||
STATICFILES_FINDERS = (
|
STATICFILES_FINDERS = (
|
||||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||||
'openslides.utils.staticfiles.AppDirectoriesFinder',
|
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||||
)
|
)
|
||||||
|
|
||||||
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
|
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
|
||||||
|
@ -40,6 +40,7 @@ class MediafileCreateView(CreateView):
|
|||||||
model = Mediafile
|
model = Mediafile
|
||||||
permission_required = 'mediafile.can_upload'
|
permission_required = 'mediafile.can_upload'
|
||||||
success_url_name = 'mediafile_list'
|
success_url_name = 'mediafile_list'
|
||||||
|
url_name_args = []
|
||||||
|
|
||||||
def get_form(self, form_class):
|
def get_form(self, form_class):
|
||||||
form_kwargs = self.get_form_kwargs()
|
form_kwargs = self.get_form_kwargs()
|
||||||
@ -71,6 +72,7 @@ class MediafileUpdateView(UpdateView):
|
|||||||
permission_required = 'mediafile.can_manage'
|
permission_required = 'mediafile.can_manage'
|
||||||
form_class = MediafileUpdateForm
|
form_class = MediafileUpdateForm
|
||||||
success_url_name = 'mediafile_list'
|
success_url_name = 'mediafile_list'
|
||||||
|
url_name_args = []
|
||||||
|
|
||||||
def get_form_kwargs(self, *args, **kwargs):
|
def get_form_kwargs(self, *args, **kwargs):
|
||||||
form_kwargs = super(MediafileUpdateView, self).get_form_kwargs(*args, **kwargs)
|
form_kwargs = super(MediafileUpdateView, self).get_form_kwargs(*args, **kwargs)
|
||||||
@ -86,10 +88,10 @@ class MediafileDeleteView(DeleteView):
|
|||||||
permission_required = 'mediafile.can_manage'
|
permission_required = 'mediafile.can_manage'
|
||||||
success_url_name = 'mediafile_list'
|
success_url_name = 'mediafile_list'
|
||||||
|
|
||||||
def case_yes(self, *args, **kwargs):
|
def on_clicked_yes(self, *args, **kwargs):
|
||||||
"""Deletes the file in the filesystem, if user clicks "Yes"."""
|
"""Deletes the file in the filesystem, if user clicks "Yes"."""
|
||||||
self.object.mediafile.delete()
|
self.object.mediafile.delete()
|
||||||
return super(MediafileDeleteView, self).case_yes(*args, **kwargs)
|
return super(MediafileDeleteView, self).on_clicked_yes(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def register_tab(request):
|
def register_tab(request):
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
:copyright: (c) 2011–2013 by the OpenSlides team, see AUTHORS.
|
:copyright: (c) 2011–2013 by the OpenSlides team, see AUTHORS.
|
||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
from reportlab.platypus import SimpleDocTemplate
|
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
@ -20,26 +19,26 @@ from django.db.models import Model
|
|||||||
from django.http import Http404, HttpResponseRedirect
|
from django.http import Http404, HttpResponseRedirect
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
from django.utils.translation import ugettext as _, ugettext_lazy, ugettext_noop
|
from django.utils.translation import ugettext as _, ugettext_lazy, ugettext_noop
|
||||||
|
from reportlab.platypus import SimpleDocTemplate
|
||||||
|
|
||||||
from openslides.agenda.views import (
|
|
||||||
CreateRelatedAgendaItemView as _CreateRelatedAgendaItemView)
|
|
||||||
from openslides.config.api import config
|
|
||||||
from openslides.poll.views import PollFormView
|
|
||||||
from openslides.projector.api import get_active_slide, update_projector
|
|
||||||
from openslides.projector.projector import Widget
|
|
||||||
from openslides.utils.pdf import stylesheet
|
from openslides.utils.pdf import stylesheet
|
||||||
from openslides.utils.template import Tab
|
|
||||||
from openslides.utils.utils import html_strong, htmldiff
|
|
||||||
from openslides.utils.views import (
|
from openslides.utils.views import (
|
||||||
TemplateView, RedirectView, UpdateView, CreateView, DeleteView, PDFView,
|
TemplateView, RedirectView, UpdateView, CreateView, DeleteView, PDFView,
|
||||||
DetailView, ListView, FormView, QuestionMixin, SingleObjectMixin)
|
DetailView, ListView, FormView, QuestionView, SingleObjectMixin)
|
||||||
|
from openslides.utils.template import Tab
|
||||||
|
from openslides.utils.utils import html_strong, htmldiff
|
||||||
|
from openslides.poll.views import PollFormView
|
||||||
|
from openslides.projector.api import get_active_slide
|
||||||
|
from openslides.projector.projector import Widget
|
||||||
|
from openslides.config.api import config
|
||||||
|
from openslides.agenda.views import CreateRelatedAgendaItemView as _CreateRelatedAgendaItemView
|
||||||
|
|
||||||
from .csv_import import import_motions
|
from .csv_import import import_motions
|
||||||
|
from .models import (Motion, MotionSubmitter, MotionSupporter, MotionPoll,
|
||||||
|
MotionVersion, State, WorkflowError, Category)
|
||||||
from .forms import (BaseMotionForm, MotionSubmitterMixin, MotionSupporterMixin,
|
from .forms import (BaseMotionForm, MotionSubmitterMixin, MotionSupporterMixin,
|
||||||
MotionDisableVersioningMixin, MotionCategoryMixin,
|
MotionDisableVersioningMixin, MotionCategoryMixin,
|
||||||
MotionIdentifierMixin, MotionWorkflowMixin, MotionImportForm)
|
MotionIdentifierMixin, MotionWorkflowMixin, MotionImportForm)
|
||||||
from .models import (Motion, MotionSubmitter, MotionSupporter, MotionPoll,
|
|
||||||
MotionVersion, State, WorkflowError, Category)
|
|
||||||
from .pdf import motions_to_pdf, motion_to_pdf, motion_poll_to_pdf
|
from .pdf import motions_to_pdf, motion_to_pdf, motion_poll_to_pdf
|
||||||
|
|
||||||
|
|
||||||
@ -297,7 +296,7 @@ class MotionDeleteView(DeleteView):
|
|||||||
"""
|
"""
|
||||||
return self.get_object().get_allowed_actions(request.user)['delete']
|
return self.get_object().get_allowed_actions(request.user)['delete']
|
||||||
|
|
||||||
def get_success_message(self):
|
def get_final_message(self):
|
||||||
return _('%s was successfully deleted.') % _('Motion')
|
return _('%s was successfully deleted.') % _('Motion')
|
||||||
|
|
||||||
motion_delete = MotionDeleteView.as_view()
|
motion_delete = MotionDeleteView.as_view()
|
||||||
@ -326,21 +325,20 @@ class VersionDeleteView(DeleteView):
|
|||||||
raise Http404('You can not delete the active version of a motion.')
|
raise Http404('You can not delete the active version of a motion.')
|
||||||
return version
|
return version
|
||||||
|
|
||||||
def get_success_url_name_args(self):
|
def get_url_name_args(self):
|
||||||
return (self.object.motion_id, )
|
return (self.object.motion_id, )
|
||||||
|
|
||||||
version_delete = VersionDeleteView.as_view()
|
version_delete = VersionDeleteView.as_view()
|
||||||
|
|
||||||
|
|
||||||
class VersionPermitView(SingleObjectMixin, QuestionMixin, RedirectView):
|
class VersionPermitView(SingleObjectMixin, QuestionView):
|
||||||
"""
|
"""
|
||||||
View to permit a version of a motion.
|
View to permit a version of a motion.
|
||||||
"""
|
"""
|
||||||
model = Motion
|
model = Motion
|
||||||
question_url_name = 'motion_version_detail'
|
final_message = ugettext_lazy('Version successfully permitted.')
|
||||||
success_url_name = 'motion_version_detail'
|
|
||||||
success_message = ugettext_lazy('Version successfully permitted.')
|
|
||||||
permission_required = 'motion.can_manage_motion'
|
permission_required = 'motion.can_manage_motion'
|
||||||
|
question_url_name = 'motion_version_detail'
|
||||||
|
|
||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -360,13 +358,13 @@ class VersionPermitView(SingleObjectMixin, QuestionMixin, RedirectView):
|
|||||||
"""
|
"""
|
||||||
return [self.object.pk, self.version.version_number]
|
return [self.object.pk, self.version.version_number]
|
||||||
|
|
||||||
def get_question(self):
|
def get_question_message(self):
|
||||||
"""
|
"""
|
||||||
Return a string, shown to the user as question to permit the version.
|
Return a string, shown to the user as question to permit the version.
|
||||||
"""
|
"""
|
||||||
return _('Are you sure you want permit version %s?') % self.version.version_number
|
return _('Are you sure you want permit version %s?') % self.version.version_number
|
||||||
|
|
||||||
def case_yes(self):
|
def on_clicked_yes(self):
|
||||||
"""
|
"""
|
||||||
Activate the version, if the user chooses 'yes'.
|
Activate the version, if the user chooses 'yes'.
|
||||||
"""
|
"""
|
||||||
@ -418,7 +416,7 @@ class VersionDiffView(DetailView):
|
|||||||
version_diff = VersionDiffView.as_view()
|
version_diff = VersionDiffView.as_view()
|
||||||
|
|
||||||
|
|
||||||
class SupportView(SingleObjectMixin, QuestionMixin, RedirectView):
|
class SupportView(SingleObjectMixin, QuestionView):
|
||||||
"""
|
"""
|
||||||
View to support or unsupport a motion.
|
View to support or unsupport a motion.
|
||||||
|
|
||||||
@ -452,7 +450,7 @@ class SupportView(SingleObjectMixin, QuestionMixin, RedirectView):
|
|||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_question(self):
|
def get_question_message(self):
|
||||||
"""
|
"""
|
||||||
Return the question string.
|
Return the question string.
|
||||||
"""
|
"""
|
||||||
@ -461,7 +459,7 @@ class SupportView(SingleObjectMixin, QuestionMixin, RedirectView):
|
|||||||
else:
|
else:
|
||||||
return _('Do you really want to unsupport this motion?')
|
return _('Do you really want to unsupport this motion?')
|
||||||
|
|
||||||
def case_yes(self):
|
def on_clicked_yes(self):
|
||||||
"""
|
"""
|
||||||
Append or remove the request.user from the motion.
|
Append or remove the request.user from the motion.
|
||||||
|
|
||||||
@ -477,7 +475,7 @@ class SupportView(SingleObjectMixin, QuestionMixin, RedirectView):
|
|||||||
self.object.unsupport(person=user)
|
self.object.unsupport(person=user)
|
||||||
self.object.write_log([ugettext_noop('Motion unsupported')], user)
|
self.object.write_log([ugettext_noop('Motion unsupported')], user)
|
||||||
|
|
||||||
def get_success_message(self):
|
def get_final_message(self):
|
||||||
"""
|
"""
|
||||||
Return the success message.
|
Return the success message.
|
||||||
"""
|
"""
|
||||||
@ -486,12 +484,6 @@ class SupportView(SingleObjectMixin, QuestionMixin, RedirectView):
|
|||||||
else:
|
else:
|
||||||
return _("You have unsupported this motion successfully.")
|
return _("You have unsupported this motion successfully.")
|
||||||
|
|
||||||
def get_redirect_url(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Return the url, the view should redirect to.
|
|
||||||
"""
|
|
||||||
return self.object.get_absolute_url()
|
|
||||||
|
|
||||||
motion_support = SupportView.as_view(support=True)
|
motion_support = SupportView.as_view(support=True)
|
||||||
motion_unsupport = SupportView.as_view(support=False)
|
motion_unsupport = SupportView.as_view(support=False)
|
||||||
|
|
||||||
@ -558,6 +550,7 @@ class PollUpdateView(PollMixin, PollFormView):
|
|||||||
"""
|
"""
|
||||||
View to update a MotionPoll.
|
View to update a MotionPoll.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
poll_class = MotionPoll
|
poll_class = MotionPoll
|
||||||
"""
|
"""
|
||||||
Poll Class to use for this view.
|
Poll Class to use for this view.
|
||||||
@ -595,11 +588,11 @@ class PollDeleteView(PollMixin, DeleteView):
|
|||||||
|
|
||||||
model = MotionPoll
|
model = MotionPoll
|
||||||
|
|
||||||
def case_yes(self):
|
def on_clicked_yes(self):
|
||||||
"""
|
"""
|
||||||
Write a log message, if the form is valid.
|
Write a log message, if the form is valid.
|
||||||
"""
|
"""
|
||||||
super(PollDeleteView, self).case_yes()
|
super(PollDeleteView, self).on_clicked_yes()
|
||||||
self.object.motion.write_log([ugettext_noop('Poll deleted')], self.request.user)
|
self.object.motion.write_log([ugettext_noop('Poll deleted')], self.request.user)
|
||||||
|
|
||||||
def get_redirect_url(self, **kwargs):
|
def get_redirect_url(self, **kwargs):
|
||||||
|
@ -138,11 +138,11 @@ class Group(SlideMixin, PersonMixin, Person, DjangoGroup):
|
|||||||
Return the URL to the user group.
|
Return the URL to the user group.
|
||||||
"""
|
"""
|
||||||
if link == 'detail' or link == 'view':
|
if link == 'detail' or link == 'view':
|
||||||
return reverse('user_group_view', args=[str(self.id)])
|
return reverse('user_group_view', args=[str(self.pk)])
|
||||||
if link == 'update' or link == 'edit':
|
if link == 'update' or link == 'edit':
|
||||||
return reverse('user_group_edit', args=[str(self.id)])
|
return reverse('user_group_edit', args=[str(self.pk)])
|
||||||
if link == 'delete':
|
if link == 'delete':
|
||||||
return reverse('user_group_delete', args=[str(self.id)])
|
return reverse('user_group_delete', args=[str(self.pk)])
|
||||||
return super(Group, self).get_absolute_url(link)
|
return super(Group, self).get_absolute_url(link)
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ from openslides.utils.utils import (
|
|||||||
template, delete_default_permissions, html_strong)
|
template, delete_default_permissions, html_strong)
|
||||||
from openslides.utils.views import (
|
from openslides.utils.views import (
|
||||||
FormView, PDFView, CreateView, UpdateView, DeleteView, PermissionMixin,
|
FormView, PDFView, CreateView, UpdateView, DeleteView, PermissionMixin,
|
||||||
RedirectView, SingleObjectMixin, ListView, QuestionMixin, DetailView)
|
RedirectView, SingleObjectMixin, ListView, QuestionView, DetailView)
|
||||||
from openslides.config.api import config
|
from openslides.config.api import config
|
||||||
from openslides.projector.projector import Widget
|
from openslides.projector.projector import Widget
|
||||||
|
|
||||||
@ -155,6 +155,7 @@ class UserDeleteView(DeleteView):
|
|||||||
permission_required = 'participant.can_manage_participant'
|
permission_required = 'participant.can_manage_participant'
|
||||||
model = User
|
model = User
|
||||||
success_url_name = 'user_overview'
|
success_url_name = 'user_overview'
|
||||||
|
url_name_args = []
|
||||||
|
|
||||||
def pre_redirect(self, request, *args, **kwargs):
|
def pre_redirect(self, request, *args, **kwargs):
|
||||||
if self.object == self.request.user:
|
if self.object == self.request.user:
|
||||||
@ -335,14 +336,14 @@ class UserImportView(FormView):
|
|||||||
return super(UserImportView, self).form_valid(form)
|
return super(UserImportView, self).form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class ResetPasswordView(SingleObjectMixin, QuestionMixin, RedirectView):
|
class ResetPasswordView(SingleObjectMixin, QuestionView):
|
||||||
"""
|
"""
|
||||||
Set the Passwort for a user to his default password.
|
Set the Passwort for a user to his default password.
|
||||||
"""
|
"""
|
||||||
permission_required = 'participant.can_manage_participant'
|
permission_required = 'participant.can_manage_participant'
|
||||||
model = User
|
model = User
|
||||||
allow_ajax = True
|
allow_ajax = True
|
||||||
question = ugettext_lazy('Do you really want to reset the password?')
|
question_message = ugettext_lazy('Do you really want to reset the password?')
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
@ -351,10 +352,10 @@ class ResetPasswordView(SingleObjectMixin, QuestionMixin, RedirectView):
|
|||||||
def get_redirect_url(self, **kwargs):
|
def get_redirect_url(self, **kwargs):
|
||||||
return reverse('user_edit', args=[self.object.id])
|
return reverse('user_edit', args=[self.object.id])
|
||||||
|
|
||||||
def case_yes(self):
|
def on_clicked_yes(self):
|
||||||
self.object.reset_password()
|
self.object.reset_password()
|
||||||
|
|
||||||
def get_success_message(self):
|
def get_final_message(self):
|
||||||
return _('The Password for %s was successfully reset.') % html_strong(self.object)
|
return _('The Password for %s was successfully reset.') % html_strong(self.object)
|
||||||
|
|
||||||
|
|
||||||
@ -432,6 +433,7 @@ class GroupDeleteView(DeleteView):
|
|||||||
permission_required = 'participant.can_manage_participant'
|
permission_required = 'participant.can_manage_participant'
|
||||||
model = Group
|
model = Group
|
||||||
success_url_name = 'user_group_overview'
|
success_url_name = 'user_group_overview'
|
||||||
|
url_name_args = []
|
||||||
|
|
||||||
def pre_redirect(self, request, *args, **kwargs):
|
def pre_redirect(self, request, *args, **kwargs):
|
||||||
if not self.is_protected_from_deleting():
|
if not self.is_protected_from_deleting():
|
||||||
@ -466,14 +468,17 @@ def login(request):
|
|||||||
try:
|
try:
|
||||||
admin = User.objects.get(pk=1)
|
admin = User.objects.get(pk=1)
|
||||||
if admin.check_password(admin.default_password):
|
if admin.check_password(admin.default_password):
|
||||||
|
user_data = {
|
||||||
|
'user': html_strong(admin.username),
|
||||||
|
'password': html_strong(admin.default_password)}
|
||||||
|
|
||||||
extra_content['first_time_message'] = _(
|
extra_content['first_time_message'] = _(
|
||||||
"Installation was successfully! Use %(user)s "
|
"Installation was successfully! Use %(user)s "
|
||||||
"(password: %(password)s) for first login.<br>"
|
"(password: %(password)s) for first login.<br>"
|
||||||
"<strong>Important:</strong> Please change the password after "
|
"<strong>Important:</strong> Please change the password after "
|
||||||
"first login! Otherwise this message still appears for "
|
"first login! Otherwise this message still appears for "
|
||||||
"everyone and could be a security risk.") % {
|
"everyone and could be a security risk.") % user_data
|
||||||
'user': html_strong(admin.username),
|
|
||||||
'password': html_strong(admin.default_password)}
|
|
||||||
extra_content['next'] = reverse('password_change')
|
extra_content['next'] = reverse('password_change')
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
@ -14,7 +14,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _, ugettext_noop
|
from django.utils.translation import ugettext_lazy as _, ugettext_noop
|
||||||
|
|
||||||
from openslides.utils.modelfields import MinMaxIntegerField
|
from openslides.utils.models import MinMaxIntegerField
|
||||||
|
|
||||||
|
|
||||||
class BaseOption(models.Model):
|
class BaseOption(models.Model):
|
||||||
|
@ -14,10 +14,10 @@ from django.http import HttpResponseRedirect
|
|||||||
from django.forms.models import modelform_factory
|
from django.forms.models import modelform_factory
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
|
||||||
from openslides.utils.views import TemplateView, UrlMixin
|
from openslides.utils.views import TemplateView, FormMixin
|
||||||
|
|
||||||
|
|
||||||
class PollFormView(UrlMixin, TemplateView):
|
class PollFormView(FormMixin, TemplateView):
|
||||||
poll_class = None
|
poll_class = None
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
@ -23,7 +23,7 @@ from django.shortcuts import redirect
|
|||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from openslides.utils.template import render_block_to_string, Tab
|
from openslides.utils.template import Tab
|
||||||
from openslides.utils.views import (
|
from openslides.utils.views import (
|
||||||
TemplateView, RedirectView, CreateView, UpdateView, DeleteView, AjaxMixin)
|
TemplateView, RedirectView, CreateView, UpdateView, DeleteView, AjaxMixin)
|
||||||
from openslides.config.api import config
|
from openslides.config.api import config
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{{ error }}</h1>
|
<h1>{% trans 'Permission Denied' %}</h1>
|
||||||
|
{% trans 'Sorry, you have no rights to see this page.' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
Modelfields for OpenSlides
|
Modelfields for OpenSlides
|
||||||
|
|
||||||
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
|
:copyright: 2011–2013 by OpenSlides team, see AUTHORS.
|
||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -14,6 +14,10 @@ from django.db import models
|
|||||||
|
|
||||||
|
|
||||||
class MinMaxIntegerField(models.IntegerField):
|
class MinMaxIntegerField(models.IntegerField):
|
||||||
|
"""
|
||||||
|
IntegerField with options to set a min- and a max-value.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, min_value=None, max_value=None, *args, **kwargs):
|
def __init__(self, min_value=None, max_value=None, *args, **kwargs):
|
||||||
self.min_value, self.max_value = min_value, max_value
|
self.min_value, self.max_value = min_value, max_value
|
||||||
super(MinMaxIntegerField, self).__init__(*args, **kwargs)
|
super(MinMaxIntegerField, self).__init__(*args, **kwargs)
|
0
openslides/utils/pdf.py
Executable file → Normal file
0
openslides/utils/pdf.py
Executable file → Normal file
@ -1,48 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
openslides.utils.staticfiles
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
StaticFiels fix for the django bug #18404.
|
|
||||||
|
|
||||||
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
|
|
||||||
:license: GNU GPL, see LICENSE for more details.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from django.core.files.storage import FileSystemStorage
|
|
||||||
from django.utils.importlib import import_module
|
|
||||||
from django.contrib.staticfiles.finders import (
|
|
||||||
AppDirectoriesFinder as _AppDirectoriesFinder)
|
|
||||||
|
|
||||||
|
|
||||||
# This is basically a copy of
|
|
||||||
# django.contrib.staticfiles.storage.AppStaticStorage
|
|
||||||
# with the fix for django bug #18404 applied
|
|
||||||
# see https://code.djangoproject.com/ticket/18404 for details
|
|
||||||
class AppStaticStorage(FileSystemStorage):
|
|
||||||
"""
|
|
||||||
A file system storage backend that takes an app module and works
|
|
||||||
for the ``static`` directory of it.
|
|
||||||
"""
|
|
||||||
prefix = None
|
|
||||||
source_dir = 'static'
|
|
||||||
|
|
||||||
def __init__(self, app, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Returns a static file storage if available in the given app.
|
|
||||||
"""
|
|
||||||
# app is the actual app module
|
|
||||||
mod = import_module(app)
|
|
||||||
mod_path = os.path.dirname(mod.__file__)
|
|
||||||
location = os.path.join(mod_path, self.source_dir)
|
|
||||||
fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
|
|
||||||
location = location.decode(fs_encoding)
|
|
||||||
super(AppStaticStorage, self).__init__(location, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class AppDirectoriesFinder(_AppDirectoriesFinder):
|
|
||||||
storage_class = AppStaticStorage
|
|
@ -10,11 +10,11 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.template import loader, Context
|
|
||||||
from django.template.loader_tags import BlockNode, ExtendsNode
|
|
||||||
|
|
||||||
|
|
||||||
class Tab(object):
|
class Tab(object):
|
||||||
|
"""
|
||||||
|
Entry for the main menu of OpenSlides.
|
||||||
|
"""
|
||||||
def __init__(self, title='', app='', stylefile='', url='', permission=True, selected=False):
|
def __init__(self, title='', app='', stylefile='', url='', permission=True, selected=False):
|
||||||
self.title = title
|
self.title = title
|
||||||
self.app = app
|
self.app = app
|
||||||
@ -22,62 +22,3 @@ class Tab(object):
|
|||||||
self.url = url
|
self.url = url
|
||||||
self.permission = permission
|
self.permission = permission
|
||||||
self.selected = selected
|
self.selected = selected
|
||||||
|
|
||||||
|
|
||||||
## All following function are only needed to render a block from a template
|
|
||||||
## and could be removed, if the template worked with an include-statement instead.
|
|
||||||
## Its only used for ajax-request from the projector.
|
|
||||||
|
|
||||||
def get_template(template):
|
|
||||||
if isinstance(template, (tuple, list)):
|
|
||||||
return loader.select_template(template)
|
|
||||||
return loader.get_template(template)
|
|
||||||
|
|
||||||
|
|
||||||
class BlockNotFound(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def render_template_block(template, block, context):
|
|
||||||
"""
|
|
||||||
Renders a single block from a template. This template should have previously
|
|
||||||
been rendered.
|
|
||||||
"""
|
|
||||||
return render_template_block_nodelist(template.nodelist, block, context)
|
|
||||||
|
|
||||||
|
|
||||||
def render_template_block_nodelist(nodelist, block, context):
|
|
||||||
for node in nodelist:
|
|
||||||
if isinstance(node, BlockNode) and node.name == block:
|
|
||||||
return node.render(context)
|
|
||||||
for key in ('nodelist', 'nodelist_true', 'nodelist_false'):
|
|
||||||
if hasattr(node, key):
|
|
||||||
try:
|
|
||||||
return render_template_block_nodelist(
|
|
||||||
getattr(node, key), block, context)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
for node in nodelist:
|
|
||||||
if isinstance(node, ExtendsNode):
|
|
||||||
try:
|
|
||||||
return render_template_block(
|
|
||||||
node.get_parent(context), block, context)
|
|
||||||
except BlockNotFound:
|
|
||||||
pass
|
|
||||||
raise BlockNotFound
|
|
||||||
|
|
||||||
|
|
||||||
def render_block_to_string(template_name, block, dictionary=None,
|
|
||||||
context_instance=None):
|
|
||||||
"""
|
|
||||||
Loads the given template_name and renders the given block with the given
|
|
||||||
dictionary as context. Returns a string.
|
|
||||||
"""
|
|
||||||
dictionary = dictionary or {}
|
|
||||||
t = get_template(template_name)
|
|
||||||
if context_instance:
|
|
||||||
context_instance.update(dictionary)
|
|
||||||
else:
|
|
||||||
context_instance = Context(dictionary)
|
|
||||||
t.render(context_instance)
|
|
||||||
return render_template_block(t, block, context_instance)
|
|
||||||
|
@ -11,54 +11,12 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import difflib
|
import difflib
|
||||||
import json
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
from django.core.context_processors import csrf
|
from django.shortcuts import render_to_response
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.http import HttpResponse, HttpResponseForbidden
|
|
||||||
from django.shortcuts import render_to_response, redirect
|
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.template.loader import render_to_string
|
|
||||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
|
||||||
|
|
||||||
from openslides.utils.signals import template_manipulation
|
from .signals import template_manipulation
|
||||||
|
|
||||||
|
|
||||||
def gen_confirm_form(request, message, url):
|
|
||||||
"""
|
|
||||||
Generate a message-form.
|
|
||||||
|
|
||||||
Deprecated. Use Class base Views instead.
|
|
||||||
"""
|
|
||||||
messages.warning(
|
|
||||||
request,
|
|
||||||
"""
|
|
||||||
%s
|
|
||||||
<form action="%s" method="post">
|
|
||||||
<input type="hidden" value="%s" name="csrfmiddlewaretoken">
|
|
||||||
<button type="submit" name="submit" class="btn btn-mini">%s</button>
|
|
||||||
<button name="cancel" class="btn btn-mini">%s</button>
|
|
||||||
</form>
|
|
||||||
"""
|
|
||||||
% (message, url, csrf(request)['csrf_token'], _("Yes"), _("No")))
|
|
||||||
|
|
||||||
|
|
||||||
def del_confirm_form(request, object, name=None, delete_link=None):
|
|
||||||
"""
|
|
||||||
Creates a question to delete an object.
|
|
||||||
|
|
||||||
Deprecated. Use Class base Views instead.
|
|
||||||
"""
|
|
||||||
if name is None:
|
|
||||||
name = object
|
|
||||||
if delete_link is None:
|
|
||||||
delete_link = object.get_absolute_url('delete')
|
|
||||||
gen_confirm_form(
|
|
||||||
request, _('Do you really want to delete %s?')
|
|
||||||
% html_strong(name), delete_link)
|
|
||||||
|
|
||||||
|
|
||||||
def template(template_name):
|
def template(template_name):
|
||||||
@ -67,6 +25,8 @@ def template(template_name):
|
|||||||
|
|
||||||
Deprecated. Use class based views instead.
|
Deprecated. Use class based views instead.
|
||||||
"""
|
"""
|
||||||
|
# TODO: Write the login page an the usersettings page with class based views
|
||||||
|
# Remove this function afterwards
|
||||||
def renderer(func):
|
def renderer(func):
|
||||||
def wrapper(request, *args, **kwargs):
|
def wrapper(request, *args, **kwargs):
|
||||||
output = func(request, *args, **kwargs)
|
output = func(request, *args, **kwargs)
|
||||||
@ -85,36 +45,12 @@ def template(template_name):
|
|||||||
return renderer
|
return renderer
|
||||||
|
|
||||||
|
|
||||||
def permission_required(perm, login_url=None):
|
|
||||||
"""
|
|
||||||
Decorator for views that checks whether a user has a particular permission
|
|
||||||
enabled, redirecting to the log-in page if necessary.
|
|
||||||
|
|
||||||
Deprecated.
|
|
||||||
"""
|
|
||||||
def renderer(func):
|
|
||||||
def wrapper(request, *args, **kw):
|
|
||||||
if request.user.has_perm(perm):
|
|
||||||
return func(request, *args, **kw)
|
|
||||||
if request.user.is_authenticated():
|
|
||||||
return render_to_forbidden(request)
|
|
||||||
return redirect(reverse('user_login'))
|
|
||||||
return wrapper
|
|
||||||
return renderer
|
|
||||||
|
|
||||||
|
|
||||||
def render_to_forbidden(request,
|
|
||||||
error=ugettext_lazy("Sorry, you have no rights to see this page.")):
|
|
||||||
# TODO: Integrate this function into the PermissionMixin once the
|
|
||||||
# above function is deleted.
|
|
||||||
return HttpResponseForbidden(render_to_string(
|
|
||||||
'403.html', {'error': error}, context_instance=RequestContext(request)))
|
|
||||||
|
|
||||||
|
|
||||||
def delete_default_permissions(**kwargs):
|
def delete_default_permissions(**kwargs):
|
||||||
"""
|
"""
|
||||||
Deletes the permissions, django creates by default for the admin.
|
Deletes the permissions, django creates by default for the admin.
|
||||||
"""
|
"""
|
||||||
|
# TODO: Create an participant app which does not create the permissions.
|
||||||
|
# Delete this function afterwards
|
||||||
for p in Permission.objects.all():
|
for p in Permission.objects.all():
|
||||||
if (p.codename.startswith('add') or
|
if (p.codename.startswith('add') or
|
||||||
p.codename.startswith('delete') or
|
p.codename.startswith('delete') or
|
||||||
@ -122,29 +58,26 @@ def delete_default_permissions(**kwargs):
|
|||||||
p.delete()
|
p.delete()
|
||||||
|
|
||||||
|
|
||||||
def ajax_request(data):
|
|
||||||
"""
|
|
||||||
generates a HTTPResponse-Object with json-Data for a
|
|
||||||
ajax response.
|
|
||||||
|
|
||||||
Deprecated.
|
|
||||||
"""
|
|
||||||
return HttpResponse(json.dumps(data))
|
|
||||||
|
|
||||||
|
|
||||||
def html_strong(string):
|
def html_strong(string):
|
||||||
|
"""
|
||||||
|
Returns the text wrapped in an HTML-Strong element.
|
||||||
|
"""
|
||||||
return u"<strong>%s</strong>" % string
|
return u"<strong>%s</strong>" % string
|
||||||
|
|
||||||
|
|
||||||
def htmldiff(text1, text2):
|
def htmldiff(text1, text2):
|
||||||
"""Return string of html diff between two strings (text1 and text2)"""
|
"""
|
||||||
|
Return string of html diff between two strings (text1 and text2)
|
||||||
|
"""
|
||||||
diff = difflib.HtmlDiff(wrapcolumn=60)
|
diff = difflib.HtmlDiff(wrapcolumn=60)
|
||||||
return diff.make_table(text1.splitlines(), text2.splitlines())
|
return diff.make_table(text1.splitlines(), text2.splitlines())
|
||||||
|
|
||||||
|
|
||||||
def int_or_none(object):
|
def int_or_none(var):
|
||||||
|
"""
|
||||||
|
Trys to convert 'var' into an integer. Returns None if an TypeError occures.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return int(object)
|
return int(var)
|
||||||
except TypeError:
|
except (TypeError, ValueError):
|
||||||
return None
|
return None
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
Views for OpenSlides.
|
Views for OpenSlides.
|
||||||
|
|
||||||
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
|
:copyright: 2011–2013 by OpenSlides team, see AUTHORS.
|
||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -15,257 +15,280 @@ from cStringIO import StringIO
|
|||||||
from reportlab.platypus import SimpleDocTemplate, Spacer
|
from reportlab.platypus import SimpleDocTemplate, Spacer
|
||||||
from reportlab.lib.units import cm
|
from reportlab.lib.units import cm
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.core.context_processors import csrf
|
from django.core.context_processors import csrf
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.conf import settings
|
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.http import HttpResponseServerError, HttpResponse, HttpResponseRedirect
|
from django.http import (HttpResponse, HttpResponseRedirect,
|
||||||
from django.utils.decorators import method_decorator
|
HttpResponseServerError)
|
||||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
|
||||||
from django.utils.importlib import import_module
|
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.views.generic import (
|
from django.utils.decorators import method_decorator
|
||||||
TemplateView as _TemplateView,
|
from django.utils.importlib import import_module
|
||||||
RedirectView as _RedirectView,
|
from django.utils.translation import ugettext as _
|
||||||
UpdateView as _UpdateView,
|
from django.utils.translation import ugettext_lazy
|
||||||
CreateView as _CreateView,
|
from django.views import generic as django_views
|
||||||
View as _View,
|
|
||||||
FormView as _FormView,
|
|
||||||
ListView as _ListView,
|
|
||||||
DetailView as _DetailView,
|
|
||||||
)
|
|
||||||
from django.views.generic.detail import SingleObjectMixin
|
from django.views.generic.detail import SingleObjectMixin
|
||||||
from django.views.generic.list import TemplateResponseMixin
|
from django.views.generic.list import TemplateResponseMixin
|
||||||
|
from reportlab.lib.units import cm
|
||||||
|
from reportlab.platypus import SimpleDocTemplate, Spacer
|
||||||
|
|
||||||
from openslides.utils.utils import render_to_forbidden, html_strong
|
from .pdf import firstPage, laterPages
|
||||||
from openslides.utils.signals import template_manipulation
|
from .signals import template_manipulation
|
||||||
from openslides.utils.pdf import firstPage, laterPages
|
from .utils import html_strong
|
||||||
|
|
||||||
|
|
||||||
NO_PERMISSION_REQUIRED = 'No permission required'
|
NO_PERMISSION_REQUIRED = 'No permission required'
|
||||||
|
|
||||||
View = _View
|
View = django_views.View
|
||||||
|
|
||||||
|
|
||||||
class SetCookieMixin(object):
|
|
||||||
def render_to_response(self, context, **response_kwargs):
|
|
||||||
response = TemplateResponseMixin.render_to_response(
|
|
||||||
self, context, **response_kwargs)
|
|
||||||
if 'cookie' in context:
|
|
||||||
response.set_cookie(context['cookie'][0], context['cookie'][1])
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
class LoginMixin(object):
|
class LoginMixin(object):
|
||||||
|
"""
|
||||||
|
Mixin for Views, that only can be viseted from users how are logedin.
|
||||||
|
"""
|
||||||
|
|
||||||
@method_decorator(login_required)
|
@method_decorator(login_required)
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Check if the user is loged in.
|
||||||
|
"""
|
||||||
return super(LoginMixin, self).dispatch(request, *args, **kwargs)
|
return super(LoginMixin, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class PermissionMixin(object):
|
class PermissionMixin(object):
|
||||||
|
"""
|
||||||
|
Mixin for views, that only can be visited from users with special rights.
|
||||||
|
|
||||||
|
Set the attribute 'permission_required' to the required permission string.
|
||||||
|
"""
|
||||||
permission_required = NO_PERMISSION_REQUIRED
|
permission_required = NO_PERMISSION_REQUIRED
|
||||||
|
|
||||||
def has_permission(self, request, *args, **kwargs):
|
def has_permission(self, request, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Checks if the user has the required permission.
|
||||||
|
"""
|
||||||
if self.permission_required == NO_PERMISSION_REQUIRED:
|
if self.permission_required == NO_PERMISSION_REQUIRED:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return request.user.has_perm(self.permission_required)
|
return request.user.has_perm(self.permission_required)
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Check if the user has the permission.
|
||||||
|
|
||||||
|
If the user is not logged in, redirect the user to the login page.
|
||||||
|
"""
|
||||||
if not self.has_permission(request, *args, **kwargs):
|
if not self.has_permission(request, *args, **kwargs):
|
||||||
if not request.user.is_authenticated():
|
if not request.user.is_authenticated():
|
||||||
path = request.get_full_path()
|
path = request.get_full_path()
|
||||||
return HttpResponseRedirect(
|
return HttpResponseRedirect(
|
||||||
"%s?next=%s" % (settings.LOGIN_URL, path))
|
"%s?next=%s" % (settings.LOGIN_URL, path))
|
||||||
else:
|
else:
|
||||||
return render_to_forbidden(request)
|
raise PermissionDenied
|
||||||
return super(PermissionMixin, self).dispatch(request, *args, **kwargs)
|
return super(PermissionMixin, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AjaxMixin(object):
|
class AjaxMixin(object):
|
||||||
|
"""
|
||||||
|
Mixin to response to an ajax request with an json object.
|
||||||
|
"""
|
||||||
|
|
||||||
def get_ajax_context(self, **kwargs):
|
def get_ajax_context(self, **kwargs):
|
||||||
return {}
|
"""
|
||||||
|
Returns a dictonary with the context for the ajax response.
|
||||||
|
"""
|
||||||
|
return kwargs
|
||||||
|
|
||||||
def ajax_get(self, request, *args, **kwargs):
|
def ajax_get(self, request, *args, **kwargs):
|
||||||
return HttpResponse(json.dumps(self.get_ajax_context(**kwargs)))
|
"""
|
||||||
|
Returns the HttpResponse.
|
||||||
|
"""
|
||||||
|
return HttpResponse(json.dumps(self.get_ajax_context()))
|
||||||
|
|
||||||
|
|
||||||
class ExtraContextMixin(object):
|
class ExtraContextMixin(object):
|
||||||
|
"""
|
||||||
|
Mixin to send the signal 'template_manipulation' to add extra content to the
|
||||||
|
context of the view.
|
||||||
|
|
||||||
|
For example this is used to add the main menu of openslides.
|
||||||
|
"""
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Sends the signal.
|
||||||
|
"""
|
||||||
context = super(ExtraContextMixin, self).get_context_data(**kwargs)
|
context = super(ExtraContextMixin, self).get_context_data(**kwargs)
|
||||||
context.setdefault('extra_javascript', [])
|
|
||||||
template_manipulation.send(
|
template_manipulation.send(
|
||||||
sender=self.__class__, request=self.request, context=context)
|
sender=self.__class__, request=self.request, context=context)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class UrlMixin(object):
|
class UrlMixin(object):
|
||||||
"""
|
|
||||||
Mixin to provide the use of url names in views with success url and
|
|
||||||
apply url.
|
|
||||||
|
|
||||||
The initial value of url_name_args is None, but the default given by
|
|
||||||
the used get_url_name_args method is [], because in the future, the
|
|
||||||
method might return another default value. Compare this with the QuestionMixin.
|
|
||||||
"""
|
|
||||||
apply_url_name = None
|
|
||||||
success_url_name = None
|
|
||||||
url_name_args = None
|
url_name_args = None
|
||||||
|
|
||||||
|
def get_url(self, url_name=None, url=None, args=None, use_absolute_url_link=None):
|
||||||
|
"""
|
||||||
|
Returns an url.
|
||||||
|
|
||||||
|
Tries
|
||||||
|
1. to use the reverse for the attribute 'url_name',
|
||||||
|
2. to use the attribute 'url' or
|
||||||
|
3. to use self.object.get_absolute_url().
|
||||||
|
|
||||||
|
Uses the attribute 'use_absolute_url_link' as argument for
|
||||||
|
get_absolute_url in the third step. If the attribute is 'None' then
|
||||||
|
the default value of get_absolute_url is used.
|
||||||
|
|
||||||
|
Raises ImproperlyConfigured if no url can be found.
|
||||||
|
"""
|
||||||
|
if url_name:
|
||||||
|
value = reverse(url_name, args=args or [])
|
||||||
|
elif url:
|
||||||
|
value = url
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if use_absolute_url_link is None:
|
||||||
|
value = self.object.get_absolute_url()
|
||||||
|
else:
|
||||||
|
value = self.object.get_absolute_url(use_absolute_url_link)
|
||||||
|
except AttributeError:
|
||||||
|
raise ImproperlyConfigured(
|
||||||
|
'No url to redirect to. See openslides.utils.views.UrlMixin for more details.')
|
||||||
|
return value
|
||||||
|
|
||||||
|
def get_url_name_args(self):
|
||||||
|
"""
|
||||||
|
Returns the arguments for the url name.
|
||||||
|
|
||||||
|
Default is an empty list or [self.object.pk] if this exist.
|
||||||
|
"""
|
||||||
|
if self.url_name_args is not None:
|
||||||
|
value = self.url_name_args
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
pk = self.object.pk
|
||||||
|
except AttributeError:
|
||||||
|
value = []
|
||||||
|
else:
|
||||||
|
if pk:
|
||||||
|
value = [pk]
|
||||||
|
else:
|
||||||
|
value = []
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class FormMixin(UrlMixin):
|
||||||
|
"""
|
||||||
|
Mixin for views with forms.
|
||||||
|
"""
|
||||||
|
|
||||||
|
use_apply = True
|
||||||
|
success_url_name = None
|
||||||
success_url = None
|
success_url = None
|
||||||
|
success_message = None
|
||||||
|
apply_url_name = None
|
||||||
apply_url = None
|
apply_url = None
|
||||||
|
error_message = ugettext_lazy('Please check the form for errors.')
|
||||||
|
|
||||||
def get_apply_url(self):
|
def get_apply_url(self):
|
||||||
if self.apply_url_name:
|
"""
|
||||||
return reverse(self.apply_url_name, args=self.get_url_name_args())
|
Returns the url when the user clicks on 'apply'.
|
||||||
elif self.apply_url:
|
"""
|
||||||
return self.apply_url
|
return self.get_url(self.apply_url_name, self.apply_url,
|
||||||
else:
|
args=self.get_url_name_args(),
|
||||||
try:
|
use_absolute_url_link='update')
|
||||||
return self.object.get_absolute_url('edit')
|
|
||||||
except AttributeError:
|
|
||||||
raise ImproperlyConfigured(
|
|
||||||
"No URL to redirect to. Provide an apply_url_name.")
|
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
if 'apply' in self.request.POST:
|
"""
|
||||||
return self.get_apply_url()
|
Returns the url when the user submits a form.
|
||||||
|
|
||||||
if self.success_url_name:
|
Redirects to get_apply_url if self.use_apply is True
|
||||||
return reverse(self.success_url_name, args=self.get_url_name_args())
|
"""
|
||||||
elif self.success_url:
|
if self.use_apply and 'apply' in self.request.POST:
|
||||||
return self.success_url
|
value = self.get_apply_url()
|
||||||
else:
|
else:
|
||||||
try:
|
value = self.get_url(self.success_url_name, self.success_url,
|
||||||
return self.object.get_absolute_url()
|
args=self.get_url_name_args())
|
||||||
except AttributeError:
|
return value
|
||||||
raise ImproperlyConfigured(
|
|
||||||
"No URL to redirect to. Either provide an URL or define "
|
|
||||||
"a get_absolute_url method of the model.")
|
|
||||||
|
|
||||||
def get_url_name_args(self):
|
def form_valid(self, form):
|
||||||
"""
|
value = super(FormMixin, self).form_valid(form)
|
||||||
Returns the arguments for the url name. Default is an empty list.
|
messages.success(self.request, self.get_success_message())
|
||||||
"""
|
return value
|
||||||
if self.url_name_args is not None:
|
|
||||||
return self.url_name_args
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
def form_invalid(self, form):
|
||||||
class QuestionMixin(object):
|
value = super(FormMixin, self).form_invalid(form)
|
||||||
"""
|
messages.error(self.request, self.get_error_message())
|
||||||
Mixin for questions to the requesting user.
|
return value
|
||||||
|
|
||||||
The initial value of url_name_args is None, but the default given by
|
|
||||||
the used get_url_name_args method is [self.object.pk] if it exist, else
|
|
||||||
an empty list. Set url_name_args to an empty list, if you use an url
|
|
||||||
name which does not need any arguments.
|
|
||||||
"""
|
|
||||||
question = ugettext_lazy('Are you sure?')
|
|
||||||
success_message = ugettext_lazy('Thank you for your answer')
|
|
||||||
answer_options = [('yes', ugettext_lazy("Yes")), ('no', ugettext_lazy("No"))]
|
|
||||||
question_url_name = None
|
|
||||||
success_url_name = None
|
|
||||||
url_name_args = None
|
|
||||||
|
|
||||||
def get_redirect_url(self, **kwargs):
|
|
||||||
# TODO: raise error when question_url_name/success_url_name is not present
|
|
||||||
if self.request.method == 'GET':
|
|
||||||
return reverse(self.question_url_name, args=self.get_question_url_name_args())
|
|
||||||
else:
|
|
||||||
return reverse(self.success_url_name, args=self.get_success_url_name_args())
|
|
||||||
|
|
||||||
def get_question_url_name_args(self):
|
|
||||||
return self.get_url_name_args()
|
|
||||||
|
|
||||||
def get_success_url_name_args(self):
|
|
||||||
return self.get_url_name_args()
|
|
||||||
|
|
||||||
def get_url_name_args(self):
|
|
||||||
"""
|
|
||||||
Returns the arguments for the url name. Default is an empty list
|
|
||||||
or [self.object.pk] if this exist.
|
|
||||||
"""
|
|
||||||
if self.url_name_args is not None:
|
|
||||||
return self.url_name_args
|
|
||||||
try:
|
|
||||||
return [self.object.pk]
|
|
||||||
except AttributeError:
|
|
||||||
return []
|
|
||||||
|
|
||||||
def pre_redirect(self, request, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Prints the question in a GET request.
|
|
||||||
"""
|
|
||||||
self.confirm_form()
|
|
||||||
|
|
||||||
def get_question(self):
|
|
||||||
return unicode(self.question)
|
|
||||||
|
|
||||||
def get_answer_options(self):
|
|
||||||
return self.answer_options
|
|
||||||
|
|
||||||
def get_answer_url(self):
|
|
||||||
try:
|
|
||||||
return self.answer_url
|
|
||||||
except AttributeError:
|
|
||||||
return self.request.path
|
|
||||||
|
|
||||||
def confirm_form(self):
|
|
||||||
option_fields = "\n".join([
|
|
||||||
'<button type="submit" class="btn btn-mini" name="%s">%s</button>' % (option[0], unicode(option[1]))
|
|
||||||
for option in self.get_answer_options()])
|
|
||||||
messages.warning(
|
|
||||||
self.request,
|
|
||||||
"""
|
|
||||||
%(message)s
|
|
||||||
<form action="%(url)s" method="post">
|
|
||||||
<input type="hidden" value="%(csrf)s" name="csrfmiddlewaretoken">
|
|
||||||
%(option_fields)s
|
|
||||||
</form>
|
|
||||||
""" % {'message': self.get_question(),
|
|
||||||
'url': self.get_answer_url(),
|
|
||||||
'csrf': csrf(self.request)['csrf_token'],
|
|
||||||
'option_fields': option_fields})
|
|
||||||
|
|
||||||
def pre_post_redirect(self, request, *args, **kwargs):
|
|
||||||
# Reacts on the response of the user in a POST-request.
|
|
||||||
# TODO: call the methodes for all possible answers.
|
|
||||||
if self.get_answer() == 'yes':
|
|
||||||
self.case_yes()
|
|
||||||
messages.success(request, self.get_success_message())
|
|
||||||
|
|
||||||
def get_answer(self):
|
|
||||||
for option in self.get_answer_options():
|
|
||||||
if option[0] in self.request.POST:
|
|
||||||
return option[0]
|
|
||||||
return None
|
|
||||||
|
|
||||||
def case_yes(self):
|
|
||||||
# TODO: raise a warning
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_success_message(self):
|
def get_success_message(self):
|
||||||
return self.success_message
|
return self.success_message
|
||||||
|
|
||||||
|
def get_error_message(self):
|
||||||
|
return self.error_message
|
||||||
|
|
||||||
class TemplateView(PermissionMixin, ExtraContextMixin, _TemplateView):
|
|
||||||
|
class ModelFormMixin(FormMixin):
|
||||||
|
"""
|
||||||
|
Mixin for FormViews.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
"""
|
||||||
|
Called if the form is valid.
|
||||||
|
|
||||||
|
1. saves the form into the model,
|
||||||
|
2. calls 'self.manipulate_object,
|
||||||
|
3. saves the object in the database,
|
||||||
|
4. calls self.post_save.
|
||||||
|
"""
|
||||||
|
self.object = form.save(commit=False)
|
||||||
|
self.manipulate_object(form)
|
||||||
|
self.object.save()
|
||||||
|
self.post_save(form)
|
||||||
|
messages.success(self.request, self.get_success_message())
|
||||||
|
return HttpResponseRedirect(self.get_success_url())
|
||||||
|
|
||||||
|
def manipulate_object(self, form):
|
||||||
|
"""
|
||||||
|
Called before the object is saved into the database.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def post_save(self, form):
|
||||||
|
"""
|
||||||
|
Called after the object is saved into the database.
|
||||||
|
"""
|
||||||
|
form.save_m2m()
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateView(PermissionMixin, ExtraContextMixin, django_views.TemplateView):
|
||||||
|
"""
|
||||||
|
View to return with an template.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ListView(PermissionMixin, SetCookieMixin, ExtraContextMixin, _ListView):
|
class ListView(PermissionMixin, ExtraContextMixin, django_views.ListView):
|
||||||
|
"""
|
||||||
|
View to show a list of model objects.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AjaxView(PermissionMixin, AjaxMixin, View):
|
class AjaxView(PermissionMixin, AjaxMixin, View):
|
||||||
|
"""
|
||||||
|
View for ajax requests.
|
||||||
|
"""
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
return self.ajax_get(request, *args, **kwargs)
|
return self.ajax_get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class RedirectView(PermissionMixin, AjaxMixin, _RedirectView):
|
class RedirectView(PermissionMixin, AjaxMixin, UrlMixin, django_views.RedirectView):
|
||||||
"""
|
"""
|
||||||
View to redirect to another url.
|
View to redirect to another url.
|
||||||
|
|
||||||
@ -277,12 +300,19 @@ class RedirectView(PermissionMixin, AjaxMixin, _RedirectView):
|
|||||||
permanent = False
|
permanent = False
|
||||||
allow_ajax = False
|
allow_ajax = False
|
||||||
url_name = None
|
url_name = None
|
||||||
url_name_args = None
|
|
||||||
|
|
||||||
def pre_redirect(self, request, *args, **kwargs):
|
def pre_redirect(self, request, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Called before the redirect.
|
||||||
|
"""
|
||||||
|
# TODO: Also call this method on post-request.
|
||||||
|
# Add pre_get_redirect for get requests.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def pre_post_redirect(self, request, *args, **kwargs):
|
def pre_post_redirect(self, request, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Called before the redirect, if it is a post request.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
@ -291,62 +321,143 @@ class RedirectView(PermissionMixin, AjaxMixin, _RedirectView):
|
|||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
self.pre_post_redirect(request, *args, **kwargs)
|
self.pre_post_redirect(request, *args, **kwargs)
|
||||||
|
|
||||||
if self.request.is_ajax() and self.allow_ajax:
|
if request.is_ajax() and self.allow_ajax:
|
||||||
return self.ajax_get(request, *args, **kwargs)
|
return self.ajax_get(request, *args, **kwargs)
|
||||||
return super(RedirectView, self).get(request, *args, **kwargs)
|
return super(RedirectView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_redirect_url(self, **kwargs):
|
def get_redirect_url(self, **kwargs):
|
||||||
if self.url_name is not None:
|
"""
|
||||||
return reverse(self.url_name, args=self.get_url_name_args())
|
Returns the url to which the redirect should go.
|
||||||
|
"""
|
||||||
|
return self.get_url(self.url_name, self.url,
|
||||||
|
args=self.get_url_name_args())
|
||||||
|
|
||||||
|
|
||||||
|
class QuestionView(RedirectView):
|
||||||
|
"""
|
||||||
|
Mixin for questions to the requesting user.
|
||||||
|
|
||||||
|
The BaseView has to be a RedirectView.
|
||||||
|
"""
|
||||||
|
|
||||||
|
question_message = ugettext_lazy('Are you sure?')
|
||||||
|
final_message = ugettext_lazy('Thank you for your answer.')
|
||||||
|
answer_options = [('yes', ugettext_lazy("Yes")), ('no', ugettext_lazy("No"))]
|
||||||
|
question_url_name = None
|
||||||
|
question_url = None
|
||||||
|
|
||||||
|
def get_redirect_url(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Returns the url to which the view should redirect.
|
||||||
|
"""
|
||||||
|
if self.request.method == 'GET':
|
||||||
|
url = self.get_url(self.question_url_name, self.question_url,
|
||||||
|
args=self.get_url_name_args())
|
||||||
else:
|
else:
|
||||||
return super(RedirectView, self).get_redirect_url(**kwargs)
|
url = super(QuestionView, self).get_redirect_url()
|
||||||
|
return url
|
||||||
|
|
||||||
def get_url_name_args(self):
|
def pre_redirect(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Returns the arguments for the url name. Default is an empty list
|
Prints the question in a GET request.
|
||||||
or [self.object.pk] if this exist.
|
|
||||||
"""
|
"""
|
||||||
if self.url_name_args is not None:
|
self.confirm_form()
|
||||||
return self.url_name_args
|
|
||||||
try:
|
def get_question_message(self):
|
||||||
return [self.object.pk]
|
"""
|
||||||
except AttributeError:
|
Returns the question.
|
||||||
return []
|
"""
|
||||||
|
return self.question_message
|
||||||
|
|
||||||
|
def get_answer_options(self):
|
||||||
|
"""
|
||||||
|
Returns the possible answers.
|
||||||
|
|
||||||
|
This is a list of tubles. The first element of the tuble is the key,
|
||||||
|
the second element is shown to the user.
|
||||||
|
"""
|
||||||
|
return self.answer_options
|
||||||
|
|
||||||
|
def confirm_form(self):
|
||||||
|
"""
|
||||||
|
Returns the form to show in the message.
|
||||||
|
"""
|
||||||
|
option_fields = "\n".join([
|
||||||
|
'<button type="submit" class="btn btn-mini" name="%s">%s</button>'
|
||||||
|
% (option[0], unicode(option[1]))
|
||||||
|
for option in self.get_answer_options()])
|
||||||
|
messages.warning(
|
||||||
|
self.request,
|
||||||
|
"""
|
||||||
|
%(message)s
|
||||||
|
<form action="%(url)s" method="post">
|
||||||
|
<input type="hidden" value="%(csrf)s" name="csrfmiddlewaretoken">
|
||||||
|
%(option_fields)s
|
||||||
|
</form>
|
||||||
|
""" % {'message': self.get_question_message(),
|
||||||
|
'url': self.request.path,
|
||||||
|
'csrf': csrf(self.request)['csrf_token'],
|
||||||
|
'option_fields': option_fields})
|
||||||
|
|
||||||
|
def pre_post_redirect(self, request, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
method_name = 'on_clicked_%s' % self.get_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.
|
||||||
|
"""
|
||||||
|
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)
|
||||||
|
|
||||||
|
def get_final_message(self):
|
||||||
|
"""
|
||||||
|
Returns the message to show after the action.
|
||||||
|
|
||||||
|
Uses the attribute 'final_messsage' as default
|
||||||
|
"""
|
||||||
|
return self.final_message
|
||||||
|
|
||||||
|
def create_final_message(self):
|
||||||
|
"""
|
||||||
|
Creates a message.
|
||||||
|
"""
|
||||||
|
messages.success(self.request, self.get_final_message())
|
||||||
|
|
||||||
|
|
||||||
class FormView(PermissionMixin, ExtraContextMixin, UrlMixin, _FormView):
|
class FormView(PermissionMixin, ExtraContextMixin, FormMixin,
|
||||||
def form_invalid(self, form):
|
django_views.FormView):
|
||||||
messages.error(self.request, _('Please check the form for errors.'))
|
"""
|
||||||
return super(FormView, self).form_invalid(form)
|
View for forms.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ModelFormMixin(object):
|
class UpdateView(PermissionMixin, ExtraContextMixin,
|
||||||
def form_valid(self, form):
|
ModelFormMixin, django_views.UpdateView):
|
||||||
self.object = form.save(commit=False)
|
"""
|
||||||
self.manipulate_object(form)
|
View to update an model object.
|
||||||
self.object.save()
|
"""
|
||||||
self.post_save(form)
|
|
||||||
return HttpResponseRedirect(self.get_success_url())
|
|
||||||
|
|
||||||
def manipulate_object(self, form):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def post_save(self, form):
|
|
||||||
form.save_m2m()
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateView(PermissionMixin, UrlMixin, ExtraContextMixin,
|
|
||||||
ModelFormMixin, _UpdateView):
|
|
||||||
success_message = None
|
|
||||||
|
|
||||||
def form_invalid(self, form):
|
|
||||||
messages.error(self.request, _('Please check the form for errors.'))
|
|
||||||
return super(UpdateView, self).form_invalid(form)
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
value = super(UpdateView, self).form_valid(form)
|
|
||||||
messages.success(self.request, self.get_success_message())
|
|
||||||
return value
|
|
||||||
|
|
||||||
def get_success_message(self):
|
def get_success_message(self):
|
||||||
if self.success_message is None:
|
if self.success_message is None:
|
||||||
@ -356,18 +467,11 @@ class UpdateView(PermissionMixin, UrlMixin, ExtraContextMixin,
|
|||||||
return message
|
return message
|
||||||
|
|
||||||
|
|
||||||
class CreateView(PermissionMixin, UrlMixin, ExtraContextMixin,
|
class CreateView(PermissionMixin, ExtraContextMixin,
|
||||||
ModelFormMixin, _CreateView):
|
ModelFormMixin, django_views.CreateView):
|
||||||
success_message = None
|
"""
|
||||||
|
View to create a model object.
|
||||||
def form_invalid(self, form):
|
"""
|
||||||
messages.error(self.request, _('Please check the form for errors.'))
|
|
||||||
return super(CreateView, self).form_invalid(form)
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
value = super(CreateView, self).form_valid(form)
|
|
||||||
messages.success(self.request, self.get_success_message())
|
|
||||||
return value
|
|
||||||
|
|
||||||
def get_success_message(self):
|
def get_success_message(self):
|
||||||
if self.success_message is None:
|
if self.success_message is None:
|
||||||
@ -377,8 +481,12 @@ class CreateView(PermissionMixin, UrlMixin, ExtraContextMixin,
|
|||||||
return message
|
return message
|
||||||
|
|
||||||
|
|
||||||
class DeleteView(SingleObjectMixin, QuestionMixin, RedirectView):
|
class DeleteView(SingleObjectMixin, QuestionView):
|
||||||
question_url_name = None
|
"""
|
||||||
|
View to delete an model object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
success_url = None
|
||||||
success_url_name = None
|
success_url_name = None
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
@ -386,32 +494,53 @@ class DeleteView(SingleObjectMixin, QuestionMixin, RedirectView):
|
|||||||
return super(DeleteView, self).get(request, *args, **kwargs)
|
return super(DeleteView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_redirect_url(self, **kwargs):
|
def get_redirect_url(self, **kwargs):
|
||||||
if self.question_url_name is None and (self.request.method == 'GET' or
|
"""
|
||||||
self.get_answer() == 'no'):
|
Returns the url on which the delete dialog is shown and the url after
|
||||||
return self.object.get_absolute_url()
|
the deleten.
|
||||||
else:
|
|
||||||
return super(DeleteView, self).get_redirect_url(**kwargs)
|
|
||||||
|
|
||||||
def get_question(self):
|
On GET-requests and on aborted POST-requests, redirect 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())
|
||||||
|
else:
|
||||||
|
url = self.get_url(self.success_url_name, self.success_url,
|
||||||
|
args=self.get_url_name_args())
|
||||||
|
return url
|
||||||
|
|
||||||
|
def get_question_message(self):
|
||||||
|
"""
|
||||||
|
Returns the question for the delete dialog.
|
||||||
|
"""
|
||||||
return _('Do you really want to delete %s?') % html_strong(self.object)
|
return _('Do you really want to delete %s?') % html_strong(self.object)
|
||||||
|
|
||||||
def case_yes(self):
|
def on_clicked_yes(self):
|
||||||
|
"""
|
||||||
|
Deletes the object.
|
||||||
|
"""
|
||||||
self.object.delete()
|
self.object.delete()
|
||||||
|
|
||||||
def get_success_message(self):
|
def get_final_message(self):
|
||||||
|
"""
|
||||||
|
Prints the success message to the user.
|
||||||
|
"""
|
||||||
return _('%s was successfully deleted.') % html_strong(self.object)
|
return _('%s was successfully deleted.') % html_strong(self.object)
|
||||||
|
|
||||||
def get_url_name_args(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
class DetailView(PermissionMixin, ExtraContextMixin, django_views.DetailView):
|
||||||
class DetailView(PermissionMixin, ExtraContextMixin, _DetailView):
|
"""
|
||||||
def get(self, request, *args, **kwargs):
|
View to show an model object.
|
||||||
self.object = self.get_object()
|
"""
|
||||||
return super(DetailView, self).get(request, *args, **kwargs)
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PDFView(PermissionMixin, View):
|
class PDFView(PermissionMixin, View):
|
||||||
|
"""
|
||||||
|
View to generate an PDF.
|
||||||
|
"""
|
||||||
|
|
||||||
filename = _('undefined-filename')
|
filename = _('undefined-filename')
|
||||||
top_space = 3
|
top_space = 3
|
||||||
document_title = None
|
document_title = None
|
||||||
@ -480,6 +609,8 @@ def send_register_tab(sender, request, context, **kwargs):
|
|||||||
extra_stylefiles = context['extra_stylefiles']
|
extra_stylefiles = context['extra_stylefiles']
|
||||||
else:
|
else:
|
||||||
extra_stylefiles = []
|
extra_stylefiles = []
|
||||||
|
context.setdefault('extra_javascript', [])
|
||||||
|
|
||||||
# TODO: Do not go over the filesystem by any request
|
# TODO: Do not go over the filesystem by any request
|
||||||
for app in settings.INSTALLED_APPS:
|
for app in settings.INSTALLED_APPS:
|
||||||
try:
|
try:
|
||||||
|
@ -370,14 +370,14 @@ class TestMotionDeleteView(MotionViewTestCase):
|
|||||||
self.assertRedirects(response, '/motion/2/')
|
self.assertRedirects(response, '/motion/2/')
|
||||||
|
|
||||||
def test_admin(self):
|
def test_admin(self):
|
||||||
response = self.admin_client.post('/motion/2/del/', {})
|
response = self.admin_client.post('/motion/2/del/', {'yes': 'yes'})
|
||||||
self.assertRedirects(response, '/motion/')
|
self.assertRedirects(response, '/motion/')
|
||||||
|
|
||||||
def test_delegate(self):
|
def test_delegate(self):
|
||||||
response = self.delegate_client.post('/motion/2/del/', {})
|
response = self.delegate_client.post('/motion/2/del/', {'yes': 'yes'})
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
motion = Motion.objects.get(pk=2).add_submitter(self.delegate)
|
motion = Motion.objects.get(pk=2).add_submitter(self.delegate)
|
||||||
response = self.delegate_client.post('/motion/2/del/', {})
|
response = self.delegate_client.post('/motion/2/del/', {'yes': 'yes'})
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
|
||||||
@ -394,7 +394,7 @@ class TestVersionPermitView(MotionViewTestCase):
|
|||||||
def test_post(self):
|
def test_post(self):
|
||||||
new_version = self.motion1.get_last_version()
|
new_version = self.motion1.get_last_version()
|
||||||
response = self.admin_client.post('/motion/1/version/2/permit/', {'yes': 1})
|
response = self.admin_client.post('/motion/1/version/2/permit/', {'yes': 1})
|
||||||
self.assertRedirects(response, '/motion/1/version/2/')
|
self.assertRedirects(response, '/motion/1/')
|
||||||
self.assertEqual(self.motion1.get_active_version(), new_version)
|
self.assertEqual(self.motion1.get_active_version(), new_version)
|
||||||
|
|
||||||
def test_activate_old_version(self):
|
def test_activate_old_version(self):
|
||||||
|
25
tests/utils/test_utils.py
Normal file
25
tests/utils/test_utils.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Tests for openslides utils.utils
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
TODO: Move this test to the correct place when the projector app is cleaned up.
|
||||||
|
|
||||||
|
:copyright: 2011–2013 by OpenSlides team, see AUTHORS.
|
||||||
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from openslides.utils.test import TestCase
|
||||||
|
from openslides.utils.utils import html_strong, int_or_none
|
||||||
|
|
||||||
|
|
||||||
|
class Test_functions(TestCase):
|
||||||
|
def test_string(self):
|
||||||
|
self.assertEqual(html_strong('some text'), '<strong>some text</strong>')
|
||||||
|
|
||||||
|
def test_int_or_none(self):
|
||||||
|
self.assertEqual(int_or_none('5'), 5)
|
||||||
|
self.assertEqual(int_or_none(5), 5)
|
||||||
|
self.assertIsNone(int_or_none('text'))
|
||||||
|
self.assertIsNone(int_or_none(None))
|
210
tests/utils/test_views.py
Normal file
210
tests/utils/test_views.py
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Tests for openslides utils.utils
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
TODO: Move this test to the correct place when the projector app is cleaned up.
|
||||||
|
|
||||||
|
:copyright: 2011–2013 by OpenSlides team, see AUTHORS.
|
||||||
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.contrib.messages.storage import default_storage
|
||||||
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
from django.core.urlresolvers import clear_url_caches
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from django.http.response import HttpResponseNotAllowed
|
||||||
|
from django.test import RequestFactory
|
||||||
|
from django.test.client import Client
|
||||||
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
|
from openslides.participant.models import User
|
||||||
|
from openslides.utils import views
|
||||||
|
from openslides.utils.signals import template_manipulation
|
||||||
|
from openslides.utils.test import TestCase
|
||||||
|
|
||||||
|
from . import views as test_views
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings(ROOT_URLCONF='tests.utils.urls')
|
||||||
|
class ViewTestCase(TestCase):
|
||||||
|
rf = RequestFactory()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# Clear the cache for the urlresolver, so the overriden settings works.
|
||||||
|
clear_url_caches()
|
||||||
|
|
||||||
|
|
||||||
|
class LoginMixinTest(ViewTestCase):
|
||||||
|
def test_dispatch(self):
|
||||||
|
view = test_views.LoginMixinView.as_view()
|
||||||
|
client = Client()
|
||||||
|
response = client.get('/login_mixin/')
|
||||||
|
self.assertEqual(response['Location'], 'http://testserver/login/?next=/login_mixin/')
|
||||||
|
|
||||||
|
client.login(username='admin', password='admin')
|
||||||
|
response = client.get('/login_mixin/')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(response.content, 'Well done.')
|
||||||
|
|
||||||
|
|
||||||
|
class PermissionMixinTest(ViewTestCase):
|
||||||
|
def test_dispatch(self):
|
||||||
|
client = Client()
|
||||||
|
|
||||||
|
# View without permission_required
|
||||||
|
response = client.get('/permission_mixin1/')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(response.content, 'Well done.')
|
||||||
|
|
||||||
|
# View with permission_required without login
|
||||||
|
response = client.get('/permission_mixin2/')
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
self.assertEqual(response['Location'], 'http://testserver/login/?next=/permission_mixin2/')
|
||||||
|
|
||||||
|
# View with permission_required, with login, without permission
|
||||||
|
client.login(username='admin', password='admin')
|
||||||
|
response = client.get('/permission_mixin2/')
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
# View with permission_required, with login, with permission
|
||||||
|
response = client.get('/permission_mixin3/')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
|
class AjaxMixinTest(ViewTestCase):
|
||||||
|
def test_ajax_get(self):
|
||||||
|
view = test_views.AjaxMixinView()
|
||||||
|
ajax_get = view.ajax_get
|
||||||
|
response = ajax_get(self.rf.get('/', {}))
|
||||||
|
self.assertEqual(response.content, '{"new_context": "newer_context"}')
|
||||||
|
|
||||||
|
def test_get_ajax_context(self):
|
||||||
|
get_ajax_context = test_views.AjaxMixinView().get_ajax_context
|
||||||
|
self.assertEqual(get_ajax_context()['new_context'], 'newer_context')
|
||||||
|
self.assertEqual(
|
||||||
|
get_ajax_context(test_content='some_content')['test_content'],
|
||||||
|
'some_content')
|
||||||
|
|
||||||
|
|
||||||
|
class ExtraContextMixinTest(ViewTestCase):
|
||||||
|
"""
|
||||||
|
Tests the ExtraContextMixin by testen the TemplateView
|
||||||
|
"""
|
||||||
|
def test_get_context_data(self):
|
||||||
|
view = views.TemplateView()
|
||||||
|
get_context_data = view.get_context_data
|
||||||
|
view.request = self.rf.get('/', {})
|
||||||
|
|
||||||
|
context = get_context_data()
|
||||||
|
self.assertIn('tabs', context)
|
||||||
|
|
||||||
|
context = get_context_data(some_context='context')
|
||||||
|
self.assertIn('tabs', context)
|
||||||
|
self.assertIn('some_context', context)
|
||||||
|
|
||||||
|
template_manipulation.connect(set_context, dispatch_uid='set_context_test')
|
||||||
|
context = get_context_data()
|
||||||
|
self.assertIn('tabs', context)
|
||||||
|
self.assertIn('new_context', context)
|
||||||
|
template_manipulation.disconnect(set_context, dispatch_uid='set_context_test')
|
||||||
|
|
||||||
|
|
||||||
|
class UrlMixinTest(ViewTestCase):
|
||||||
|
def test_get_url(self):
|
||||||
|
get_url = test_views.UrlMixinView().get_url
|
||||||
|
|
||||||
|
# url_name has the higher priority
|
||||||
|
self.assertEqual(get_url('test_url_mixin', 'view_url'),
|
||||||
|
'/url_mixin/')
|
||||||
|
|
||||||
|
# If the url_name is none, return the second argument
|
||||||
|
self.assertEqual(get_url(None, 'view_url'),
|
||||||
|
'view_url')
|
||||||
|
|
||||||
|
# Test argument in url
|
||||||
|
self.assertEqual(get_url('test_url_mixin_args', None,
|
||||||
|
args=[1]),
|
||||||
|
'/url_mixin_args/1/')
|
||||||
|
|
||||||
|
# No Url given.
|
||||||
|
self.assertRaisesMessage(
|
||||||
|
ImproperlyConfigured,
|
||||||
|
'No url to redirect to. See openslides.utils.views.UrlMixin for more details.',
|
||||||
|
get_url, None, None)
|
||||||
|
|
||||||
|
def test_get_url_with_object(self):
|
||||||
|
get_url = test_views.UrlMixinViewWithObject().get_url
|
||||||
|
|
||||||
|
self.assertEqual(get_url(None, None),
|
||||||
|
'default_url')
|
||||||
|
self.assertEqual(get_url(None, None, use_absolute_url_link='detail'),
|
||||||
|
'detail_url')
|
||||||
|
|
||||||
|
def test_get_url_name_args(self):
|
||||||
|
view = test_views.UrlMixinViewWithObject()
|
||||||
|
get_url_name_args = view.get_url_name_args
|
||||||
|
view.url_name_args = [1]
|
||||||
|
|
||||||
|
self.assertEqual(get_url_name_args(), [1])
|
||||||
|
|
||||||
|
view.url_name_args = None
|
||||||
|
self.assertEqual(get_url_name_args(), [])
|
||||||
|
|
||||||
|
view.object.pk = 5
|
||||||
|
self.assertEqual(get_url_name_args(), [5])
|
||||||
|
|
||||||
|
|
||||||
|
## class QuestionMixinTest(ViewTestCase):
|
||||||
|
## def test_get_redirect_url(self):
|
||||||
|
## view = views.QuestionMixin()
|
||||||
|
## get_redirect_url = view.get_redirect_url
|
||||||
|
##
|
||||||
|
## view.request = self.rf.get('/')
|
||||||
|
## view.question_url = 'redirect_to_get_url'
|
||||||
|
## self.assertEqual(get_redirect_url(), 'redirect_to_get_url')
|
||||||
|
##
|
||||||
|
## view.request = self.rf.post('/')
|
||||||
|
## view.success_url = 'redirect_to_post_url'
|
||||||
|
## self.assertEqual(get_redirect_url(), 'redirect_to_post_url')
|
||||||
|
##
|
||||||
|
## def test_get_question(self):
|
||||||
|
## view = views.QuestionMixin()
|
||||||
|
## get_redirect_url = view.get_question
|
||||||
|
##
|
||||||
|
## self.assertEqual(get_redirect_url(), 'Are you sure?')
|
||||||
|
##
|
||||||
|
## view.question = 'new_question'
|
||||||
|
## self.assertEqual(get_redirect_url(), 'new_question')
|
||||||
|
##
|
||||||
|
## def test_get_answer_options(self):
|
||||||
|
## view = views.QuestionMixin()
|
||||||
|
## get_answer_options = view.get_answer_options
|
||||||
|
##
|
||||||
|
## self.assertIn('yes', dict(get_answer_options()))
|
||||||
|
## self.assertIn('no', dict(get_answer_options()))
|
||||||
|
##
|
||||||
|
## view.answer_options = [('new_answer', 'Answer')]
|
||||||
|
## self.assertNotIn('yes', dict(get_answer_options()))
|
||||||
|
## self.assertIn('new_answer', dict(get_answer_options()))
|
||||||
|
##
|
||||||
|
## def test_confirm_form(self):
|
||||||
|
## view = views.QuestionMixin()
|
||||||
|
## confirm_form = view.confirm_form
|
||||||
|
## view.request = self.rf.get('/')
|
||||||
|
## view.request._messages = default_storage(view.request)
|
||||||
|
##
|
||||||
|
## confirm_form()
|
||||||
|
## message = "".join(view.request._messages._queued_messages[0].message.split())
|
||||||
|
## self.assertEqual(
|
||||||
|
## message, 'Areyousure?<formaction="/"method="post">'
|
||||||
|
## '<inputtype="hidden"value="NOTPROVIDED"name="csrfmiddlewaretoken">' '<buttontype="submit"class="btnbtn-mini"name="yes">Yes</button>'
|
||||||
|
## '<buttontype="submit"class="btnbtn-mini"name="no">No</button></form>')
|
||||||
|
|
||||||
|
|
||||||
|
def set_context(sender, request, context, **kwargs):
|
||||||
|
"""
|
||||||
|
receiver for testing the ExtraContextMixin
|
||||||
|
"""
|
||||||
|
context.update({'new_context': 'some new context'})
|
29
tests/utils/urls.py
Normal file
29
tests/utils/urls.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
|
from openslides.urls import urlpatterns
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns += patterns(
|
||||||
|
'',
|
||||||
|
url(r'^url_mixin/$',
|
||||||
|
views.UrlMixinView.as_view(),
|
||||||
|
name='test_url_mixin'),
|
||||||
|
|
||||||
|
url(r'^url_mixin_args/(?P<arg>\d+)/$',
|
||||||
|
views.UrlMixinView.as_view(),
|
||||||
|
name='test_url_mixin_args'),
|
||||||
|
|
||||||
|
url(r'^login_mixin/$',
|
||||||
|
views.LoginMixinView.as_view()),
|
||||||
|
|
||||||
|
url(r'^permission_mixin1/$',
|
||||||
|
views.PermissionMixinView.as_view()),
|
||||||
|
|
||||||
|
url(r'^permission_mixin2/$',
|
||||||
|
views.PermissionMixinView.as_view(permission_required='permission_string')),
|
||||||
|
|
||||||
|
url(r'^permission_mixin3/$',
|
||||||
|
views.PermissionMixinView.as_view(permission_required='agenda.can_see_agenda')),
|
||||||
|
)
|
47
tests/utils/views.py
Normal file
47
tests/utils/views.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
|
from openslides.utils import views
|
||||||
|
|
||||||
|
|
||||||
|
class GetAbsoluteUrl(object):
|
||||||
|
"""
|
||||||
|
Generates objects with a get_absolute_url method.
|
||||||
|
|
||||||
|
Helper Class for the tests.
|
||||||
|
"""
|
||||||
|
def get_absolute_url(self, link='default'):
|
||||||
|
if link == 'detail':
|
||||||
|
url = 'detail_url'
|
||||||
|
elif link == 'update':
|
||||||
|
url = 'update_url'
|
||||||
|
elif link == 'default':
|
||||||
|
url = 'default_url'
|
||||||
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
class LoginMixinView(views.LoginMixin, views.View):
|
||||||
|
def get(self, *args, **kwargs):
|
||||||
|
response = HttpResponse('Well done.')
|
||||||
|
response.status_code = 200
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class PermissionMixinView(views.PermissionMixin, views.View):
|
||||||
|
def get(self, *args, **kwargs):
|
||||||
|
response = HttpResponse('Well done.')
|
||||||
|
response.status_code = 200
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class AjaxMixinView(views.AjaxMixin, views.View):
|
||||||
|
def get_ajax_context(self, **kwargs):
|
||||||
|
return super(AjaxMixinView, self).get_ajax_context(
|
||||||
|
new_context='newer_context', **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class UrlMixinView(views.UrlMixin, views.View):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UrlMixinViewWithObject(views.UrlMixin, views.View):
|
||||||
|
object = GetAbsoluteUrl()
|
Loading…
Reference in New Issue
Block a user