diff --git a/openslides/motion/forms.py b/openslides/motion/forms.py index 9f35e4bab..028328837 100644 --- a/openslides/motion/forms.py +++ b/openslides/motion/forms.py @@ -19,6 +19,9 @@ from .models import Motion class BaseMotionForm(forms.ModelForm, CssClassMixin): + """ + Form to automaticly save the version data for a motion. + """ class Meta: model = Motion fields = () @@ -38,12 +41,20 @@ class BaseMotionForm(forms.ModelForm, CssClassMixin): widget=forms.Textarea(), required=False, label=_("Reason")) -class MotionCreateForm(BaseMotionForm): - pass +class MotionSubmitterMixin(forms.ModelForm): + submitter = MultiplePersonFormField(label=_("Submitter")) -class MotionUpdateForm(BaseMotionForm): - pass +class MotionSupporterMixin(forms.ModelForm): + supporter = MultiplePersonFormField(required=False, label=_("Supporters")) + + + + +class MotionTrivialChangesMixin(object): + trivial_change = forms.BooleanField( + required=False, label=_("Trivial change"), + help_text=_("Trivial changes don't create a new version.")) class ConfigForm(forms.Form, CssClassMixin): diff --git a/openslides/motion/models.py b/openslides/motion/models.py index 6b68bda19..19afe043e 100644 --- a/openslides/motion/models.py +++ b/openslides/motion/models.py @@ -31,49 +31,21 @@ from openslides.projector.models import SlideMixin from openslides.agenda.models import Item -RELATION = ( - (1, _('Submitter')), - (2, _('Supporter'))) - - -class RelatedPersonsManager(models.Manager): - """ - Manager for MotionRelatedPersons. - - Returns a custom manager with gives a specific queryset for one type of - persons. - """ - def __init__(self, relation, *args, **kwargs): - super(RelatedPersonsManager, self).__init__(*args, **kwargs) - for key, value in RELATION: - if key == relation: - self.relation = key - break - else: - raise ValueError('Unknown relation with id %d' % relation) - - def get_query_set(self): - return (super(RelatedPersonsManager, self).get_query_set() - .filter(relation=self.relation)) - - -class MotionRelatedPersons(models.Model): - """ - Saves the all persons related to a motion. - - relation = 1: submitter - relation = 2: supporter - - The custom manager submitter and supporter return a queryset with the - specific persons. - """ - submitter = RelatedPersonsManager(relation=1) - supporter = RelatedPersonsManager(relation=2) - objects = models.Manager() - +# TODO: Save submitter and supporter in the same table +class MotionSubmitter(models.Model): person = PersonField() - relation = models.IntegerField(default=1, choices=RELATION) - motion = models.ForeignKey('Motion', related_name="persons") + motion = models.ForeignKey('Motion', related_name="submitter") + + def __unicode__(self): + return unicode(self.person) + + +class MotionSupporter(models.Model): + person = PersonField() + motion = models.ForeignKey('Motion', related_name="supporter") + + def __unicode__(self): + return unicode(self.person) class Motion(SlideMixin, models.Model): @@ -198,20 +170,6 @@ class Motion(SlideMixin, models.Model): reason = property(get_reason, set_reason) - @property - def submitter(self): - """ - Return a queryset with all submitter of this motion. - """ - return MotionRelatedPersons.submitter.filter(motion=self) - - @property - def supporter(self): - """ - Returns a queryset with all supporter of this motion. - """ - return MotionRelatedPersons.supporter.filter(motion=self) - @property def new_version(self): """ @@ -292,9 +250,15 @@ class MotionVersion(models.Model): note = models.TextField(null=True, blank=True) def __unicode__(self): - return "%s Version %s" % (self.motion, self.get_version_number()) + return "%s Version %s" % (self.motion, self.version_number) - def get_version_number(self): + def get_absolute_url(self, link='detail'): + if link == 'view' or link == 'detail': + return reverse('motion_version_detail', args=[str(self.motion.id), + str(self.version_number)]) + + @property + def version_number(self): if self.pk is None: return 'new' return (MotionVersion.objects.filter(motion=self.motion) diff --git a/openslides/motion/templates/motion/motion_detail.html b/openslides/motion/templates/motion/motion_detail.html index 9cd880936..07f048750 100644 --- a/openslides/motion/templates/motion/motion_detail.html +++ b/openslides/motion/templates/motion/motion_detail.html @@ -4,9 +4,21 @@ {% load i18n %} {% load staticfiles %} -{% block title %}{{ block.super }} – {% trans "Motion" %} "{{ version.title }}"{% endblock %} +{% block title %}{{ block.super }} – {% trans "Motion" %} "{{ motion.title }}"{% endblock %} {% block content %} -

Titel: {{ object.title }}

-

Text: {{ object.text }}

+

Titel: {{ motion.title }}

+

Text: {{ motion.text }}

+

Reason: {{ motion.reason }}

+

Submitter: {% for submitter in motion.submitter.all %}{{ submitter.person }} {% endfor %}

