Merge pull request #1789 from ostcar/update_requirements

Update requirements
This commit is contained in:
Oskar Hahn 2016-01-09 12:22:41 +01:00
commit 4b69c57c78
29 changed files with 281 additions and 129 deletions

View File

@ -6,7 +6,6 @@ cache:
- $HOME/virtualenv/python$TRAVIS_PYTHON_VERSION/lib/python$TRAVIS_PYTHON_VERSION/site-packages/ - $HOME/virtualenv/python$TRAVIS_PYTHON_VERSION/lib/python$TRAVIS_PYTHON_VERSION/site-packages/
- $HOME/virtualenv/python$TRAVIS_PYTHON_VERSION/bin/ - $HOME/virtualenv/python$TRAVIS_PYTHON_VERSION/bin/
python: python:
- "3.3"
- "3.4" - "3.4"
- "3.5" - "3.5"
install: install:

View File

@ -29,7 +29,7 @@ Other:
- New OpenSlides logo. - New OpenSlides logo.
- New design for web interface. - New design for web interface.
- Added multiple countdown support. - Added multiple countdown support.
- Changed supported Python version to >= 3.3. - Changed supported Python version to >= 3.4.
- Used Django 1.7 as lowest requirement. - Used Django 1.7 as lowest requirement.
- Added Django's application configuration. Refactored loading of signals - Added Django's application configuration. Refactored loading of signals
and projector elements/slides. and projector elements/slides.
@ -56,6 +56,7 @@ Other:
- Used setup.cfg for development tools. - Used setup.cfg for development tools.
- Removed code for Windows portable version with GUI. Used new repository for - Removed code for Windows portable version with GUI. Used new repository for
this. this.
- Django 1.9 is supported
Translations: Translations:
- Added DE and FR translations. - Added DE and FR translations.

View File

@ -26,7 +26,7 @@ Installation on GNU/Linux or Mac OS X
1. Check requirements 1. Check requirements
Make sure that you have installed Python Programming Language 3 (>= 3.3) Make sure that you have installed Python Programming Language 3 (>= 3.4)
on your system. You will also need the Python development headers. on your system. You will also need the Python development headers.
For example for Ubuntu run:: For example for Ubuntu run::
@ -73,7 +73,7 @@ portable version you should observe the following install steps.*
1. Check requirements 1. Check requirements
Make sure that you have installed Python Programming Language 3 (>= 3.3) Make sure that you have installed Python Programming Language 3 (>= 3.4)
and Setuptools on your system. and Setuptools on your system.
a. Download and run the latest `Python 3.4 32-bit MSI installer a. Download and run the latest `Python 3.4 32-bit MSI installer
@ -170,7 +170,7 @@ Installation and start of the development version
1. Check requirements 1. Check requirements
You need to have `Python 3 (>=3.3) <https://www.python.org/>`_, `Node.js You need to have `Python 3 (>=3.4) <https://www.python.org/>`_, `Node.js
(>=0.10) <https://nodejs.org/>`_ and `Git <http://git-scm.com/>`_ (>=0.10) <https://nodejs.org/>`_ and `Git <http://git-scm.com/>`_
installed. See also step 1 in the correspondent instruction in section installed. See also step 1 in the correspondent instruction in section
III. III.

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-01-09 11:45
from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agenda', '0005_auto_20151210_0016'),
]
operations = [
migrations.AlterField(
model_name='item',
name='content_type',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='contenttypes.ContentType'),
),
migrations.AlterField(
model_name='item',
name='parent',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='children', to='agenda.Item'),
),
]

View File

@ -190,7 +190,12 @@ class Item(RESTModelMixin, models.Model):
The intended duration for the topic. The intended duration for the topic.
""" """
parent = models.ForeignKey('self', null=True, blank=True, related_name='children') parent = models.ForeignKey(
'self',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='children')
""" """
The parent item in the agenda tree. The parent item in the agenda tree.
""" """
@ -200,7 +205,11 @@ class Item(RESTModelMixin, models.Model):
Weight to sort the item in the agenda. Weight to sort the item in the agenda.
""" """
content_type = models.ForeignKey(ContentType, null=True, blank=True) content_type = models.ForeignKey(
ContentType,
on_delete=models.SET_NULL,
null=True,
blank=True)
""" """
Field for generic relation to a related object. Type of the object. Field for generic relation to a related object. Type of the object.
""" """
@ -318,12 +327,17 @@ class Speaker(RESTModelMixin, models.Model):
objects = SpeakerManager() objects = SpeakerManager()
user = models.ForeignKey(settings.AUTH_USER_MODEL) user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
""" """
ForeinKey to the user who speaks. ForeinKey to the user who speaks.
""" """
item = models.ForeignKey(Item, related_name='speakers') item = models.ForeignKey(
Item,
on_delete=models.CASCADE,
related_name='speakers')
""" """
ForeinKey to the agenda item to which the user want to speak. ForeinKey to the agenda item to which the user want to speak.
""" """

