From 545d4be04fa1b5b01837bf6866c61a200e78de72 Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Thu, 14 Mar 2013 22:18:56 +0100 Subject: [PATCH 1/3] fixed update of person_api --- .gitignore | 1 + .travis.yml | 1 + manage.py | 5 ++-- openslides/utils/person/models.py | 14 +++++++--- tests/person_api/__init__.py | 0 tests/person_api/models.py | 46 +++++++++++++++++++++++++++++++ tests/person_api/tests.py | 34 +++++++++++++++++++++++ tests/settings.py | 36 ++++++++++++++++++++++++ 8 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 tests/person_api/__init__.py create mode 100644 tests/person_api/models.py create mode 100644 tests/person_api/tests.py create mode 100644 tests/settings.py diff --git a/.gitignore b/.gitignore index b8b12bc11..d6170257f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *~ settings.py database.sqlite +!tests/settings.py # Package building docs/_build/* diff --git a/.travis.yml b/.travis.yml index 9a87327fd..870aa5947 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,5 +6,6 @@ install: - pip install -r requirements.txt --use-mirrors - python extras/scripts/create_local_settings.py script: + - export DJANGO_SETTINGS_MODULE=tests.settings - coverage run ./manage.py test tests && coverage report -m - pep8 --max-line-length=150 --exclude="urls.py," --statistics openslides diff --git a/manage.py b/manage.py index af82b6f37..2618206eb 100644 --- a/manage.py +++ b/manage.py @@ -12,6 +12,7 @@ from django.core.management import execute_from_command_line from openslides.main import get_user_config_path, setup_django_environment if __name__ == "__main__": - setup_django_environment( - get_user_config_path('openslides', 'settings.py')) + if 'DJANGO_SETTINGS_MODULE' not in os.environ: + setup_django_environment( + get_user_config_path('openslides', 'settings.py')) execute_from_command_line(sys.argv) diff --git a/openslides/utils/person/models.py b/openslides/utils/person/models.py index f22cdddc4..35f969705 100644 --- a/openslides/utils/person/models.py +++ b/openslides/utils/person/models.py @@ -12,7 +12,7 @@ from django.db import models from .forms import PersonFormField -from .api import get_person, generate_person_id, Person +from .api import get_person, generate_person_id class PersonField(models.fields.Field): @@ -29,7 +29,7 @@ class PersonField(models.fields.Field): """ Convert string value to a User Object. """ - if isinstance(value, Person): + if isinstance(value, PersonMixin): return value elif value is None: return None @@ -60,5 +60,11 @@ class PersonMixin(object): raise AttributeError("%s has to have a attribute 'person_prefix'" % self) - def __repr__(self): - return 'Person: %s' % self.person_id + def __unicode__(self): + return 'MyPerson: %s' % self.person_id + + def prepare_database_save(self, field): + if type(field) is PersonField: + return self.person_id + else: + return super(PersonMixin, self).prepare_database_save(field) diff --git a/tests/person_api/__init__.py b/tests/person_api/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/person_api/models.py b/tests/person_api/models.py new file mode 100644 index 000000000..22fa3ad31 --- /dev/null +++ b/tests/person_api/models.py @@ -0,0 +1,46 @@ +from django.db import models +from django.dispatch import receiver + +from openslides.utils.person.models import PersonMixin, PersonField +from openslides.utils.person.signals import receive_persons +from openslides.utils.person.api import Person + + +class TestPerson(PersonMixin, models.Model): + person_prefix = 'test' + name = models.CharField(max_length='255') + + def __unicode__(self): + return self.name + + +class TestPersonToPerson(object): + def __init__(self, person_prefix_filter=None, id_filter=None): + self.person_prefix_filter = person_prefix_filter + self.id_filter = id_filter + + def __iter__(self): + if (not self.person_prefix_filter or + self.person_prefix_filter == TestPerson.person_prefix): + if self.id_filter: + try: + yield TestPerson.objects.get(pk=self.id_filter) + except TestPerson.DoesNotExist: + pass + else: + for user in TestPerson.objects.all(): + yield user + + +@receiver(receive_persons, dispatch_uid="test_person") +def receive_persons(sender, **kwargs): + return TestPersonToPerson( + person_prefix_filter=kwargs['person_prefix_filter'], + id_filter=kwargs['id_filter']) + + +class TestModel(models.Model): + person = PersonField() + + def __unicode__(self): + return self.person diff --git a/tests/person_api/tests.py b/tests/person_api/tests.py new file mode 100644 index 000000000..95c59d056 --- /dev/null +++ b/tests/person_api/tests.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + openslides.person_api.tests + ~~~~~~~~~~~~~~~~~~~~~~~ + + Unit test for the person api. + + :copyright: 2011 - 2013 by OpenSlides team, see AUTHORS. + :license: GNU GPL, see LICENSE for more details. +""" + +from django.test.client import Client +from django.db.models.query import EmptyQuerySet + +from openslides.utils.test import TestCase + +from .models import TestPerson, TestModel + + +class ItemTest(TestCase): + def setUp(self): + self.person1 = TestPerson.objects.create(name='test1') + + def test_update_of_person_field(self): + self.assertEqual(self.person1.person_id, 'test:1') + + # save person field + test_object = TestModel.objects.create(person=self.person1) + self.assertEqual(test_object.person, self.person1) + + # update person field + test_object.save() + self.assertEqual(TestModel.objects.get(pk=test_object.pk).person, self.person1) diff --git a/tests/settings.py b/tests/settings.py new file mode 100644 index 000000000..097862b34 --- /dev/null +++ b/tests/settings.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import openslides.main +from openslides.global_settings import * + +# Use 'DEBUG = True' to get more details for server errors +# (Default for releases: 'False') +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +DBPATH = u'database.sqlite' + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': DBPATH, + 'USER': '', + 'PASSWORD': '', + 'HOST': '', + 'PORT': '', + } +} + +# Set timezone +TIME_ZONE = 'Europe/Berlin' + +# Make this unique, and don't share it with anybody. +SECRET_KEY = 'secred' + +# Add OpenSlides plugins to this list (see example entry in comment) +INSTALLED_PLUGINS = ( + 'tests.person_api', +) + +INSTALLED_APPS += INSTALLED_PLUGINS From 1a2ebf7b3b4fcd98695d891203c05fb967475022 Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Fri, 15 Mar 2013 01:34:17 +0100 Subject: [PATCH 2/3] removed some unused functions --- openslides/motion/models.py | 1 - openslides/participant/views.py | 2 +- openslides/utils/utils.py | 21 --------------------- 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/openslides/motion/models.py b/openslides/motion/models.py index 1c14a35cb..010b1a855 100644 --- a/openslides/motion/models.py +++ b/openslides/motion/models.py @@ -23,7 +23,6 @@ from django.utils import formats from django.utils.translation import pgettext from django.utils.translation import ugettext_lazy, ugettext_noop, ugettext as _ -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 diff --git a/openslides/participant/views.py b/openslides/participant/views.py index 0b63db3a0..b3c890ef9 100644 --- a/openslides/participant/views.py +++ b/openslides/participant/views.py @@ -29,7 +29,7 @@ from django.utils.translation import ugettext as _, ugettext_lazy, activate from openslides.utils.pdf import stylesheet from openslides.utils.template import Tab from openslides.utils.utils import ( - template, decodedict, encodedict, delete_default_permissions, html_strong) + template, delete_default_permissions, html_strong) from openslides.utils.views import ( FormView, PDFView, CreateView, UpdateView, DeleteView, PermissionMixin, RedirectView, SingleObjectMixin, ListView, QuestionMixin, DetailView) diff --git a/openslides/utils/utils.py b/openslides/utils/utils.py index d2ab19fca..1ddb5c751 100644 --- a/openslides/utils/utils.py +++ b/openslides/utils/utils.py @@ -131,26 +131,5 @@ def ajax_request(data): return HttpResponse(json.dumps(data)) -def _propper_unicode(text): - if not isinstance(text, unicode): - return u"%s" % text.decode('UTF-8') - else: - return text - - -def decodedict(dict): - newdict = {} - for key in dict: - newdict[key] = [dict[key][0].encode('utf-8')] - return newdict - - -def encodedict(dict): - newdict = {} - for key in dict: - newdict[key] = [unicode(dict[key][0].decode('utf-8'))] - return newdict - - def html_strong(string): return u"%s" % string From 3832aa417806142d772041c9a4642e4afd0cf807 Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Fri, 15 Mar 2013 11:35:03 +0100 Subject: [PATCH 3/3] Tests for the motion views --- openslides/motion/models.py | 5 +- openslides/motion/views.py | 5 + openslides/utils/templatetags/tags.py | 5 - tests/motion/test_views.py | 138 ++++++++++++++++++++++++++ 4 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 tests/motion/test_views.py diff --git a/openslides/motion/models.py b/openslides/motion/models.py index 0adc1cd51..17f81f238 100644 --- a/openslides/motion/models.py +++ b/openslides/motion/models.py @@ -338,13 +338,16 @@ class Motion(SlideMixin, models.Model): def is_submitter(self, person): """Return True, if person is a submitter of this motion. Else: False.""" - self.submitter.filter(person=person).exists() + return 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 add_submitter(self, person): + MotionSubmitter.objects.create(motion=self, person=person) + def is_supporter(self, person): """Return True, if person is a supporter of this motion. Else: False.""" return self.supporter.filter(person=person).exists() diff --git a/openslides/motion/views.py b/openslides/motion/views.py index 9748d7ec9..788e7c50b 100644 --- a/openslides/motion/views.py +++ b/openslides/motion/views.py @@ -165,6 +165,11 @@ class MotionCreateView(MotionMixin, CreateView): self.object.write_log(ugettext_noop('Motion created'), self.request.user) return value + def post_save(self, form): + super(MotionCreateView, self).post_save(form) + if not 'submitter' in form.cleaned_data: + self.object.add_submitter(self.request.user) + motion_create = MotionCreateView.as_view() diff --git a/openslides/utils/templatetags/tags.py b/openslides/utils/templatetags/tags.py index dfa8e02f2..e8cc0d5c5 100644 --- a/openslides/utils/templatetags/tags.py +++ b/openslides/utils/templatetags/tags.py @@ -16,11 +16,6 @@ from openslides.config.models import config register = template.Library() -@register.simple_tag -def get_min_supporters(): - return config['motion_min_supporters'] - - @register.simple_tag def get_config(key): return config[key] diff --git a/tests/motion/test_views.py b/tests/motion/test_views.py new file mode 100644 index 000000000..15cc01c79 --- /dev/null +++ b/tests/motion/test_views.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + Tests for openslides.motion.models + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + :copyright: 2011, 2012 by OpenSlides team, see AUTHORS. + :license: GNU GPL, see LICENSE for more details. +""" + +from django.test.client import Client + +from openslides.utils.test import TestCase +from openslides.participant.models import User, Group +from openslides.motion.models import Motion + + +class MotionViewTestCase(TestCase): + def setUp(self): + # Admin + self.admin = User.objects.create_superuser('admin', 'admin@admin.admin', 'admin') + self.admin_client = Client() + self.admin_client.login(username='admin', password='admin') + + # Delegate + self.delegate = User.objects.create_user('delegate', 'delegate@user.user', 'delegate') + delegate_group = Group.objects.get(name='Delegates') + self.delegate.groups.add(delegate_group) + self.delegate.save() + self.delegate_client = Client() + self.delegate_client.login(username='delegate', password='delegate') + + # Registered + self.registered = User.objects.create_user('registered', 'registered@user.user', 'registered') + self.registered_client = Client() + self.registered_client.login(username='registered', password='registered') + + self.motion1 = Motion.objects.create(title='motion1') + self.motion2 = Motion.objects.create(title='motion2') + + def check_url(self, url, test_client, response_cose): + response = test_client.get(url) + self.assertEqual(response.status_code, response_cose) + return response + + +class TestMotionListView(MotionViewTestCase): + def test_get(self): + self.check_url('/motion/', self.admin_client, 200) + + +class TestMotionDetailView(MotionViewTestCase): + def test_get(self): + self.check_url('/motion/1/', self.admin_client, 200) + self.check_url('/motion/2/', self.admin_client, 200) + self.check_url('/motion/500/', self.admin_client, 404) + + +class TestMotionCreateView(MotionViewTestCase): + url = '/motion/new/' + + def test_get(self): + self.check_url(self.url, self.admin_client, 200) + + def test_admin(self): + self.assertFalse(Motion.objects.filter(versions__title='new motion').exists()) + response = self.admin_client.post(self.url, {'title': 'new motion', + 'text': 'motion text', + 'reason': 'motion reason', + 'submitter': self.admin}) + self.assertEqual(response.status_code, 302) + self.assertTrue(Motion.objects.filter(versions__title='new motion').exists()) + + def test_delegate(self): + self.assertFalse(Motion.objects.filter(versions__title='delegate motion').exists()) + response = self.delegate_client.post(self.url, {'title': 'delegate motion', + 'text': 'motion text', + 'reason': 'motion reason', + 'submitter': self.admin}) + self.assertEqual(response.status_code, 302) + motion = Motion.objects.get(versions__title='delegate motion') + self.assertTrue(motion.is_submitter(self.delegate)) + + def test_registered(self): + self.assertFalse(Motion.objects.filter(versions__title='registered motion').exists()) + response = self.registered_client.post(self.url, {'title': 'registered motion', + 'text': 'motion text', + 'reason': 'motion reason', + 'submitter': self.admin}) + self.assertEqual(response.status_code, 403) + self.assertFalse(Motion.objects.filter(versions__title='registered motion').exists()) + + +class TestMotionUpdateView(MotionViewTestCase): + url = '/motion/1/edit/' + + def test_get(self): + self.check_url(self.url, self.admin_client, 200) + + def test_admin(self): + response = self.admin_client.post(self.url, {'title': 'new motion_title', + 'text': 'motion text', + 'reason': 'motion reason', + 'submitter': self.admin}) + self.assertRedirects(response, '/motion/1/') + motion = Motion.objects.get(pk=1) + self.assertEqual(motion.title, 'new motion_title') + + def test_delegate(self): + response = self.delegate_client.post(self.url, {'title': 'my title', + 'text': 'motion text', + 'reason': 'motion reason'}) + self.assertEqual(response.status_code, 403) + motion = Motion.objects.get(pk=1) + motion.add_submitter(self.delegate) + response = self.delegate_client.post(self.url, {'title': 'my title', + 'text': 'motion text', + 'reason': 'motion reason'}) + self.assertRedirects(response, '/motion/1/') + motion = Motion.objects.get(pk=1) + self.assertEqual(motion.title, 'my title') + + +class TestMotionDeleteView(MotionViewTestCase): + def test_get(self): + response = self.check_url('/motion/2/del/', self.admin_client, 302) + self.assertRedirects(response, '/motion/2/') + + def test_admin(self): + response = self.admin_client.post('/motion/2/del/', {}) + self.assertRedirects(response, '/motion/') + + def test_delegate(self): + response = self.delegate_client.post('/motion/2/del/', {}) + self.assertEqual(response.status_code, 403) + motion = Motion.objects.get(pk=2).add_submitter(self.delegate) + response = self.delegate_client.post('/motion/2/del/', {}) + self.assertRedirects(response, '/motion/')