+ +
    +{% for motion_version in motion.versions.all %} + {% if motion_version.id == motion.version.id %} +
  1. {{ motion_version }}
  2. + {% else %} +
  3. {{ motion_version }}
  4. + {% endif %} +{% endfor %} +
{% endblock %} diff --git a/openslides/motion/templates/motion/motion_list.html b/openslides/motion/templates/motion/motion_list.html index 32118ff73..9cb2e5506 100644 --- a/openslides/motion/templates/motion/motion_list.html +++ b/openslides/motion/templates/motion/motion_list.html @@ -8,9 +8,9 @@ {% block content %}

{% trans "Motions" %}

- + {% endblock %} diff --git a/openslides/motion/views.py b/openslides/motion/views.py index 3121c3efd..c46697f20 100644 --- a/openslides/motion/views.py +++ b/openslides/motion/views.py @@ -17,6 +17,7 @@ from django.db import transaction from django.db.models import Model from django.utils.translation import ugettext as _, ugettext_lazy from django.views.generic.detail import SingleObjectMixin +from django.http import Http404 from openslides.utils.pdf import stylesheet from openslides.utils.views import ( @@ -26,8 +27,10 @@ from openslides.utils.template import Tab from openslides.utils.utils import html_strong from openslides.projector.api import get_active_slide from openslides.projector.projector import Widget, SLIDE -from .models import Motion -from .forms import MotionCreateForm, MotionUpdateForm +from openslides.config.models import config +from .models import Motion, MotionSubmitter +from .forms import (BaseMotionForm, MotionSubmitterMixin, MotionSupporterMixin, + MotionTrivialChangesMixin) from django.views.generic.edit import ModelFormMixin @@ -55,7 +58,10 @@ class MotionDetailView(DetailView): object = super(MotionDetailView, self).get_object() version_id = self.kwargs.get('version_id', None) if version_id is not None: - object.version = int(version_id) -1 + try: + object.version = int(version_id) -1 + except IndexError: + raise Http404 return object motion_detail = MotionDetailView.as_view() @@ -66,9 +72,28 @@ class MotionMixin(object): Mixin to add save the version-data to the motion-object """ def manipulate_object(self, form): + super(MotionMixin, self).manipulate_object(form) for attr in ['title', 'text', 'reason']: setattr(self.object, attr, form.cleaned_data[attr]) + def post_save(self, form): + super(MotionMixin, self).post_save(form) + # TODO: only delete and save neccessary submitters + self.object.submitter.all().delete() + MotionSubmitter.objects.bulk_create( + [MotionSubmitter(motion=self.object, person=person) + for person in form.cleaned_data['submitter']]) + + def get_form_class(self): + form_classes = [BaseMotionForm] + if config['motion_allow_trivial_change']: + form_classes.append(MotionTrivialChangesMixin) + if self.request.user.has_perm('motion.can_manage_motion'): + form_classes.append(MotionSubmitterMixin) + if config['motion_min_supporters'] > 0: + form_classes.append(MotionSupporterMixin) + return type('MotionForm', tuple(form_classes), {}) + class MotionCreateView(MotionMixin, CreateView): """ @@ -76,7 +101,6 @@ class MotionCreateView(MotionMixin, CreateView): """ permission_required = 'motion.can_create_motion' model = Motion - form_class = MotionCreateForm motion_create = MotionCreateView.as_view() @@ -85,7 +109,21 @@ class MotionUpdateView(MotionMixin, UpdateView): """ Update a motion. """ + # TODO: set permissions model = Motion - form_class = MotionUpdateForm + apply_url = '' motion_edit = MotionUpdateView.as_view() + + +def register_tab(request): + """ + Register the projector tab. + """ + selected = request.path.startswith('/motion/') + return Tab( + title=_('Motions'), + url=reverse('motion_list'), + permission=request.user.has_perm('motion.can_see_motion'), + selected=selected, + ) diff --git a/openslides/utils/templatetags/tags.py b/openslides/utils/templatetags/tags.py index 96809af10..dfa8e02f2 100644 --- a/openslides/utils/templatetags/tags.py +++ b/openslides/utils/templatetags/tags.py @@ -35,6 +35,7 @@ def active(request, pattern): @register.simple_tag def model_url(object, link='view'): + # TODO: Rename to object_url return object.get_absolute_url(link) diff --git a/openslides/utils/views.py b/openslides/utils/views.py index c13087592..412ddac88 100644 --- a/openslides/utils/views.py +++ b/openslides/utils/views.py @@ -113,7 +113,7 @@ class SuccessUrlMixin(object): if 'apply' in self.request.POST: return reverse(self.get_apply_url(), args=[self.object.id]) if self.success_url: - url = reverse(success_url) + url = reverse(self.success_url) else: try: url = self.object.get_absolute_url() @@ -230,12 +230,15 @@ class ModelFormMixin(object): self.object = form.save(commit=False) self.manipulate_object(form) self.object.save() - form.save_m2m() + 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, SuccessUrlMixin, ExtraContextMixin, ModelFormMixin, _UpdateView):