diff --git a/openslides/motion/models.py b/openslides/motion/models.py index fb252e2a8..8e777e1ee 100644 --- a/openslides/motion/models.py +++ b/openslides/motion/models.py @@ -30,7 +30,8 @@ from openslides.projector.api import register_slidemodel from openslides.projector.models import SlideMixin from openslides.agenda.models import Item -from .workflow import motion_workflow_choices, get_state, State, WorkflowError +from .workflow import (motion_workflow_choices, get_state, State, WorkflowError, + DUMMY_STATE) # TODO: Save submitter and supporter in the same table @@ -237,6 +238,9 @@ class Motion(SlideMixin, models.Model): except IndexError: return self.new_version + def is_submitter(self, person): + self.submitter.filter(person=person).exists() + def is_supporter(self, person): return self.supporter.filter(person=person).exists() @@ -266,7 +270,7 @@ class Motion(SlideMixin, models.Model): Create a new poll for this motion """ # TODO: auto increment the poll_number in the Database - if self.state.poll: + if self.state.create_poll: poll_number = self.polls.aggregate(Max('poll_number'))['poll_number__max'] or 0 poll = MotionPoll.objects.create(motion=self, poll_number=poll_number + 1) poll.set_options() @@ -281,7 +285,7 @@ class Motion(SlideMixin, models.Model): try: return get_state(self.state_id) except WorkflowError: - return None + return DUMMY_STATE def set_state(self, next_state): """ @@ -321,6 +325,40 @@ class Motion(SlideMixin, models.Model): ## number = self.number or '[%s]' % ugettext('no number') ## return '(%s %s)' % (ugettext('motion'), number) + def get_allowed_actions(self, person): + """ + Gets a dictonary with all allowed actions for a specific person. + + The dictonary contains the following actions. + + * edit + * delete + * create_poll + * support + * unsupport + * change_state + * reset_state + """ + actions = { + 'edit': (self.is_submitter(person) and + self.state.edit_as_submitter) or + person.has_perm('motion.can_manage_motion'), + + 'create_poll': person.has_perm('motion.can_manage_motion') and + self.state.create_poll, + + 'support': self.state.support and + config['motion_min_supporters'] > 0 and + not self.is_submitter(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'] = 'change_state' + return actions + class MotionVersion(models.Model): title = models.CharField(max_length=255, verbose_name=ugettext_lazy("Title")) diff --git a/openslides/motion/signals.py b/openslides/motion/signals.py index 5735545a8..b482cf38c 100644 --- a/openslides/motion/signals.py +++ b/openslides/motion/signals.py @@ -15,6 +15,7 @@ from django.utils.translation import ugettext as _ from openslides.config.signals import default_config_value + @receiver(default_config_value, dispatch_uid="motion_default_config") def default_config(sender, key, **kwargs): return { diff --git a/openslides/motion/templates/motion/motion_detail.html b/openslides/motion/templates/motion/motion_detail.html index ceae96d0d..234b057ca 100644 --- a/openslides/motion/templates/motion/motion_detail.html +++ b/openslides/motion/templates/motion/motion_detail.html @@ -35,26 +35,15 @@

{% trans "Vote results" %}:

- {% with motion.polls.all as polls %} - {% if not polls.exists %} - {% if perms.motion.can_manage_motion %} - - - {% trans 'New vote' %} - - - {% else %} - - - {% endif %} - {% endif %} + {% with motion.polls.all as polls %} - {% endwith %} + {% if allowed_actions.create_poll %} + + {% trans 'New vote' %} + + {% endif %} + {% endwith %} {% endblock %} diff --git a/openslides/motion/views.py b/openslides/motion/views.py index bb7405629..3183d020d 100644 --- a/openslides/motion/views.py +++ b/openslides/motion/views.py @@ -64,6 +64,11 @@ class MotionDetailView(DetailView): raise Http404 return object + def get_context_data(self, **kwargs): + context = super(MotionDetailView, self).get_context_data(**kwargs) + context['allowed_actions'] = self.object.get_allowed_actions(self.request.user) + return context + motion_detail = MotionDetailView.as_view() diff --git a/openslides/motion/workflow.py b/openslides/motion/workflow.py index 18348c756..d5533186a 100644 --- a/openslides/motion/workflow.py +++ b/openslides/motion/workflow.py @@ -8,12 +8,14 @@ ugettext = lambda s: s _workflow = None class State(object): - def __init__(self, id, name, next_states=[], poll=False, support=False): + def __init__(self, id, name, next_states=[], create_poll=False, support=False, + edit_as_submitter=False): self.id = id self.name = name self.next_states = next_states - self.poll = poll + self.create_poll = create_poll self.support = support + self.edit_as_submitter=edit_as_submitter def __unicode__(self): return self.name @@ -61,6 +63,7 @@ def get_state(state='default'): populate_workflow(default_state, _workflow) return get_state(state) + def populate_workflow(state, workflow): workflow[state.id] = state for s in state.next_states: @@ -68,13 +71,17 @@ def populate_workflow(state, workflow): populate_workflow(s, workflow) -default_workflow = State('pub', ugettext('Published'), support=True, next_states=[ - State('per', ugettext('Permitted'), poll=True, next_states=[ - State('acc', ugettext('Accepted')), - State('rej', ugettext('Rejected')), - State('wit', ugettext('Withdrawed')), - State('adj', ugettext('Adjourned')), - State('noc', ugettext('Not Concerned')), - State('com', ugettext('Commited a bill')), - State('rev', ugettext('Needs Review'))]), - State('nop', ugettext('Rejected (not authorized)'))]) +DUMMY_STATE = State('dummy', ugettext('Unknwon state')) + +default_workflow = State('pub', ugettext('Published'), support=True, + edit_as_submitter=True, next_states=[ + State('per', ugettext('Permitted'), create_poll=True, + edit_as_submitter=True, next_states=[ + State('acc', ugettext('Accepted')), + State('rej', ugettext('Rejected')), + State('wit', ugettext('Withdrawed')), + State('adj', ugettext('Adjourned')), + State('noc', ugettext('Not Concerned')), + State('com', ugettext('Commited a bill')), + State('rev', ugettext('Needs Review'))]), + State('nop', ugettext('Rejected (not authorized)'))])