diff --git a/openslides/agenda/templates/agenda/item_row.html b/openslides/agenda/templates/agenda/item_row.html index 1ae13e9c2..386f00ee8 100644 --- a/openslides/agenda/templates/agenda/item_row.html +++ b/openslides/agenda/templates/agenda/item_row.html @@ -31,7 +31,7 @@ {% if perms.agenda.can_see_orga_items %} {% if item.duration %} - {{ item.duration }}h + {{ item.duration }}h {% if start and end %}{% endif %} {% endif %} {% endif %} diff --git a/openslides/agenda/templates/agenda/overview.html b/openslides/agenda/templates/agenda/overview.html index b311de352..06557bac5 100644 --- a/openslides/agenda/templates/agenda/overview.html +++ b/openslides/agenda/templates/agenda/overview.html @@ -55,7 +55,7 @@

{% trans "Agenda" %} {% if perms.agenda.can_manage_agenda %} - {% trans "New" %} + {% trans "New" %} {% endif %} PDF diff --git a/openslides/assignment/templates/assignment/overview.html b/openslides/assignment/templates/assignment/overview.html index afd499d48..c27e534b0 100644 --- a/openslides/assignment/templates/assignment/overview.html +++ b/openslides/assignment/templates/assignment/overview.html @@ -9,7 +9,7 @@

{% trans "Elections" %} {% if perms.assignment.can_manage_assignment %} - {% trans "New" %} + {% trans "New" %} {% endif %} {% if perms.assignment.can_see_assignment %} PDF diff --git a/openslides/motion/models.py b/openslides/motion/models.py index 88f6c665e..f8de1544d 100644 --- a/openslides/motion/models.py +++ b/openslides/motion/models.py @@ -19,6 +19,7 @@ from django.core.urlresolvers import reverse from django.db import models from django.db.models import Max from django.dispatch import receiver +from django.utils import formats from django.utils.translation import pgettext from django.utils.translation import ugettext_lazy, ugettext_noop, ugettext as _ @@ -101,7 +102,7 @@ class Motion(SlideMixin, models.Model): and the config 'motion_create_new_version' is set to - 'ALLWASY_CREATE_NEW_VERSION'. + 'ALWAYS_CREATE_NEW_VERSION'. """ if not self.state: self.reset_state() @@ -296,10 +297,20 @@ class Motion(SlideMixin, models.Model): except IndexError: return self.new_version + @property + def submitters(self): + return sorted([object.person for object in self.submitter.all()], + key=lambda person: person.sort_name) + def is_submitter(self, person): """Return True, if person is a submitter of this motion. Else: False.""" self.submitter.filter(person=person).exists() + @property + def supporters(self): + return sorted([object.person for object in self.supporter.all()], + key=lambda person: person.sort_name) + def is_supporter(self, person): """Return True, if person is a supporter of this motion. Else: False.""" return self.supporter.filter(person=person).exists() @@ -379,13 +390,17 @@ class Motion(SlideMixin, models.Model): 'support': (self.state.allow_support and config['motion_min_supporters'] > 0 and - not self.is_submitter(person)), + not self.is_submitter(person) and + not self.is_supporter(person)), + + 'unsupport': (self.state.allow_support and + not self.is_submitter(person) and + self.is_supporter(person)), 'change_state': person.has_perm('motion.can_manage_motion'), } actions['delete'] = actions['edit'] # TODO: Only if the motion has no number - actions['unsupport'] = actions['support'] actions['reset_state'] = actions['change_state'] return actions @@ -394,7 +409,7 @@ class Motion(SlideMixin, models.Model): Message should be in english and translatable. - e.G: motion.write_log(ugettext_noob('Message Text')) + e.g.: motion.write_log(ugettext_noob('Message Text')) """ MotionLog.objects.create(motion=self, message=message, person=person) @@ -546,11 +561,11 @@ class MotionLog(models.Model): def __unicode__(self): """Return a string, representing the log message.""" - # TODO: write time in the local time format. + time = formats.date_format(self.time, 'DATETIME_FORMAT') if self.person is None: - return "%s %s" % (self.time, _(self.message)) + return "%s %s" % (time, _(self.message)) else: - return "%s %s by %s" % (self.time, _(self.message), self.person) + return "%s %s by %s" % (time, _(self.message), self.person) class MotionVote(BaseVote): diff --git a/openslides/motion/templates/motion/motion_detail.html b/openslides/motion/templates/motion/motion_detail.html index ccf616aab..a9de961b6 100644 --- a/openslides/motion/templates/motion/motion_detail.html +++ b/openslides/motion/templates/motion/motion_detail.html @@ -4,26 +4,141 @@ {% load i18n %} {% load staticfiles %} -{% block title %}{{ block.super }} – {% trans "Motion" %} "{{ motion.title }}"{% endblock %} +{% block title %}{{ block.super }} – {% trans "Motion" %} {{ motion.number }}{% endblock %} {% block content %} -

