diff --git a/CHANGELOG b/CHANGELOG
index d5524d69a..c1271cbbb 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -27,6 +27,14 @@ Version 1.5.1 (unreleased)
==========================
[https://github.com/OpenSlides/OpenSlides/issues?milestone=15]
+Participant:
+- Added permission to see participants also to the manager group.
+Files:
+- Fixed error when a file was removed from filesystem.
+Other:
+- Fixed http status code when requesting a non-existing static page using
+ Tordado web server.
+
Version 1.5 (2013-11-25)
========================
diff --git a/openslides/agenda/signals.py b/openslides/agenda/signals.py
index 2c7f093c1..c4e144fab 100644
--- a/openslides/agenda/signals.py
+++ b/openslides/agenda/signals.py
@@ -98,7 +98,7 @@ def agenda_list_of_speakers(sender, **kwargs):
list-of-speakers slide.
"""
slide = get_active_object()
- if isinstance(slide, Item):
+ if slide is None or isinstance(slide, Item):
item = slide
else:
# TODO: If there are more the one items, use the first one in the
diff --git a/openslides/mediafile/models.py b/openslides/mediafile/models.py
index e2f2ec3f8..28ec44dca 100644
--- a/openslides/mediafile/models.py
+++ b/openslides/mediafile/models.py
@@ -4,6 +4,7 @@ import mimetypes
from django.core.urlresolvers import reverse
from django.db import models
+from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy, ugettext_noop
from openslides.projector.models import SlideMixin
@@ -80,15 +81,20 @@ class Mediafile(SlideMixin, models.Model):
def get_filesize(self):
"""
- Transforms Bytes to Kilobytes or Megabytes. Returns the size as string.
+ Transforms bytes to kilobytes or megabytes. Returns the size as string.
"""
# TODO: Read http://stackoverflow.com/a/1094933 and think about it.
- size = self.mediafile.size
- if size < 1024:
- return '< 1 kB'
- if size >= 1024 * 1024:
- mB = size / 1024 / 1024
- return '%d MB' % mB
+ try:
+ size = self.mediafile.size
+ except OSError:
+ size_string = _('unknown')
else:
- kB = size / 1024
- return '%d kB' % kB
+ if size < 1024:
+ size_string = '< 1 kB'
+ elif size >= 1024 * 1024:
+ mB = size / 1024 / 1024
+ size_string = '%d MB' % mB
+ else:
+ kB = size / 1024
+ size_string = '%d kB' % kB
+ return size_string
diff --git a/openslides/mediafile/templates/mediafile/mediafile_list.html b/openslides/mediafile/templates/mediafile/mediafile_list.html
index 518b93f46..9f2d1d370 100644
--- a/openslides/mediafile/templates/mediafile/mediafile_list.html
+++ b/openslides/mediafile/templates/mediafile/mediafile_list.html
@@ -27,7 +27,7 @@
{% for mediafile in mediafile_list %}
{{ mediafile }} |
- {{ mediafile.filetype }} |
+ {% trans mediafile.filetype %} |
{{ mediafile.get_filesize }} |
{{ mediafile.timestamp }} |
{{ mediafile.uploader }} |
diff --git a/openslides/participant/signals.py b/openslides/participant/signals.py
index 54cafa5c1..c76387680 100644
--- a/openslides/participant/signals.py
+++ b/openslides/participant/signals.py
@@ -118,6 +118,7 @@ def create_builtin_groups_and_admin(sender, **kwargs):
group_staff = Group.objects.create(name=ugettext_noop('Staff'), pk=4)
group_staff.permissions.add(perm_7, perm_9, perm_10, perm_10a, perm_11, perm_12, perm_13, perm_14, perm_15, perm_15a, perm_16)
+ group_staff.permissions.add(perm_6) # TODO: Remove this redundancy after cleanup of the permission system
# Admin user
create_or_reset_admin_user()
diff --git a/openslides/projector/exceptions.py b/openslides/projector/exceptions.py
new file mode 100644
index 000000000..88bf6dc00
--- /dev/null
+++ b/openslides/projector/exceptions.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+
+
+class ProjectorExceptionWarning(RuntimeWarning):
+ pass
diff --git a/openslides/projector/projector.py b/openslides/projector/projector.py
index b1a73a8a1..b569284e7 100644
--- a/openslides/projector/projector.py
+++ b/openslides/projector/projector.py
@@ -1,9 +1,12 @@
# -*- coding: utf-8 -*-
-from django.conf import settings
+import warnings
+
from openslides.config.api import config
+from .exceptions import ProjectorExceptionWarning
+
class Overlay(object):
"""
@@ -18,6 +21,9 @@ class Overlay(object):
self.javascript_callback = get_javascript
self.allways_active = allways_active
+ def __repr__(self):
+ return self.name
+
def get_widget_html(self):
"""
Returns the html code for the overlay widget.
@@ -36,11 +42,10 @@ class Overlay(object):
try:
value = self.get_html_wrapper(self.projector_html_callback())
except Exception as exception:
- if settings.DEBUG:
- raise exception
- else:
- # Catch all errors, so an overlay can not kill the projector
- value = ''
+ warnings.warn('%s in overlay "%s": %s'
+ % (type(exception).__name__, self, exception),
+ ProjectorExceptionWarning)
+ value = ''
return value
def get_javascript(self):
diff --git a/openslides/projector/templates/projector/default_slide.html b/openslides/projector/templates/projector/default_slide.html
index 71971372a..a44f04e56 100644
--- a/openslides/projector/templates/projector/default_slide.html
+++ b/openslides/projector/templates/projector/default_slide.html
@@ -2,5 +2,4 @@
{{ 'welcome_title'|get_config }}
-
diff --git a/openslides/projector/templates/projector/projectorslide_slide.html b/openslides/projector/templates/projector/projectorslide_slide.html
index 80c33eaaf..3eb47df89 100644
--- a/openslides/projector/templates/projector/projectorslide_slide.html
+++ b/openslides/projector/templates/projector/projectorslide_slide.html
@@ -2,7 +2,6 @@
{{ slide.title }}
-
{% if slide.text %}
diff --git a/openslides/static/javascript/utils.js b/openslides/static/javascript/utils.js
index c45061b22..7c7602fa4 100644
--- a/openslides/static/javascript/utils.js
+++ b/openslides/static/javascript/utils.js
@@ -72,7 +72,7 @@ $(function () {
function new_message(text, type) {
var message = $('#dummy-notification').clone(true);
- $(message).removeAttr('id').addClass(type).children('em').html(text);
+ $(message).removeAttr('id').addClass(type).html(text);
$('#notifications').append(message);
message.slideDown('fast');
}
diff --git a/openslides/utils/tornado_webserver.py b/openslides/utils/tornado_webserver.py
index 6b64df3b0..2558f141a 100644
--- a/openslides/utils/tornado_webserver.py
+++ b/openslides/utils/tornado_webserver.py
@@ -43,10 +43,10 @@ class DjangoStaticFileHandler(StaticFileHandler):
# a shared root prefix
# - we do not handle self.default_filename (we do not use it and it
# does not make much sense here anyway)
- if not os.path.exists(absolute_path):
+ if absolute_path is None or not os.path.exists(absolute_path):
raise HTTPError(404)
if not os.path.isfile(absolute_path):
- raise HTTPError(403, "%s is not a file", self.path)
+ raise HTTPError(403, 'The requested resource is not a file.')
return absolute_path
diff --git a/tests/agenda/test_list_of_speakers.py b/tests/agenda/test_list_of_speakers.py
index b4e240ac0..a6d4b50d0 100644
--- a/tests/agenda/test_list_of_speakers.py
+++ b/tests/agenda/test_list_of_speakers.py
@@ -5,6 +5,7 @@ from django.test.client import Client
from mock import patch, MagicMock
from openslides.agenda.models import Item, Speaker
+from openslides.agenda.signals import agenda_list_of_speakers
from openslides.config.api import config
from openslides.participant.models import Group, User
from openslides.projector.api import set_active_slide
@@ -300,3 +301,16 @@ class GlobalListOfSpeakersLinks(SpeakerViewTestCase):
response = self.admin_client.get('/agenda/list_of_speakers/end_speach/')
self.assertRedirects(response, '/dashboard/')
self.assertTrue(Speaker.objects.get(item__pk='1').end_time is not None)
+
+
+class TestOverlay(TestCase):
+ def test_overlay_with_no_model_slide(self):
+ """
+ When a slide is active, that is not a model (for example the agenda)
+ an Attribute Error was raised.
+ """
+ config['projector_active_slide'] = {'callback': None}
+
+ value = agenda_list_of_speakers(sender='test').get_projector_html()
+
+ self.assertEqual(value, '')
diff --git a/tests/mediafile/tests.py b/tests/mediafile/tests.py
index 46106f190..507c4691a 100644
--- a/tests/mediafile/tests.py
+++ b/tests/mediafile/tests.py
@@ -255,4 +255,5 @@ class MediafileTest(TestCase):
bigfile.seek(1048575)
bigfile.write('0')
self.assertEqual(object_4.get_filesize(), '1 MB')
- object_4.mediafile.delete()
+ os.remove(mediafile_4_path)
+ self.assertEqual(object_4.get_filesize(), 'unknown')
diff --git a/tests/participant/test_views.py b/tests/participant/test_views.py
index 9c00db5ce..13e7c1800 100644
--- a/tests/participant/test_views.py
+++ b/tests/participant/test_views.py
@@ -2,9 +2,12 @@
import re
+from django.contrib.auth.models import Permission
+from django.contrib.contenttypes.models import ContentType
from django.test.client import Client
from openslides.config.api import config
+from openslides.participant.api import get_registered_group
from openslides.participant.models import get_protected_perm, Group, User
from openslides.utils.test import TestCase
@@ -93,7 +96,9 @@ class GroupViews(TestCase):
class LockoutProtection(TestCase):
"""
Tests that a manager user can not lockout himself by doing
- something that removes his last permission to manage participants.
+ something that removes his last permission to manage participants. Tests
+ also that he can see the participant app (although there is no absolute
+ protection).
"""
def setUp(self):
self.user = User.objects.get(pk=1)
@@ -159,6 +164,17 @@ class LockoutProtection(TestCase):
field=None,
errors='You can not remove the permission to manage participants from the last group you are in.')
+ def test_remove_permission_can_see_participant_from_registered(self):
+ self.assertTrue(self.user.has_perm('participant.can_see_participant'))
+ # Remove perm from registered group
+ can_see_perm = Permission.objects.get(
+ content_type=ContentType.objects.get(app_label='participant', model='user'),
+ codename='can_see_participant')
+ get_registered_group().permissions.remove(can_see_perm)
+ # Reload user
+ self.user = User.objects.get(pk=1)
+ self.assertTrue(self.user.has_perm('participant.can_see_participant'))
+
class TestUserSettings(TestCase):
def setUp(self):
diff --git a/tests/projector/test_overlays.py b/tests/projector/test_overlays.py
index c59927c50..c9e8fdddf 100644
--- a/tests/projector/test_overlays.py
+++ b/tests/projector/test_overlays.py
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
-from mock import MagicMock, patch
+import warnings
+
+from mock import MagicMock
from openslides.projector.projector import Overlay
from openslides.utils.test import TestCase
@@ -9,18 +11,11 @@ from openslides.utils.test import TestCase
class OverlayTest(TestCase):
def test_error_in_html(self):
"""
- Tests that the methof get_projector_html does not raise any errors.
+ Tests that the method get_projector_html does not raise any errors.
"""
get_projector_html = MagicMock(side_effect=Exception('no good error'))
overlay = Overlay('test_overlay', lambda: 'widget_html', get_projector_html)
- # Test in productive mode
- with patch('openslides.projector.projector.settings.DEBUG', False):
- self.assertEqual(overlay.get_projector_html(), '')
-
- # Test in debug mode
- with patch('openslides.projector.projector.settings.DEBUG', True):
- self.assertRaisesMessage(
- Exception,
- 'no good error',
- overlay.get_projector_html)
+ with warnings.catch_warnings(record=True) as warning:
+ overlay.get_projector_html()
+ self.assertEqual(warning[0].message.message, 'Exception in overlay "test_overlay": no good error')