View File

@ -1,10 +1,9 @@
from django.conf.urls import patterns, url from django.conf.urls import url
from . import views from . import views
urlpatterns = patterns( urlpatterns = [
'',
url(r'^print/$', url(r'^print/$',
views.AgendaPDF.as_view(), views.AgendaPDF.as_view(),
name='agenda_pdf'), name='agenda_pdf'),
) ]

View File

@ -1,4 +1,4 @@
from cgi import escape from html import escape
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.db import transaction from django.db import transaction

View File

@ -1,7 +1,8 @@
from collections import OrderedDict
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext_lazy, ugettext_noop from django.utils.translation import ugettext_lazy, ugettext_noop
from openslides.agenda.models import Item, Speaker from openslides.agenda.models import Item, Speaker
@ -34,9 +35,11 @@ class AssignmentRelatedUser(RESTModelMixin, models.Model):
assignment = models.ForeignKey( assignment = models.ForeignKey(
'Assignment', 'Assignment',
db_index=True, on_delete=models.CASCADE,
related_name='assignment_related_users') related_name='assignment_related_users')
user = models.ForeignKey(settings.AUTH_USER_MODEL, db_index=True) user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
status = models.IntegerField( status = models.IntegerField(
choices=STATUSES, choices=STATUSES,
default=STATUS_CANDIDATE) default=STATUS_CANDIDATE)
@ -272,7 +275,7 @@ class Assignment(RESTModelMixin, models.Model):
Returns a table represented as a list with all candidates from all Returns a table represented as a list with all candidates from all
related polls and their vote results. related polls and their vote results.
""" """
vote_results_dict = SortedDict() vote_results_dict = OrderedDict()
polls = self.polls.all() polls = self.polls.all()
if only_published: if only_published:
@ -331,7 +334,10 @@ class Assignment(RESTModelMixin, models.Model):
class AssignmentVote(RESTModelMixin, BaseVote): class AssignmentVote(RESTModelMixin, BaseVote):
option = models.ForeignKey('AssignmentOption', related_name='votes') option = models.ForeignKey(
'AssignmentOption',
on_delete=models.CASCADE,
related_name='votes')
class Meta: class Meta:
default_permissions = () default_permissions = ()
@ -344,8 +350,13 @@ class AssignmentVote(RESTModelMixin, BaseVote):
class AssignmentOption(RESTModelMixin, BaseOption): class AssignmentOption(RESTModelMixin, BaseOption):
poll = models.ForeignKey('AssignmentPoll', related_name='options') poll = models.ForeignKey(
candidate = models.ForeignKey(settings.AUTH_USER_MODEL) 'AssignmentPoll',
on_delete=models.CASCADE,
related_name='options')
candidate = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
vote_class = AssignmentVote vote_class = AssignmentVote
class Meta: class Meta:
@ -366,7 +377,10 @@ class AssignmentPoll(RESTModelMixin, CollectDefaultVotesMixin,
slide_callback_name = 'assignmentpoll' slide_callback_name = 'assignmentpoll'
option_class = AssignmentOption option_class = AssignmentOption
assignment = models.ForeignKey(Assignment, related_name='polls') assignment = models.ForeignKey(
Assignment,
on_delete=models.CASCADE,
related_name='polls')
yesnoabstain = models.BooleanField(default=False) yesnoabstain = models.BooleanField(default=False)
description = models.CharField( description = models.CharField(
max_length=79, max_length=79,

View File

@ -1,9 +1,8 @@
from django.conf.urls import patterns, url from django.conf.urls import url
from . import views from . import views
urlpatterns = patterns( urlpatterns = [
'',
url(r'^print/$', url(r'^print/$',
views.AssignmentPDF.as_view(), views.AssignmentPDF.as_view(),
name='assignments_pdf'), name='assignments_pdf'),
@ -15,4 +14,4 @@ urlpatterns = patterns(
url(r'^poll/(?P<poll_pk>\d+)/print/$', url(r'^poll/(?P<poll_pk>\d+)/print/$',
views.AssignmentPollPDF.as_view(), views.AssignmentPollPDF.as_view(),
name='assignmentpoll_pdf'), name='assignmentpoll_pdf'),
) ]

View File

@ -1,4 +1,4 @@
from cgi import escape from html import escape
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model

View File

@ -1,12 +1,13 @@
import errno import errno
import os
import socket import socket
import sys import sys
from datetime import datetime from datetime import datetime
from django.core.exceptions import ImproperlyConfigured from django.conf import settings
from django.core.management.commands.runserver import Command as _Command from django.core.management.commands.runserver import Command as _Command
from django.utils import translation from django.utils import six
from django.utils.encoding import force_text from django.utils.encoding import force_text, get_system_encoding
from openslides.utils.autoupdate import run_tornado from openslides.utils.autoupdate import run_tornado
@ -17,32 +18,34 @@ class Command(_Command):
Only the line to run tornado has changed from the django default Only the line to run tornado has changed from the django default
implementation. implementation.
The Code is from django 1.9
""" """
# TODO: do not start tornado when the settings says so # TODO: do not start tornado when the settings says so
def inner_run(self, *args, **options): def inner_run(self, *args, **options):
from django.conf import settings # If an exception was silenced in ManagementUtility.execute in order
# From the base class: # to be raised in the child process, raise it now.
self.stdout.write("Performing system checks...\n\n") # OPENSLIDES: We do not use the django autoreload command
self.validate(display_num_errors=True) # autoreload.raise_last_exception()
try:
self.check_migrations()
except ImproperlyConfigured:
pass
now = datetime.now().strftime('%B %d, %Y - %X')
# OPENSLIDES: This line is not needed by tornado
# threading = options.get('use_threading')
shutdown_message = options.get('shutdown_message', '') shutdown_message = options.get('shutdown_message', '')
quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C' quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C'
self.stdout.write("Performing system checks...\n\n")
self.check(display_num_errors=True)
self.check_migrations()
now = datetime.now().strftime('%B %d, %Y - %X')
if six.PY2:
now = now.decode(get_system_encoding())
self.stdout.write(now)
self.stdout.write(( self.stdout.write((
"%(started_at)s\n"
"Django version %(version)s, using settings %(settings)r\n" "Django version %(version)s, using settings %(settings)r\n"
"Starting development server at http://%(addr)s:%(port)s/\n" "Starting development server at http://%(addr)s:%(port)s/\n"
"Quit the server with %(quit_command)s.\n" "Quit the server with %(quit_command)s.\n"
) % { ) % {
"started_at": now,
"version": self.get_version(), "version": self.get_version(),
"settings": settings.SETTINGS_MODULE, "settings": settings.SETTINGS_MODULE,
"addr": '[%s]' % self.addr if self._raw_ipv6 else self.addr, "addr": '[%s]' % self.addr if self._raw_ipv6 else self.addr,
@ -50,8 +53,6 @@ class Command(_Command):
"quit_command": quit_command, "quit_command": quit_command,
}) })
translation.activate(settings.LANGUAGE_CODE)
try: try:
handler = self.get_handler(*args, **options) handler = self.get_handler(*args, **options)
run_tornado( run_tornado(
@ -64,14 +65,15 @@ class Command(_Command):
ERRORS = { ERRORS = {
errno.EACCES: "You don't have permission to access that port.", errno.EACCES: "You don't have permission to access that port.",
errno.EADDRINUSE: "That port is already in use.", errno.EADDRINUSE: "That port is already in use.",
errno.EADDRNOTAVAIL: "That IP address can't be assigned-to.", errno.EADDRNOTAVAIL: "That IP address can't be assigned to.",
} }
try: try:
error_text = ERRORS[e.errno] error_text = ERRORS[e.errno]
except KeyError: except KeyError:
error_text = force_text(e) error_text = force_text(e)
self.stderr.write("Error: %s" % error_text) self.stderr.write("Error: %s" % error_text)
sys.exit(0) # Need to use an OS exit because sys.exit doesn't work in a thread
os._exit(1)
except KeyboardInterrupt: except KeyboardInterrupt:
if shutdown_message: if shutdown_message:
self.stdout.write(shutdown_message) self.stdout.write(shutdown_message)

View File

@ -217,6 +217,7 @@ class ChatMessage(RESTModelMixin, models.Model):
user = models.ForeignKey( user = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
verbose_name=ugettext_lazy('User')) verbose_name=ugettext_lazy('User'))
class Meta: class Meta:

View File

@ -54,12 +54,6 @@ STATICFILES_FINDERS = (
STATICFILES_DIRS = [ STATICFILES_DIRS = [
os.path.join(SITE_ROOT, 'static')] os.path.join(SITE_ROOT, 'static')]
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',

View File

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-01-09 11:45
from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mediafiles', '0004_auto_20151210_0016'),
]
operations = [
migrations.AlterField(
model_name='mediafile',
name='uploader',
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
verbose_name='Uploaded by'),
),
]

View File

@ -21,7 +21,12 @@ class Mediafile(RESTModelMixin, models.Model):
title = models.CharField(max_length=255, unique=True, blank=True, verbose_name=ugettext_lazy('Title')) title = models.CharField(max_length=255, unique=True, blank=True, verbose_name=ugettext_lazy('Title'))
"""A string representing the title of the file.""" """A string representing the title of the file."""
uploader = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, verbose_name=ugettext_lazy('Uploaded by')) uploader = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True,
blank=True,
verbose_name=ugettext_lazy('Uploaded by'))
"""A user the uploader of a file.""" """A user the uploader of a file."""
timestamp = models.DateTimeField(auto_now_add=True) timestamp = models.DateTimeField(auto_now_add=True)

View File

@ -1,10 +0,0 @@
{% load i18n %}
{% load highlight %}
{% if perms.mediafiles.can_see %}
<li>
<a href="{{ result.object.get_absolute_url }}">{{ result.object }}</a><br>
<span class="app">{% trans "File" %}</a></span><br>
{% highlight result.text with request.GET.q %}
</li>
{% endif %}

View File

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-01-09 11:45
from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('motions', '0005_auto_20151210_0019'),
]
operations = [
migrations.AlterField(
model_name='motion',
name='category',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='motions.Category'),
),
migrations.AlterField(
model_name='motion',
name='parent',
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name='amendments',
to='motions.Motion'),
),
migrations.AlterField(
model_name='motion',
name='state',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='motions.State'),
),
migrations.AlterField(
model_name='motionlog',
name='person',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='workflow',
name='first_state',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='motions.State'),
),
]