Titel: {{ motion.title }}

-

Text: {{ motion.text }}

-

Reason: {{ motion.reason }}

-

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

-

Supporter: {% for supporter in motion.supporter.all %}{{ supporter.person }} {% endfor %}

-

Active Version: {{ motion.active_version }}

-

State: {{ motion.state }}

-

possible stats:

- +

+ {{ motion.title }} +
+ + {% if motion.number != None %} + {% trans "Motion" %} {{ motion.number }}, + {% else %} + [{% trans "no number" %}], + {% endif %} + {% trans "Version" %} {{ motion.version.version_number }} + + +
+ {% trans "Back to overview" %} + PDF + + {% if perms.projector.can_manage_projector %} + + + + {% endif %} +
+ + {% trans 'More actions' %} + + + +
+
+
+

+
+
+ {% if motion.active_version.id != motion.version.id %} + + {% if motion.version == motion.public_version %} + {% trans "This is not the newest version." %} {% trans "Go to version" %} {{ motion.last_version.version_number }}. + {% else %} + {% trans "This is not the authorized version." %} {% trans "Go to version" %} {{ motion.public_version.aid }}. + {% endif %} + {% endif %} -

Versions

+ +

{% trans "Motion text" %}:

+ {{ motion.version.text|linebreaks }} +
+ + +

{% trans "Reason" %}:

+ {% if motion.version.reason %} + {{ motion.version.reason|linebreaks }} + {% else %} + – + {% endif %} +
+ + + {% for version in motion.versions.all %} + {% if forloop.first %} +

{% trans "Version history" %}:

+ + + + + + + + + + {% endif %} + + + + + + + + + {% if forloop.last %} +
{% trans "Version" %}{% trans "Time" %}{% trans "Title" %}{% trans "Text" %}{% trans "Reason" %}
+ {% if version == motion.active_version %} + + {% else %} + {% if perms.motion.can_manage_motion %} + + {% endif %} + {% if not version.rejected and version.id > motion.active_version.id and perms.motion.can_manage_motion %} + + {% endif %} + {% endif %} + {% if version.rejected %} + + {% endif %} + {{ version.version_number }}{{ version.creation_time }} + {% ifchanged %} + {{ version.title }} + {% else %} + [{% trans "unchanged" %}] + {% endifchanged %} + + {% ifchanged %} + {{ version.text|linebreaks }} + {% else %} + [{% trans "unchanged" %}] + {% endifchanged %} + + {% ifchanged %} + {{ version.reason|linebreaks }} + {% else %} + [{% trans "unchanged" %}] + {% endifchanged %} +
+ {% endif %} + {% endfor %} + +
    {% for motion_version in motion.versions.all %}
  1. @@ -41,60 +156,152 @@
  2. {% endfor %}
+ -

{% trans "Vote results" %}:

- {% with motion.polls.all as polls %} -
    + + {% if perms.motion.can_manage_motion %} + +
    +
      + {% for message in motion.log_messages.all %} +
    • {{ message }}
    • + {% endfor %} +
    +
    + {% endif %} +
