Merge pull request #1789 from ostcar/update_requirements
Update requirements
This commit is contained in:
commit
4b69c57c78
@ -6,7 +6,6 @@ cache:
|
||||
- $HOME/virtualenv/python$TRAVIS_PYTHON_VERSION/lib/python$TRAVIS_PYTHON_VERSION/site-packages/
|
||||
- $HOME/virtualenv/python$TRAVIS_PYTHON_VERSION/bin/
|
||||
python:
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
- "3.5"
|
||||
install:
|
||||
|
@ -29,7 +29,7 @@ Other:
|
||||
- New OpenSlides logo.
|
||||
- New design for web interface.
|
||||
- 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.
|
||||
- Added Django's application configuration. Refactored loading of signals
|
||||
and projector elements/slides.
|
||||
@ -56,6 +56,7 @@ Other:
|
||||
- Used setup.cfg for development tools.
|
||||
- Removed code for Windows portable version with GUI. Used new repository for
|
||||
this.
|
||||
- Django 1.9 is supported
|
||||
Translations:
|
||||
- Added DE and FR translations.
|
||||
|
||||
|
@ -26,7 +26,7 @@ Installation on GNU/Linux or Mac OS X
|
||||
|
||||
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.
|
||||
|
||||
For example for Ubuntu run::
|
||||
@ -73,7 +73,7 @@ portable version you should observe the following install steps.*
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
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/>`_
|
||||
installed. See also step 1 in the correspondent instruction in section
|
||||
III.
|
||||
|
26
openslides/agenda/migrations/0006_auto_20160109_1145.py
Normal file
26
openslides/agenda/migrations/0006_auto_20160109_1145.py
Normal 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'),
|
||||
),
|
||||
]
|
@ -190,7 +190,12 @@ class Item(RESTModelMixin, models.Model):
|
||||
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.
|
||||
"""
|
||||
@ -200,7 +205,11 @@ class Item(RESTModelMixin, models.Model):
|
||||
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.
|
||||
"""
|
||||
@ -318,12 +327,17 @@ class Speaker(RESTModelMixin, models.Model):
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
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.
|
||||
"""
|
||||
|
@ -1,10 +1,9 @@
|
||||
from django.conf.urls import patterns, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
urlpatterns = [
|
||||
url(r'^print/$',
|
||||
views.AgendaPDF.as_view(),
|
||||
name='agenda_pdf'),
|
||||
)
|
||||
]
|
||||
|
@ -1,4 +1,4 @@
|
||||
from cgi import escape
|
||||
from html import escape
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db import transaction
|
||||
|
@ -1,7 +1,8 @@
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.utils.datastructures import SortedDict
|
||||
from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||
|
||||
from openslides.agenda.models import Item, Speaker
|
||||
@ -34,9 +35,11 @@ class AssignmentRelatedUser(RESTModelMixin, models.Model):
|
||||
|
||||
assignment = models.ForeignKey(
|
||||
'Assignment',
|
||||
db_index=True,
|
||||
on_delete=models.CASCADE,
|
||||
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(
|
||||
choices=STATUSES,
|
||||
default=STATUS_CANDIDATE)
|
||||
@ -272,7 +275,7 @@ class Assignment(RESTModelMixin, models.Model):
|
||||
Returns a table represented as a list with all candidates from all
|
||||
related polls and their vote results.
|
||||
"""
|
||||
vote_results_dict = SortedDict()
|
||||
vote_results_dict = OrderedDict()
|
||||
|
||||
polls = self.polls.all()
|
||||
if only_published:
|
||||
@ -331,7 +334,10 @@ class Assignment(RESTModelMixin, models.Model):
|
||||
|
||||
|
||||
class AssignmentVote(RESTModelMixin, BaseVote):
|
||||
option = models.ForeignKey('AssignmentOption', related_name='votes')
|
||||
option = models.ForeignKey(
|
||||
'AssignmentOption',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='votes')
|
||||
|
||||
class Meta:
|
||||
default_permissions = ()
|
||||
@ -344,8 +350,13 @@ class AssignmentVote(RESTModelMixin, BaseVote):
|
||||
|
||||
|
||||
class AssignmentOption(RESTModelMixin, BaseOption):
|
||||
poll = models.ForeignKey('AssignmentPoll', related_name='options')
|
||||
candidate = models.ForeignKey(settings.AUTH_USER_MODEL)
|
||||
poll = models.ForeignKey(
|
||||
'AssignmentPoll',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='options')
|
||||
candidate = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE)
|
||||
vote_class = AssignmentVote
|
||||
|
||||
class Meta:
|
||||
@ -366,7 +377,10 @@ class AssignmentPoll(RESTModelMixin, CollectDefaultVotesMixin,
|
||||
slide_callback_name = 'assignmentpoll'
|
||||
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)
|
||||
description = models.CharField(
|
||||
max_length=79,
|
||||
|
@ -1,9 +1,8 @@
|
||||
from django.conf.urls import patterns, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
urlpatterns = [
|
||||
url(r'^print/$',
|
||||
views.AssignmentPDF.as_view(),
|
||||
name='assignments_pdf'),
|
||||
@ -15,4 +14,4 @@ urlpatterns = patterns(
|
||||
url(r'^poll/(?P<poll_pk>\d+)/print/$',
|
||||
views.AssignmentPollPDF.as_view(),
|
||||
name='assignmentpoll_pdf'),
|
||||
)
|
||||
]
|
||||
|
@ -1,4 +1,4 @@
|
||||
from cgi import escape
|
||||
from html import escape
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
|
@ -1,12 +1,13 @@
|
||||
import errno
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
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.utils import translation
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_text, get_system_encoding
|
||||
|
||||
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
|
||||
implementation.
|
||||
|
||||
The Code is from django 1.9
|
||||
"""
|
||||
# TODO: do not start tornado when the settings says so
|
||||
|
||||
def inner_run(self, *args, **options):
|
||||
from django.conf import settings
|
||||
# From the base class:
|
||||
self.stdout.write("Performing system checks...\n\n")
|
||||
self.validate(display_num_errors=True)
|
||||
|
||||
try:
|
||||
self.check_migrations()
|
||||
except ImproperlyConfigured:
|
||||
pass
|
||||
|
||||
now = datetime.now().strftime('%B %d, %Y - %X')
|
||||
# If an exception was silenced in ManagementUtility.execute in order
|
||||
# to be raised in the child process, raise it now.
|
||||
# OPENSLIDES: We do not use the django autoreload command
|
||||
# autoreload.raise_last_exception()
|
||||
|
||||
# OPENSLIDES: This line is not needed by tornado
|
||||
# threading = options.get('use_threading')
|
||||
shutdown_message = options.get('shutdown_message', '')
|
||||
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((
|
||||
"%(started_at)s\n"
|
||||
"Django version %(version)s, using settings %(settings)r\n"
|
||||
"Starting development server at http://%(addr)s:%(port)s/\n"
|
||||
"Quit the server with %(quit_command)s.\n"
|
||||
) % {
|
||||
"started_at": now,
|
||||
"version": self.get_version(),
|
||||
"settings": settings.SETTINGS_MODULE,
|
||||
"addr": '[%s]' % self.addr if self._raw_ipv6 else self.addr,
|
||||
@ -50,8 +53,6 @@ class Command(_Command):
|
||||
"quit_command": quit_command,
|
||||
})
|
||||
|
||||
translation.activate(settings.LANGUAGE_CODE)
|
||||
|
||||
try:
|
||||
handler = self.get_handler(*args, **options)
|
||||
run_tornado(
|
||||
@ -64,14 +65,15 @@ class Command(_Command):
|
||||
ERRORS = {
|
||||
errno.EACCES: "You don't have permission to access that port.",
|
||||
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:
|
||||
error_text = ERRORS[e.errno]
|
||||
except KeyError:
|
||||
error_text = force_text(e)
|
||||
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:
|
||||
if shutdown_message:
|
||||
self.stdout.write(shutdown_message)
|
||||
|
@ -217,6 +217,7 @@ class ChatMessage(RESTModelMixin, models.Model):
|
||||
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name=ugettext_lazy('User'))
|
||||
|
||||
class Meta:
|
||||
|
@ -54,12 +54,6 @@ STATICFILES_FINDERS = (
|
||||
STATICFILES_DIRS = [
|
||||
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 = (
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
|
27
openslides/mediafiles/migrations/0005_auto_20160109_1145.py
Normal file
27
openslides/mediafiles/migrations/0005_auto_20160109_1145.py
Normal 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'),
|
||||
),
|
||||
]
|
@ -21,7 +21,12 @@ class Mediafile(RESTModelMixin, models.Model):
|
||||
title = models.CharField(max_length=255, unique=True, blank=True, verbose_name=ugettext_lazy('Title'))
|
||||
"""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."""
|
||||
|
||||
timestamp = models.DateTimeField(auto_now_add=True)
|
||||
|
@ -1 +0,0 @@
|
||||
{{ object.title }}
|
@ -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 %}
|
47
openslides/motions/migrations/0006_auto_20160109_1145.py
Normal file
47
openslides/motions/migrations/0006_auto_20160109_1145.py
Normal 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'),
|
||||
),
|
||||
]
|
@ -35,9 +35,11 @@ class Motion(RESTModelMixin, models.Model):
|
||||
Name of the callback for the slide-system.
|
||||
"""
|
||||
|
||||
active_version = models.ForeignKey('MotionVersion', null=True,
|
||||
related_name="active_version",
|
||||
on_delete=models.SET_NULL)
|
||||
active_version = models.ForeignKey(
|
||||
'MotionVersion',
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
related_name="active_version")
|
||||
"""
|
||||
Points to a specific version.
|
||||
|
||||
@ -46,7 +48,10 @@ class Motion(RESTModelMixin, models.Model):
|
||||
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.
|
||||
|
||||
@ -66,7 +71,11 @@ class Motion(RESTModelMixin, models.Model):
|
||||
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.
|
||||
"""
|
||||
@ -76,7 +85,12 @@ class Motion(RESTModelMixin, models.Model):
|
||||
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.
|
||||
|
||||
@ -557,7 +571,10 @@ class MotionVersion(RESTModelMixin, models.Model):
|
||||
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."""
|
||||
|
||||
version_number = models.PositiveIntegerField(default=1)
|
||||
@ -623,7 +640,10 @@ class Category(RESTModelMixin, models.Model):
|
||||
class MotionLog(RESTModelMixin, models.Model):
|
||||
"""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."""
|
||||
|
||||
message_list = JSONField()
|
||||
@ -631,7 +651,10 @@ class MotionLog(RESTModelMixin, models.Model):
|
||||
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."""
|
||||
|
||||
time = models.DateTimeField(auto_now=True)
|
||||
@ -665,7 +688,9 @@ class MotionVote(RESTModelMixin, BaseVote):
|
||||
There should allways be three MotionVote objects for each poll,
|
||||
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."""
|
||||
|
||||
class Meta:
|
||||
@ -683,7 +708,9 @@ class MotionOption(RESTModelMixin, BaseOption):
|
||||
|
||||
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."""
|
||||
|
||||
vote_class = MotionVote
|
||||
@ -705,7 +732,10 @@ class MotionPoll(RESTModelMixin, CollectDefaultVotesMixin, BasePoll):
|
||||
slide_callback_name = 'motionpoll'
|
||||
"""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."""
|
||||
|
||||
option_class = MotionOption
|
||||
@ -759,7 +789,10 @@ class State(RESTModelMixin, models.Model):
|
||||
action_word = models.CharField(max_length=255)
|
||||
"""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."""
|
||||
|
||||
next_states = models.ManyToManyField('self', symmetrical=False)
|
||||
@ -850,7 +883,11 @@ class Workflow(RESTModelMixin, models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
"""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."""
|
||||
|
||||
class Meta:
|
||||
|
@ -1,5 +1,5 @@
|
||||
import random
|
||||
from cgi import escape
|
||||
from html import escape
|
||||
from operator import attrgetter
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
|
@ -1,9 +1,8 @@
|
||||
from django.conf.urls import patterns, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
urlpatterns = [
|
||||
url(r'^pdf/$',
|
||||
views.MotionPDFView.as_view(print_all_motions=True),
|
||||
name='motions_pdf'),
|
||||
@ -11,4 +10,4 @@ urlpatterns = patterns(
|
||||
url(r'^(?P<pk>\d+)/pdf/$',
|
||||
views.MotionPDFView.as_view(print_all_motions=False),
|
||||
name='motions_single_pdf'),
|
||||
)
|
||||
]
|
||||
|
@ -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 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 += patterns(
|
||||
'',
|
||||
urlpatterns += [
|
||||
url(r'^(?P<url>.*[^/])$', RedirectView.as_view(url='/%(url)s/', permanent=True)),
|
||||
url(r'^rest/', include(router.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
|
||||
# main entry points for OpenSlides' browser clients.
|
||||
url(r'^', include('openslides.core.urls')),
|
||||
)
|
||||
]
|
||||
|
@ -1,10 +1,8 @@
|
||||
from django.conf.urls import patterns, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
|
||||
urlpatterns = [
|
||||
# Auth
|
||||
url(r'^login/$',
|
||||
views.UserLoginView.as_view(),
|
||||
@ -30,4 +28,4 @@ urlpatterns = patterns(
|
||||
url(r'^passwords/print/$',
|
||||
views.UsersPasswordsPDF.as_view(),
|
||||
name='user_passwordspdf'),
|
||||
)
|
||||
]
|
||||
|
@ -1,9 +1,9 @@
|
||||
import os
|
||||
import pkgutil
|
||||
import sys
|
||||
from importlib import import_module
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.importlib import import_module
|
||||
from pkg_resources import iter_entry_points
|
||||
|
||||
from openslides.utils.main import (
|
||||
|
@ -2,6 +2,6 @@
|
||||
-r requirements_production.txt
|
||||
|
||||
# Requirements for development and tests in alphabetical order
|
||||
coverage==4.0a5
|
||||
coverage
|
||||
flake8
|
||||
isort
|
||||
|
@ -1,12 +1,12 @@
|
||||
# Requirements for OpenSlides in production in alphabetical order
|
||||
Django>=1.7.1,<1.9
|
||||
beautifulsoup4>=4.1,<4.5
|
||||
djangorestframework>=3.2.0,<3.3.0
|
||||
Django>=1.8,<1.10
|
||||
beautifulsoup4>=4.4,<4.5
|
||||
djangorestframework>=3.2.0,<3.4.0
|
||||
html5lib>=0.9,<1.0
|
||||
jsonfield>=0.9.19,<1.1
|
||||
natsort>=3.2,<4.1
|
||||
reportlab>=3.0,<3.3
|
||||
roman>=2.0,<2.1
|
||||
setuptools>=2.2,<19.0
|
||||
setuptools>=2.2,<20.0
|
||||
sockjs-tornado>=1.0,<1.1
|
||||
Whoosh>=2.7.0,<2.8
|
||||
|
@ -20,16 +20,23 @@ class HandleConfigTest(TestCase):
|
||||
self.assertEqual(config['integer_var'], 3)
|
||||
self.assertEqual(config['choices_var'], '1')
|
||||
self.assertEqual(config['none_config_var'], None)
|
||||
self.assertRaisesMessage(expected_exception=ConfigNotFound,
|
||||
expected_message='The config variable unknown_config_var was not found.',
|
||||
callable_obj=self.get_config_var, key='unknown_config_var')
|
||||
with self.assertRaisesMessage(
|
||||
ConfigNotFound,
|
||||
'The config variable unknown_config_var was not found.'):
|
||||
self.get_config_var('unknown_config_var')
|
||||
|
||||
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')
|
||||
self.assertRaisesMessage(expected_exception=ConfigError,
|
||||
expected_message='Too many values for config variable multiple_config_var found.',
|
||||
callable_obj=config.setup_cache)
|
||||
config_signal.disconnect(set_simple_config_view_multiple_vars, dispatch_uid='set_simple_config_view_multiple_vars_for_testing')
|
||||
config_signal.connect(
|
||||
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):
|
||||
"""
|
||||
@ -67,13 +74,16 @@ class HandleConfigTest(TestCase):
|
||||
message.
|
||||
"""
|
||||
# TODO: use right exception
|
||||
self.assertRaisesMessage(
|
||||
with self.assertRaisesMessage(
|
||||
Exception,
|
||||
'Change callback dhcnfg34dlg06kdg successfully called.',
|
||||
self.set_config_var,
|
||||
'Change callback dhcnfg34dlg06kdg successfully called.'):
|
||||
self.set_config_var(
|
||||
key='var_with_callback_ghvnfjd5768gdfkwg0hm2',
|
||||
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')
|
||||
|
@ -40,10 +40,6 @@ TIME_ZONE = 'Europe/Berlin'
|
||||
|
||||
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'))
|
||||
|
||||
SEARCH_INDEX = 'ram'
|
||||
|
@ -40,10 +40,6 @@ TIME_ZONE = 'Europe/Berlin'
|
||||
|
||||
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'))
|
||||
|
||||
SEARCH_INDEX = 'ram'
|
||||
|
Loading…
Reference in New Issue
Block a user