View File

@ -35,9 +35,11 @@ class Motion(RESTModelMixin, models.Model):
Name of the callback for the slide-system. Name of the callback for the slide-system.
""" """
active_version = models.ForeignKey('MotionVersion', null=True, active_version = models.ForeignKey(
related_name="active_version", 'MotionVersion',
on_delete=models.SET_NULL) on_delete=models.SET_NULL,
null=True,
related_name="active_version")
""" """
Points to a specific version. Points to a specific version.
@ -46,7 +48,10 @@ class Motion(RESTModelMixin, models.Model):
version. Like the sighted versions on Wikipedia. version. Like the sighted versions on Wikipedia.
""" """
state = models.ForeignKey('State', null=True) # TODO: Check whether null=True is necessary. state = models.ForeignKey(
'State',
on_delete=models.SET_NULL,
null=True) # TODO: Check whether null=True is necessary.
""" """
The related state object. The related state object.
@ -66,7 +71,11 @@ class Motion(RESTModelMixin, models.Model):
Needed to find the next free motion identifier. Needed to find the next free motion identifier.
""" """
category = models.ForeignKey('Category', null=True, blank=True) category = models.ForeignKey(
'Category',
on_delete=models.SET_NULL,
null=True,
blank=True)
""" """
ForeignKey to one category of motions. ForeignKey to one category of motions.
""" """
@ -76,7 +85,12 @@ class Motion(RESTModelMixin, models.Model):
Many to many relation to mediafile objects. Many to many relation to mediafile objects.
""" """
parent = models.ForeignKey('self', null=True, blank=True, related_name='amendments') parent = models.ForeignKey(
'self',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='amendments')
""" """
Field for amendments to reference to the motion that should be altered. Field for amendments to reference to the motion that should be altered.
@ -557,7 +571,10 @@ class MotionVersion(RESTModelMixin, models.Model):
A MotionVersion object saves some date of the motion. A MotionVersion object saves some date of the motion.
""" """
motion = models.ForeignKey(Motion, related_name='versions') motion = models.ForeignKey(
Motion,
on_delete=models.CASCADE,
related_name='versions')
"""The motion to which the version belongs.""" """The motion to which the version belongs."""
version_number = models.PositiveIntegerField(default=1) version_number = models.PositiveIntegerField(default=1)
@ -623,7 +640,10 @@ class Category(RESTModelMixin, models.Model):
class MotionLog(RESTModelMixin, models.Model): class MotionLog(RESTModelMixin, models.Model):
"""Save a logmessage for a motion.""" """Save a logmessage for a motion."""
motion = models.ForeignKey(Motion, related_name='log_messages') motion = models.ForeignKey(
Motion,
on_delete=models.CASCADE,
related_name='log_messages')
"""The motion to witch the object belongs.""" """The motion to witch the object belongs."""
message_list = JSONField() message_list = JSONField()
@ -631,7 +651,10 @@ class MotionLog(RESTModelMixin, models.Model):
The log message. It should be a list of strings in English. The log message. It should be a list of strings in English.
""" """
person = models.ForeignKey(settings.AUTH_USER_MODEL, null=True) person = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True)
"""A user object, who created the log message. Optional.""" """A user object, who created the log message. Optional."""
time = models.DateTimeField(auto_now=True) time = models.DateTimeField(auto_now=True)
@ -665,7 +688,9 @@ class MotionVote(RESTModelMixin, BaseVote):
There should allways be three MotionVote objects for each poll, There should allways be three MotionVote objects for each poll,
one for 'yes', 'no', and 'abstain'.""" one for 'yes', 'no', and 'abstain'."""
option = models.ForeignKey('MotionOption') option = models.ForeignKey(
'MotionOption',
on_delete=models.CASCADE)
"""The option object, to witch the vote belongs.""" """The option object, to witch the vote belongs."""
class Meta: class Meta:
@ -683,7 +708,9 @@ class MotionOption(RESTModelMixin, BaseOption):
There should be one MotionOption object for each poll.""" There should be one MotionOption object for each poll."""
poll = models.ForeignKey('MotionPoll') poll = models.ForeignKey(
'MotionPoll',
on_delete=models.CASCADE)
"""The poll object, to witch the object belongs.""" """The poll object, to witch the object belongs."""
vote_class = MotionVote vote_class = MotionVote
@ -705,7 +732,10 @@ class MotionPoll(RESTModelMixin, CollectDefaultVotesMixin, BasePoll):
slide_callback_name = 'motionpoll' slide_callback_name = 'motionpoll'
"""Name of the callback for the slide-system.""" """Name of the callback for the slide-system."""
motion = models.ForeignKey(Motion, related_name='polls') motion = models.ForeignKey(
Motion,
on_delete=models.CASCADE,
related_name='polls')
"""The motion to witch the object belongs.""" """The motion to witch the object belongs."""
option_class = MotionOption option_class = MotionOption
@ -759,7 +789,10 @@ class State(RESTModelMixin, models.Model):
action_word = models.CharField(max_length=255) action_word = models.CharField(max_length=255)
"""An alternative string to be used for a button to switch to this state.""" """An alternative string to be used for a button to switch to this state."""
workflow = models.ForeignKey('Workflow', related_name='states') workflow = models.ForeignKey(
'Workflow',
on_delete=models.CASCADE,
related_name='states')
"""A many-to-one relation to a workflow.""" """A many-to-one relation to a workflow."""
next_states = models.ManyToManyField('self', symmetrical=False) next_states = models.ManyToManyField('self', symmetrical=False)
@ -850,7 +883,11 @@ class Workflow(RESTModelMixin, models.Model):
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
"""A string representing the workflow.""" """A string representing the workflow."""
first_state = models.OneToOneField(State, related_name='+', null=True) first_state = models.OneToOneField(
State,
on_delete=models.SET_NULL,
related_name='+',
null=True)
"""A one-to-one relation to a state, the starting point for the workflow.""" """A one-to-one relation to a state, the starting point for the workflow."""
class Meta: class Meta:

View File

@ -1,5 +1,5 @@
import random import random
from cgi import escape from html import escape
from operator import attrgetter from operator import attrgetter
from bs4 import BeautifulSoup from bs4 import BeautifulSoup

View File

@ -1,9 +1,8 @@
from django.conf.urls import patterns, url from django.conf.urls import url
from . import views from . import views
urlpatterns = patterns( urlpatterns = [
'',
url(r'^pdf/$', url(r'^pdf/$',
views.MotionPDFView.as_view(print_all_motions=True), views.MotionPDFView.as_view(print_all_motions=True),
name='motions_pdf'), name='motions_pdf'),
@ -11,4 +10,4 @@ urlpatterns = patterns(
url(r'^(?P<pk>\d+)/pdf/$', url(r'^(?P<pk>\d+)/pdf/$',
views.MotionPDFView.as_view(print_all_motions=False), views.MotionPDFView.as_view(print_all_motions=False),
name='motions_single_pdf'), name='motions_single_pdf'),
) ]

View File

@ -1,4 +1,4 @@
from django.conf.urls import include, patterns, url from django.conf.urls import include, url
from django.views.generic import RedirectView from django.views.generic import RedirectView
from openslides.utils.plugins import get_all_plugin_urlpatterns from openslides.utils.plugins import get_all_plugin_urlpatterns
@ -6,8 +6,7 @@ from openslides.utils.rest_api import router
urlpatterns = get_all_plugin_urlpatterns() urlpatterns = get_all_plugin_urlpatterns()
urlpatterns += patterns( urlpatterns += [
'',
url(r'^(?P<url>.*[^/])$', RedirectView.as_view(url='/%(url)s/', permanent=True)), url(r'^(?P<url>.*[^/])$', RedirectView.as_view(url='/%(url)s/', permanent=True)),
url(r'^rest/', include(router.urls)), url(r'^rest/', include(router.urls)),
url(r'^agenda/', include('openslides.agenda.urls')), url(r'^agenda/', include('openslides.agenda.urls')),
@ -18,4 +17,4 @@ urlpatterns += patterns(
# The urls.py of the core app has to be the last entry. It contains the # The urls.py of the core app has to be the last entry. It contains the
# main entry points for OpenSlides' browser clients. # main entry points for OpenSlides' browser clients.
url(r'^', include('openslides.core.urls')), url(r'^', include('openslides.core.urls')),
) ]

View File

@ -1,10 +1,8 @@
from django.conf.urls import patterns, url from django.conf.urls import url
from . import views from . import views
urlpatterns = patterns( urlpatterns = [
'',
# Auth # Auth
url(r'^login/$', url(r'^login/$',
views.UserLoginView.as_view(), views.UserLoginView.as_view(),
@ -30,4 +28,4 @@ urlpatterns = patterns(
url(r'^passwords/print/$', url(r'^passwords/print/$',
views.UsersPasswordsPDF.as_view(), views.UsersPasswordsPDF.as_view(),
name='user_passwordspdf'), name='user_passwordspdf'),
) ]

View File

@ -1,9 +1,9 @@
import os import os
import pkgutil import pkgutil
import sys import sys
from importlib import import_module
from django.conf import settings from django.conf import settings
from django.utils.importlib import import_module
from pkg_resources import iter_entry_points from pkg_resources import iter_entry_points
from openslides.utils.main import ( from openslides.utils.main import (

View File

@ -2,6 +2,6 @@
-r requirements_production.txt -r requirements_production.txt
# Requirements for development and tests in alphabetical order # Requirements for development and tests in alphabetical order
coverage==4.0a5 coverage
flake8 flake8
isort isort

View File

@ -1,12 +1,12 @@
# Requirements for OpenSlides in production in alphabetical order # Requirements for OpenSlides in production in alphabetical order
Django>=1.7.1,<1.9 Django>=1.8,<1.10
beautifulsoup4>=4.1,<4.5 beautifulsoup4>=4.4,<4.5
djangorestframework>=3.2.0,<3.3.0 djangorestframework>=3.2.0,<3.4.0
html5lib>=0.9,<1.0 html5lib>=0.9,<1.0
jsonfield>=0.9.19,<1.1 jsonfield>=0.9.19,<1.1
natsort>=3.2,<4.1 natsort>=3.2,<4.1
reportlab>=3.0,<3.3 reportlab>=3.0,<3.3
roman>=2.0,<2.1 roman>=2.0,<2.1
setuptools>=2.2,<19.0 setuptools>=2.2,<20.0
sockjs-tornado>=1.0,<1.1 sockjs-tornado>=1.0,<1.1
Whoosh>=2.7.0,<2.8 Whoosh>=2.7.0,<2.8

View File

@ -20,16 +20,23 @@ class HandleConfigTest(TestCase):
self.assertEqual(config['integer_var'], 3) self.assertEqual(config['integer_var'], 3)
self.assertEqual(config['choices_var'], '1') self.assertEqual(config['choices_var'], '1')
self.assertEqual(config['none_config_var'], None) self.assertEqual(config['none_config_var'], None)
self.assertRaisesMessage(expected_exception=ConfigNotFound, with self.assertRaisesMessage(
expected_message='The config variable unknown_config_var was not found.', ConfigNotFound,
callable_obj=self.get_config_var, key='unknown_config_var') 'The config variable unknown_config_var was not found.'):
self.get_config_var('unknown_config_var')
def test_get_multiple_config_var_error(self): def test_get_multiple_config_var_error(self):
config_signal.connect(set_simple_config_view_multiple_vars, dispatch_uid='set_simple_config_view_multiple_vars_for_testing') config_signal.connect(
self.assertRaisesMessage(expected_exception=ConfigError, set_simple_config_view_multiple_vars,
expected_message='Too many values for config variable multiple_config_var found.', dispatch_uid='set_simple_config_view_multiple_vars_for_testing')
callable_obj=config.setup_cache)
config_signal.disconnect(set_simple_config_view_multiple_vars, dispatch_uid='set_simple_config_view_multiple_vars_for_testing') with self.assertRaisesMessage(
ConfigError,
'Too many values for config variable multiple_config_var found.'):
config.setup_cache()
config_signal.disconnect(
set_simple_config_view_multiple_vars,
dispatch_uid='set_simple_config_view_multiple_vars_for_testing')
def test_database_queries(self): def test_database_queries(self):
""" """
@ -67,13 +74,16 @@ class HandleConfigTest(TestCase):
message. message.
""" """
# TODO: use right exception # TODO: use right exception
self.assertRaisesMessage( with self.assertRaisesMessage(
Exception, Exception,
'Change callback dhcnfg34dlg06kdg successfully called.', 'Change callback dhcnfg34dlg06kdg successfully called.'):
self.set_config_var, self.set_config_var(
key='var_with_callback_ghvnfjd5768gdfkwg0hm2', key='var_with_callback_ghvnfjd5768gdfkwg0hm2',
value='new_string_kbmbnfhdgibkdjshg452bc') value='new_string_kbmbnfhdgibkdjshg452bc')
self.assertEqual(config['var_with_callback_ghvnfjd5768gdfkwg0hm2'], 'new_string_kbmbnfhdgibkdjshg452bc')
self.assertEqual(
config['var_with_callback_ghvnfjd5768gdfkwg0hm2'],
'new_string_kbmbnfhdgibkdjshg452bc')
@receiver(config_signal, dispatch_uid='set_grouped_config_view_for_testing') @receiver(config_signal, dispatch_uid='set_grouped_config_view_for_testing')

View File

@ -40,10 +40,6 @@ TIME_ZONE = 'Europe/Berlin'
MEDIA_ROOT = os.path.join(OPENSLIDES_USER_DATA_PATH, '') MEDIA_ROOT = os.path.join(OPENSLIDES_USER_DATA_PATH, '')
TEMPLATE_DIRS = (
os.path.join(OPENSLIDES_USER_DATA_PATH, 'templates'),
)
STATICFILES_DIRS.insert(0, os.path.join(OPENSLIDES_USER_DATA_PATH, 'static')) STATICFILES_DIRS.insert(0, os.path.join(OPENSLIDES_USER_DATA_PATH, 'static'))
SEARCH_INDEX = 'ram' SEARCH_INDEX = 'ram'

View File

@ -40,10 +40,6 @@ TIME_ZONE = 'Europe/Berlin'
MEDIA_ROOT = os.path.join(OPENSLIDES_USER_DATA_PATH, '') MEDIA_ROOT = os.path.join(OPENSLIDES_USER_DATA_PATH, '')
TEMPLATE_DIRS = (
os.path.join(OPENSLIDES_USER_DATA_PATH, 'templates'),
)
STATICFILES_DIRS.insert(0, os.path.join(OPENSLIDES_USER_DATA_PATH, 'static')) STATICFILES_DIRS.insert(0, os.path.join(OPENSLIDES_USER_DATA_PATH, 'static'))
SEARCH_INDEX = 'ram' SEARCH_INDEX = 'ram'