+ + +
+
+ +
{% trans "Submitter" %}:
+ {% for submitter in motion.submitter.all %} + {{ submitter.person }}{% if not forloop.last %}, {% endif %} + {% endfor %} + + + {% if min_supporters > 0 %} +
{% trans "Supporters" %}: *
+ {% if not motion.supporters %} + - + {% else %} +
    + {% for supporter in motion.supporter.all %} +
  1. {{ supporter }}
  2. + {% endfor %} +
+ {% endif %} + {% endif %} + + +
{% trans "Status" %}:
+ {% if motion.state_id != "pub" %} + {# TODO: trans motion.state #} + {{ motion.state }} +
+ {% endif %} + {% for note in motion.notes %} + {{ note }} + {% if not forloop.last %}
{% endif %} + {% endfor %} + + +
{% trans "Vote results" %}:
+ {% with motion.polls.all as polls %} +
    {% for poll in polls %} {% if perms.motion.can_manage_motion or poll.has_votes %} -
  1. - {% if perms.motion.can_manage_motion %} - {{ forloop.counter }}. {% trans "Vote" %} - - - - - - - {% elif poll.has_votes %} - {{ forloop.counter }}. {% trans "Vote" %}: - {% endif %} -
    - {% if poll.has_votes %} - {% with poll.get_options.0 as option %} - {{ option.Yes }}
    - {{ option.No }}
    - {{ option.Abstain }}
    - {{ poll.print_votesinvalid }}
    -
    - {{ poll.print_votescast }} -
    - {% endwith %} - {% else %} +
  2. {% trans "Vote" %} {% if perms.motion.can_manage_motion %} - - {% trans 'Enter result' %} - - {% endif %} - {% endif %} -
  3. + + + {% endif %} +
    + {% if poll.has_votes %} + {% with poll.get_options.0 as option %} + {{ option.Yes }}
    + {{ option.No }}
    + {{ option.Abstain }}
    + {{ poll.print_votesinvalid }}
    +
    + {{ poll.print_votescast }} +
    + {% endwith %} + {% else %} + {% if perms.motion.can_manage_motion %} + {% trans 'No results' %} + {% endif %} + {% endif %} + {% endif %} {% endfor %} - +
{% if allowed_actions.create_poll %} - - {% trans 'New vote' %} + + {% trans 'New vote' %} + + {% endif %} + {% endwith %} + + +
{% trans "Creation Time" %}:
+ {# TODO: use creation time of _first_ version #} + {{ motion.version.creation_time }} + + + {% if allowed_actions.wit and user in motion.submitters %} +

+ + {% trans 'Withdraw motion' %} {% endif %} - {% endwith %} + + {% if perms.motion.can_support_motion and min_supporters > 0 %} + {% if allowed_actions.unsupport %} +

+ + {% trans 'Unsupport' %} + + {% endif %} + {% if allowed_actions.support %} +

+ + {% trans 'Support' %} + + {% endif %} + {% endif %} + + + {% if min_supporters > 0 %} +

+ * {% trans "minimum required supporters" %}: {{ min_supporters }} + {% endif %} +
+ + {% if perms.motion.can_manage_motion %} + +
+

{% trans "Manage motion" %}

+
+ {% for state in motion.state.next_states.all %} + {{ state }} + {% endfor %} +
+

+
+
{% trans "For administration only:" %}
+ + {% trans 'Reset state' %} + +
+ {% endif %} +
+
-

log

- {% endblock %} diff --git a/openslides/motion/templates/motion/motion_form.html b/openslides/motion/templates/motion/motion_form.html index ddffb8254..42dd96c27 100644 --- a/openslides/motion/templates/motion/motion_form.html +++ b/openslides/motion/templates/motion/motion_form.html @@ -2,25 +2,35 @@ {% load tags %} {% load i18n %} -{% load staticfiles %} -{% block title %}{{ block.super }} – {% trans "Motion Form" %}{% endblock %} +{% block title %} + {{ block.super }} – + {% if motion %} + {% trans "Edit motion" %} + {% else %} + {% trans "New motion" %} + {% endif %} +{% endblock %} {% block content %} -

{% trans "Motions Forms" %}

+

+ {% if motion %} + {% trans "Edit motion" %} + {% else %} + {% trans "New motion" %} + {% endif %} + + {% trans "Back to overview" %} + +

{% csrf_token %} - {{ form.as_p }} - - - - + {% include "form.html" %} +

+ {% include "formbuttons_saveapply.html" %} + + {% trans 'Cancel' %} +

* {% trans "required" %}
{% endblock %} diff --git a/openslides/motion/templates/motion/motion_list.html b/openslides/motion/templates/motion/motion_list.html index 9cb2e5506..3bdf74e87 100644 --- a/openslides/motion/templates/motion/motion_list.html +++ b/openslides/motion/templates/motion/motion_list.html @@ -2,15 +2,104 @@ {% load tags %} {% load i18n %} -{% load staticfiles %} {% block title %}{{ block.super }} – {% trans "Motions" %}{% endblock %} {% block content %} -

{% trans "Motions" %}

-
    +

    + {% trans "Motions" %} + + {% if perms.motion.can_create_motion %} + {% trans "New" %} + {% endif %} + {% if perms.motion.can_manage_motion %} + {# {% trans 'Import' %}#} + {% endif %} + PDF + +

    + +
    + {% if min_supporters > 0 %} + + {% endif %} + + + +
    + {{ motion_list|length }} + {% blocktrans count counter=motion_list|length context "number of motions"%}motion{% plural %}motions{% endblocktrans %} + + + + + + {% if min_supporters > 0 %} + + {% endif %} + + + + + {% for motion in motion_list %} -
  1. {{ motion }}
  2. + + + + {% if min_supporters > 0 %} + + {% endif %} + + + {# TODO: user creation_time of _first_ version #} + + + + {% empty %} + + + {% endfor %} - +
    {% trans "#" %}{% trans "Motion title" %}{% trans "Number of supporters" %}{% trans "Status" %}{% trans "Submitter" %}{% trans "Creation Time" %}{% trans "Actions" %}
    {{ motion.number }}{{ motion.title }}{# motion.count_supporters #}{{ motion.state }} + {% for submitter in motion.submitter.all %} + {{ submitter.person }}{% if not forloop.last %}, {% endif %} + {% endfor %} + {{ motion.version.creation_time }} + + {% if perms.projector.can_manage_projector %} + + + + {% endif %} + {% if perms.motion.can_manage_motion %} + + + + {% if "delete" in useractions %} + + + + {% endif %} + {% endif %} + + PDF + + +
    {% trans "No motions available." %}
    {% endblock %} diff --git a/openslides/motion/templates/motion/poll_form.html b/openslides/motion/templates/motion/poll_form.html index f7cd3635a..f3bc4aa68 100644 --- a/openslides/motion/templates/motion/poll_form.html +++ b/openslides/motion/templates/motion/poll_form.html @@ -1,48 +1,78 @@ {% extends 'base.html' %} {% load i18n %} -{% load staticfiles %} -{% load tags %} + +{% block title %} + {{ block.super }} - {% trans "Motion" %} {{ motion.number }}, {{ ballot }}. {% trans "Vote" %} +{% endblock %} {% block content %} -

    {{ motion }}

    - {% trans "Special values" %}: -1 = {% trans 'majority' %}; -2 = {% trans 'undocumented' %} -
    {% csrf_token %} - {{ pre_form }} - - - - - - - {% for value in forms.0 %} - - - - - {% endfor %} - - - - - - - - -
    {% trans "Option" %}{% trans "Votes" %}
    {{ value.label }}{{ value.errors }}{{ value }}
    {% trans "Invalid votes" %}{{ pollform.votesinvalid.errors }}{{ pollform.votesinvalid }}
    {% trans "Votes cast" %}{{ pollform.votescast.errors }}{{ pollform.votescast }}
    - - {{ post_form }} - -

    - - - - {% trans 'Cancel' %} +

    + {{ motion }} +
    + + {% trans "Motion" %} {{ motion.number }}, {{ ballot }}. {% trans "Vote" %} + + +
    + {% trans "Back to motion" %} + + {% if perms.projector.can_manage_projector %} + + -

    - + {% endif %} +
    +
    +

    + +

    +{% trans "Special values" %}: -1 = {% trans 'majority' %} | -2 = {% trans 'undocumented' %} +

    +
    {% csrf_token %} + {{ pre_form }} + + + + + + + {% for value in forms.0 %} + + + + + {% endfor %} + + + + + + + + +
    {% trans "Option" %}{% trans "Votes" %}
    {{ value.label }}{{ value.errors }}{{ value }}
    {% trans "Invalid votes" %}{{ pollform.votesinvalid.errors }}{{ pollform.votesinvalid }}
    {% trans "Votes cast" %}{{ pollform.votescast.errors }}{{ pollform.votescast }}
    + + {{ post_form }} + + +

    +{# TODO: create ballot paper instead of motion_detail_pdf ! #} + + {% trans 'Ballot paper as PDF' %} + +

    + +
    + + + + {% trans 'Cancel' %} + +
    +
    {% endblock %} diff --git a/openslides/motion/views.py b/openslides/motion/views.py index e3cbfe499..da7d27dd4 100644 --- a/openslides/motion/views.py +++ b/openslides/motion/views.py @@ -74,6 +74,7 @@ class MotionDetailView(GetVersionMixin, DetailView): """ context = super(MotionDetailView, self).get_context_data(**kwargs) context['allowed_actions'] = self.object.get_allowed_actions(self.request.user) + context['min_supporters'] = int(config['motion_min_supporters']) return context motion_detail = MotionDetailView.as_view() @@ -246,7 +247,6 @@ class SupportView(SingleObjectMixin, QuestionMixin, RedirectView): def check_permission(self, request): """Return True if the user can support or unsupport the motion. Else: False.""" - allowed_actions = self.object.get_allowed_actions(request.user) if self.support and not allowed_actions['support']: messages.error(request, _('You can not support this motion.')) @@ -373,6 +373,10 @@ class PollDeleteView(PollMixin, DeleteView): super(PollDeleteView, self).case_yes() self.object.write_log(ugettext_noop('Poll deleted'), self.request.user) + def get_redirect_url(self, **kwargs): + """Return the URL to the DetailView of the motion.""" + return reverse('motion_detail', args=[self.object.motion.pk]) + poll_delete = PollDeleteView.as_view() diff --git a/openslides/participant/templates/participant/group_overview.html b/openslides/participant/templates/participant/group_overview.html index f86c9b5ba..c5115685b 100644 --- a/openslides/participant/templates/participant/group_overview.html +++ b/openslides/participant/templates/participant/group_overview.html @@ -8,7 +8,7 @@ {% block content %}

    {% trans "Groups" %} - {% trans "New" %} + {% trans "New" %} {% trans "Back to participants overview" %}

    diff --git a/openslides/participant/templates/participant/import.html b/openslides/participant/templates/participant/import.html index e374845b7..e5c8ce024 100644 --- a/openslides/participant/templates/participant/import.html +++ b/openslides/participant/templates/participant/import.html @@ -20,7 +20,7 @@ {% trans 'Required CSV file encoding: UTF-8 (Unicode).' %}

    -

    {% trans 'A CSV example file is available in OpenSlides Wiki.' %} +

    {% trans 'A CSV example file is available in OpenSlides Wiki.' %}

    {% csrf_token %} diff --git a/openslides/participant/templates/participant/overview.html b/openslides/participant/templates/participant/overview.html index fb28d61a9..07c9ae69a 100644 --- a/openslides/participant/templates/participant/overview.html +++ b/openslides/participant/templates/participant/overview.html @@ -17,7 +17,7 @@
    {% if perms.participant.can_manage_participant %} - {% trans "New" %} + {% trans "New" %} {% trans "Groups" %} {% trans 'Import' %} {% endif %} diff --git a/openslides/static/styles/base.css b/openslides/static/styles/base.css index 7075a4103..05d137c98 100644 --- a/openslides/static/styles/base.css +++ b/openslides/static/styles/base.css @@ -80,6 +80,10 @@ a:hover { padding: 8px 5px 4px 5px; } +/* Log */ +#log { + padding-left: 14px; +} /** Utils **/ tr.offline td, li.offline {