diff --git a/openslides/motion/models.py b/openslides/motion/models.py
index 0fdeee171..3dd2683aa 100644
--- a/openslides/motion/models.py
+++ b/openslides/motion/models.py
@@ -49,7 +49,8 @@ class Motion(SlideMixin, models.Model):
"""
active_version = models.ForeignKey('MotionVersion', null=True,
- related_name="active_version")
+ related_name="active_version",
+ on_delete=models.SET_NULL)
"""
Points to a specific version.
@@ -315,20 +316,24 @@ class Motion(SlideMixin, models.Model):
Is saved in a MotionVersion object.
"""
- def get_new_version(self):
+ def get_new_version(self, **kwargs):
"""
Return a version object, not saved in the database.
The version data of the new version object is populated with the data
- set via motion.title, motion.text, motion.reason. If the data is not set,
- it is populated with the data from the last version object.
+ set via motion.title, motion.text, motion.reason if these data are
+ not given as keyword arguments. If the data is not set in the motion
+ attributes, it is populated with the data from the last version
+ object if such object exists.
"""
- new_version = MotionVersion(motion=self)
+ new_version = MotionVersion(motion=self, **kwargs)
if self.versions.exists():
last_version = self.get_last_version()
else:
last_version = None
for attr in ['title', 'text', 'reason']:
+ if attr in kwargs:
+ continue
_attr = '_%s' % attr
data = getattr(self, _attr, None)
if data is None and last_version is not None:
@@ -561,16 +566,20 @@ class MotionVersion(models.Model):
def __unicode__(self):
"""Return a string, representing this object."""
counter = self.version_number or ugettext_lazy('new')
- return "%s Version %s" % (self.motion, counter) # TODO: Should this really be self.motion or the title of the specific version?
+ return "Motion %s, Version %s" % (self.motion_id, counter)
def get_absolute_url(self, link='detail'):
- """Return the URL of this Version.
+ """
+ Return the URL of this Version.
- The keyargument link can be 'view' or 'detail'.
+ The keyargument link can be 'detail' or 'delete'.
"""
if link == 'view' or link == 'detail':
return reverse('motion_version_detail', args=[str(self.motion.id),
str(self.version_number)])
+ if link == 'delete':
+ return reverse('motion_version_delete', args=[str(self.motion.id),
+ str(self.version_number)])
@property
def active(self):
diff --git a/openslides/motion/templates/motion/motion_detail.html b/openslides/motion/templates/motion/motion_detail.html
index bb594f21f..c89a61e9c 100644
--- a/openslides/motion/templates/motion/motion_detail.html
+++ b/openslides/motion/templates/motion/motion_detail.html
@@ -130,7 +130,6 @@
- {# TODO: add delete version function #}
diff --git a/openslides/motion/urls.py b/openslides/motion/urls.py
index 59ac4eec7..dbe919f99 100644
--- a/openslides/motion/urls.py
+++ b/openslides/motion/urls.py
@@ -50,6 +50,11 @@ urlpatterns = patterns('openslides.motion.views',
name='motion_version_permit',
),
+ url(r'^(?P\d+)/version/(?P\d+)/del/$',
+ 'version_delete',
+ name='motion_version_delete',
+ ),
+
url(r'^(?P\d+)/diff/$',
'version_diff',
name='motion_version_diff',
diff --git a/openslides/motion/views.py b/openslides/motion/views.py
index c82e6024f..769fc97d7 100644
--- a/openslides/motion/views.py
+++ b/openslides/motion/views.py
@@ -247,6 +247,26 @@ class MotionDeleteView(DeleteView):
motion_delete = MotionDeleteView.as_view()
+class VersionDeleteView(DeleteView):
+ """
+ View to delete a motion version.
+ """
+ model = MotionVersion
+ permission_required = 'motion.can_manage_motion'
+ success_url_name = 'motion_detail'
+
+ def get_object(self):
+ motion_id = int(self.kwargs.get('pk'))
+ version_number = int(self.kwargs.get('version_number'))
+ return MotionVersion.objects.get(motion=motion_id,
+ version_number=version_number)
+
+ def get_success_url_name_args(self):
+ return (self.object.motion_id, )
+
+version_delete = VersionDeleteView.as_view()
+
+
class VersionPermitView(SingleObjectMixin, QuestionMixin, RedirectView):
"""
View to permit a version of a motion.
@@ -255,6 +275,7 @@ class VersionPermitView(SingleObjectMixin, QuestionMixin, RedirectView):
question_url_name = 'motion_version_detail'
success_url_name = 'motion_version_detail'
success_message = ugettext_lazy('Version successfully permitted.')
+ permission_required = 'motion.can_manage_motion'
def get(self, *args, **kwargs):
"""
diff --git a/openslides/utils/views.py b/openslides/utils/views.py
index d8bb38a86..2229bda2c 100644
--- a/openslides/utils/views.py
+++ b/openslides/utils/views.py
@@ -172,6 +172,7 @@ class QuestionMixin(object):
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:
diff --git a/tests/motion/test_views.py b/tests/motion/test_views.py
index 54e120d24..6cda947c9 100644
--- a/tests/motion/test_views.py
+++ b/tests/motion/test_views.py
@@ -344,3 +344,19 @@ class TestVersionPermitView(MotionViewTestCase):
self.motion1 = Motion.objects.get(pk=1)
self.assertEqual(self.motion1.active_version, first_version)
self.assertEqual(self.motion1.versions.count(), 2)
+
+
+class TestVersionDeleteView(MotionViewTestCase):
+ def test_get(self):
+ response = self.check_url('/motion/1/version/1/del/', self.admin_client, 302)
+ self.assertRedirects(response, '/motion/1/version/1/')
+
+ def test_post(self):
+ new_version = self.motion1.get_new_version
+ self.motion1.save(use_version=new_version(title='new', text='new'))
+ self.motion1.save(use_version=new_version(title='new2', text='new'))
+ self.assertEqual(self.motion1.versions.count(), 3)
+
+ response = self.admin_client.post('/motion/1/version/2/del/', {'yes': 1})
+ self.assertRedirects(response, '/motion/1/')
+ self.assertEqual(self.motion1.versions.count(), 2)