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/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:
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
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.
|
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.
|
||||||
"""
|
"""
|
||||||
|
@ -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'),
|
||||||
)
|
]
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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'),
|
||||||
)
|
]
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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:
|
||||||
|
@ -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',
|
||||||
|
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'))
|
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)
|
||||||
|
@ -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.
|
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:
|
||||||
|
@ -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
|
||||||
|
@ -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'),
|
||||||
)
|
]
|
||||||
|
@ -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')),
|
||||||
)
|
]
|
||||||
|
@ -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'),
|
||||||
)
|
]
|
||||||
|
@ -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 (
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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')
|
||||||
|
@ -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'
|
||||||
|
@ -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'
|
||||||
|
Loading…
Reference in New Issue
Block a user