OpenSlides/openslides/motion/models.py

317 lines
10 KiB
Python
Raw Normal View History

2011-07-31 10:46:29 +02:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
2012-10-24 11:04:23 +02:00
openslides.motion.models
2011-07-31 10:46:29 +02:00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2012-10-24 11:04:23 +02:00
Models for the motion app.
2011-07-31 10:46:29 +02:00
2012-04-25 22:29:19 +02:00
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
2011-07-31 10:46:29 +02:00
:license: GNU GPL, see LICENSE for more details.
"""
from datetime import datetime
2012-04-12 16:21:30 +02:00
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models import Max
from django.dispatch import receiver
2012-06-30 15:21:27 +02:00
from django.utils.translation import pgettext
from django.utils.translation import ugettext_lazy as _, ugettext_noop, ugettext
2011-07-31 10:46:29 +02:00
from openslides.utils.utils import _propper_unicode
from openslides.utils.person import PersonField
from openslides.config.models import config
from openslides.config.signals import default_config_value
from openslides.poll.models import (
BaseOption, BasePoll, CountVotesCast, CountInvalid, BaseVote)
from openslides.participant.models import User
from openslides.projector.api import register_slidemodel
from openslides.projector.models import SlideMixin
from openslides.agenda.models import Item
2013-01-06 12:07:37 +01:00
RELATION = (
(1, _('Submitter')),
(2, _('Supporter')))
2011-07-31 10:46:29 +02:00
2013-01-06 12:07:37 +01:00
class RelatedPersonsManager(models.Manager):
2013-01-26 12:28:51 +01:00
"""
Manager for MotionRelatedPersons.
Returns a custom manager with gives a specific queryset for one type of
persons.
"""
2013-01-06 12:07:37 +01:00
def __init__(self, relation, *args, **kwargs):
super(RelatedPersonsManager, self).__init__(*args, **kwargs)
for key, value in RELATION:
if key == relation:
self.relation = key
break
2011-09-06 10:41:06 +02:00
else:
2013-01-06 12:07:37 +01:00
raise ValueError('Unknown relation with id %d' % relation)
2011-09-06 10:41:06 +02:00
2013-01-06 12:07:37 +01:00
def get_query_set(self):
return (super(RelatedPersonsManager, self).get_query_set()
.filter(relation=self.relation))
2011-07-31 10:46:29 +02:00
2013-01-06 12:07:37 +01:00
class MotionRelatedPersons(models.Model):
2013-01-26 12:28:51 +01:00
"""
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.
"""
2013-01-06 12:07:37 +01:00
submitter = RelatedPersonsManager(relation=1)
supporter = RelatedPersonsManager(relation=2)
objects = models.Manager()
2011-07-31 10:46:29 +02:00
2013-01-06 12:07:37 +01:00
person = PersonField()
relation = models.IntegerField(default=1, choices=RELATION)
motion = models.ForeignKey('Motion', related_name="persons")
class Motion(SlideMixin, models.Model):
2013-01-26 12:28:51 +01:00
"""
The Motion-Model.
"""
2013-01-06 12:07:37 +01:00
prefix = "motion" # Rename this in the slide-system
# TODO: Use this attribute for the default_version, if the permission system
# is deactivated. Maybe it has to be renamed.
permitted_version = models.ForeignKey(
'MotionVersion', null=True, blank=True, related_name="permitted")
# TODO: Define status
status = models.CharField(max_length=3)
# Log (Translatable)
identifier = models.CharField(max_length=255, null=True, blank=True,
unique=True)
category = models.ForeignKey('Category', null=True, blank=True)
# TODO proposal
# Maybe rename to master_copy
master = models.ForeignKey('self', null=True, blank=True)
2011-07-31 10:46:29 +02:00
2013-01-06 12:07:37 +01:00
class Meta:
permissions = (
('can_see_motion', ugettext_noop('Can see motions')),
('can_create_motion', ugettext_noop('Can create motions')),
('can_support_motion', ugettext_noop('Can support motions')),
('can_manage_motion', ugettext_noop('Can manage motions')),
)
# TODO: order per default by category and identifier
# ordering = ('number',)
2013-01-06 12:07:37 +01:00
def __unicode__(self):
return self.get_title()
# TODO: Use transaction
def save(self, *args, **kwargs):
2013-01-26 12:28:51 +01:00
"""
Saves the motion. Create or update a motion_version object
"""
2013-01-06 12:07:37 +01:00
super(Motion, self).save(*args, **kwargs)
new_data = False
for attr in ['_title', '_text', '_reason']:
if hasattr(self, attr):
new_data = True
break
2013-01-26 12:28:51 +01:00
need_new_version = True # TODO: Do we need a new version (look in config)
2013-01-06 12:07:37 +01:00
if hasattr(self, '_version') or (new_data and need_new_version):
version = self.new_version
del self._new_version
version.motion = self # Test if this line is realy neccessary.
elif new_data and not need_new_version:
# TODO: choose an explicit version
version = self.last_version
else:
2013-01-06 12:07:37 +01:00
# We do not need to save the motion version
return
2013-01-06 12:07:37 +01:00
for attr in ['title', 'text', 'reason']:
_attr = '_%s' % attr
2011-07-31 10:46:29 +02:00
try:
2013-01-06 12:07:37 +01:00
setattr(version, attr, getattr(self, _attr))
2011-07-31 10:46:29 +02:00
except AttributeError:
2013-01-06 12:07:37 +01:00
setattr(version, attr, getattr(self.last_version, attr))
version.save()
2012-02-14 16:31:21 +01:00
2013-01-06 12:07:37 +01:00
def get_absolute_url(self, link='detail'):
if link == 'view' or link == 'detail':
return reverse('motion_detail', args=[str(self.id)])
if link == 'edit':
2012-10-24 11:04:23 +02:00
return reverse('motion_edit', args=[str(self.id)])
2011-07-31 10:46:29 +02:00
if link == 'delete':
2012-10-24 11:04:23 +02:00
return reverse('motion_delete', args=[str(self.id)])
2011-07-31 10:46:29 +02:00
2013-01-06 12:07:37 +01:00
def get_title(self):
2013-01-26 12:28:51 +01:00
"""
Get the title of the motion. The titel is taken from motion.version
"""
2011-07-31 10:46:29 +02:00
try:
2013-01-06 12:07:37 +01:00
return self._title
2011-07-31 10:46:29 +02:00
except AttributeError:
2013-01-26 12:28:51 +01:00
return self.version.title
2011-07-31 10:46:29 +02:00
2013-01-06 12:07:37 +01:00
def set_title(self, title):
2013-01-26 12:28:51 +01:00
"""
Set the titel of the motion. The titel will me saved in motion.save()
"""
2013-01-06 12:07:37 +01:00
self._title = title
2011-07-31 10:46:29 +02:00
2013-01-06 12:07:37 +01:00
title = property(get_title, set_title)
2011-07-31 10:46:29 +02:00
2013-01-06 12:07:37 +01:00
def get_text(self):
2013-01-26 12:28:51 +01:00
"""
Get the text of the motion. Simular to get_title()
"""
2013-01-06 12:07:37 +01:00
try:
return self._text
except AttributeError:
2013-01-26 12:28:51 +01:00
return self.version.text
2011-07-31 10:46:29 +02:00
2013-01-06 12:07:37 +01:00
def set_text(self, text):
2013-01-26 12:28:51 +01:00
"""
Set the text of the motion. Simular to set_title()
"""
2013-01-06 12:07:37 +01:00
self._text = text
text = property(get_text, set_text)
def get_reason(self):
2013-01-26 12:28:51 +01:00
"""
Get the reason of the motion. Simular to get_title()
"""
2013-01-06 12:07:37 +01:00
try:
return self._reason
except AttributeError:
2013-01-26 12:28:51 +01:00
return self.version.reason
2013-01-06 12:07:37 +01:00
def set_reason(self, reason):
2013-01-26 12:28:51 +01:00
"""
Set the reason of the motion. Simular to set_title()
"""
2013-01-06 12:07:37 +01:00
self._reason = reason
reason = property(get_reason, set_reason)
2011-07-31 10:46:29 +02:00
2013-01-06 12:07:37 +01:00
@property
def submitter(self):
2013-01-26 12:28:51 +01:00
"""
Return a queryset with all submitter of this motion.
"""
2013-01-06 12:07:37 +01:00
return MotionRelatedPersons.submitter.filter(motion=self)
2012-02-14 16:31:21 +01:00
2013-01-06 12:07:37 +01:00
@property
def supporter(self):
2013-01-26 12:28:51 +01:00
"""
Returns a queryset with all supporter of this motion.
"""
2013-01-06 12:07:37 +01:00
return MotionRelatedPersons.supporter.filter(motion=self)
2012-02-14 16:31:21 +01:00
2013-01-26 12:28:51 +01:00
@property
def new_version(self):
"""
On the first call, it creates a new version. On any later call, it
use the existing new version.
The new_version object will be deleted when it is saved into the db
"""
try:
return self._new_version
except AttributeError:
self._new_version = MotionVersion(motion=self)
return self._new_version
2013-01-06 12:07:37 +01:00
def get_version(self, version_id):
2013-01-26 12:28:51 +01:00
"""
Return a specific version from version_id
"""
2013-01-06 12:07:37 +01:00
# TODO: Check case, if version_id is not one of this motion
return self.versions.get(pk=version_id)
2013-01-26 12:28:51 +01:00
def get_version(self):
"""
Get the "active" version object. This version will be used to get the
data for this motion.
"""
2013-01-06 12:07:37 +01:00
try:
2013-01-26 12:28:51 +01:00
return self._version
2013-01-06 12:07:37 +01:00
except AttributeError:
# TODO: choose right version via config
return self.last_version
2012-02-14 16:31:21 +01:00
2013-01-26 12:28:51 +01:00
def set_version(self, version):
"""
Set the "active" version object.
If version is None, the last_version will be used.
If version is a version object, this object will be used.
If version is Int, the N version of this motion will be used.
"""
2013-01-06 12:07:37 +01:00
if version is None:
try:
2013-01-26 12:28:51 +01:00
del self._version
2013-01-06 12:07:37 +01:00
except AttributeError:
pass
else:
if type(version) is int:
version = self.versions.all()[version]
elif type(version) is not MotionVersion:
raise ValueError('The argument \'version\' has to be int or '
'MotionVersion, not %s' % type(version))
2013-01-26 12:28:51 +01:00
# TODO: Test, that the version is one of this motion
self._version = version
2012-02-14 16:31:21 +01:00
2013-01-26 12:28:51 +01:00
version = property(get_version, set_version)
2012-02-15 12:36:50 +01:00
2013-01-06 12:07:37 +01:00
@property
def last_version(self):
2013-01-26 12:28:51 +01:00
"""
Get the newest version of the motion
"""
2013-01-06 12:07:37 +01:00
# TODO: Fix the case, that the motion has no Version
try:
return self.versions.order_by('id').reverse()[0]
except IndexError:
return self.new_version
2013-01-06 12:07:37 +01:00
class MotionVersion(models.Model):
title = models.CharField(max_length=255, verbose_name=_("Title"))
text = models.TextField(verbose_name=_("Text"))
reason = models.TextField(null=True, blank=True, verbose_name=_("Reason"))
rejected = models.BooleanField(default=False)
creation_time = models.DateTimeField(auto_now=True)
motion = models.ForeignKey(Motion, related_name='versions')
identifier = models.CharField(max_length=255, verbose_name=_("Version identifier"))
note = models.TextField(null=True, blank=True)
2013-01-06 12:07:37 +01:00
def __unicode__(self):
return "%s Version %s" % (self.motion, self.get_version_number())
def get_version_number(self):
if self.pk is None:
return 'new'
return (MotionVersion.objects.filter(motion=self.motion)
.filter(id__lte=self.pk).count())
2012-04-12 16:21:30 +02:00
2013-01-06 12:07:37 +01:00
class Category(models.Model):
name = models.CharField(max_length=255, verbose_name=_("Category name"))
prefix = models.CharField(max_length=32, verbose_name=_("Category prefix"))
def __unicode__(self):
return self.name
2013-01-06 12:07:37 +01:00
class Comment(models.Model):
motion_version = models.ForeignKey(MotionVersion)
text = models.TextField()
author = PersonField()
creation_time = models.DateTimeField(auto_now=True)