Merge branch 'stable/1.5.x'

Conflicts:
	openslides/projector/projector.py
	openslides/templates/base.html
This commit is contained in:
Oskar Hahn 2014-01-11 22:30:14 +01:00
commit cde6232477
15 changed files with 85 additions and 36 deletions

View File

@ -27,6 +27,14 @@ Version 1.5.1 (unreleased)
========================== ==========================
[https://github.com/OpenSlides/OpenSlides/issues?milestone=15] [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) Version 1.5 (2013-11-25)
======================== ========================

View File

@ -98,7 +98,7 @@ def agenda_list_of_speakers(sender, **kwargs):
list-of-speakers slide. list-of-speakers slide.
""" """
slide = get_active_object() slide = get_active_object()
if isinstance(slide, Item): if slide is None or isinstance(slide, Item):
item = slide item = slide
else: else:
# TODO: If there are more the one items, use the first one in the # TODO: If there are more the one items, use the first one in the

View File

@ -4,6 +4,7 @@ import mimetypes
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import models from django.db import models
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy, ugettext_noop from django.utils.translation import ugettext_lazy, ugettext_noop
from openslides.projector.models import SlideMixin from openslides.projector.models import SlideMixin
@ -80,15 +81,20 @@ class Mediafile(SlideMixin, models.Model):
def get_filesize(self): 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. # TODO: Read http://stackoverflow.com/a/1094933 and think about it.
size = self.mediafile.size try:
if size < 1024: size = self.mediafile.size
return '< 1 kB' except OSError:
if size >= 1024 * 1024: size_string = _('unknown')
mB = size / 1024 / 1024
return '%d MB' % mB
else: else:
kB = size / 1024 if size < 1024:
return '%d kB' % kB 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

View File

@ -27,7 +27,7 @@
{% for mediafile in mediafile_list %} {% for mediafile in mediafile_list %}
<tr class="{% if mediafile.is_active_slide %}activeline{% endif %}"> <tr class="{% if mediafile.is_active_slide %}activeline{% endif %}">
<td><a href="{{ mediafile.mediafile.url }}">{{ mediafile }}</a></td> <td><a href="{{ mediafile.mediafile.url }}">{{ mediafile }}</a></td>
<td>{{ mediafile.filetype }}</td> <td>{% trans mediafile.filetype %}</td>
<td>{{ mediafile.get_filesize }}</td> <td>{{ mediafile.get_filesize }}</td>
<td>{{ mediafile.timestamp }}</td> <td>{{ mediafile.timestamp }}</td>
<td><a href="{{ mediafile.uploader|absolute_url }}">{{ mediafile.uploader }}</a></td> <td><a href="{{ mediafile.uploader|absolute_url }}">{{ mediafile.uploader }}</a></td>

View File

@ -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 = 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_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 # Admin user
create_or_reset_admin_user() create_or_reset_admin_user()

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
class ProjectorExceptionWarning(RuntimeWarning):
pass

View File

@ -1,9 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.conf import settings import warnings
from openslides.config.api import config from openslides.config.api import config
from .exceptions import ProjectorExceptionWarning
class Overlay(object): class Overlay(object):
""" """
@ -18,6 +21,9 @@ class Overlay(object):
self.javascript_callback = get_javascript self.javascript_callback = get_javascript
self.allways_active = allways_active self.allways_active = allways_active
def __repr__(self):
return self.name
def get_widget_html(self): def get_widget_html(self):
""" """
Returns the html code for the overlay widget. Returns the html code for the overlay widget.
@ -36,11 +42,10 @@ class Overlay(object):
try: try:
value = self.get_html_wrapper(self.projector_html_callback()) value = self.get_html_wrapper(self.projector_html_callback())
except Exception as exception: except Exception as exception:
if settings.DEBUG: warnings.warn('%s in overlay "%s": %s'
raise exception % (type(exception).__name__, self, exception),
else: ProjectorExceptionWarning)
# Catch all errors, so an overlay can not kill the projector value = ''
value = ''
return value return value
def get_javascript(self): def get_javascript(self):

View File

@ -2,5 +2,4 @@
<h1> <h1>
{{ 'welcome_title'|get_config }} {{ 'welcome_title'|get_config }}
<hr>
</h1> </h1>

View File

@ -2,7 +2,6 @@
<h1> <h1>
{{ slide.title }} {{ slide.title }}
<hr>
</h1> </h1>
{% if slide.text %} {% if slide.text %}

View File

@ -72,7 +72,7 @@ $(function () {
function new_message(text, type) { function new_message(text, type) {
var message = $('#dummy-notification').clone(true); 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); $('#notifications').append(message);
message.slideDown('fast'); message.slideDown('fast');
} }

View File

@ -43,10 +43,10 @@ class DjangoStaticFileHandler(StaticFileHandler):
# a shared root prefix # a shared root prefix
# - we do not handle self.default_filename (we do not use it and it # - we do not handle self.default_filename (we do not use it and it
# does not make much sense here anyway) # 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) raise HTTPError(404)
if not os.path.isfile(absolute_path): 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 return absolute_path

View File

@ -5,6 +5,7 @@ from django.test.client import Client
from mock import patch, MagicMock from mock import patch, MagicMock
from openslides.agenda.models import Item, Speaker from openslides.agenda.models import Item, Speaker
from openslides.agenda.signals import agenda_list_of_speakers
from openslides.config.api import config from openslides.config.api import config
from openslides.participant.models import Group, User from openslides.participant.models import Group, User
from openslides.projector.api import set_active_slide 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/') response = self.admin_client.get('/agenda/list_of_speakers/end_speach/')
self.assertRedirects(response, '/dashboard/') self.assertRedirects(response, '/dashboard/')
self.assertTrue(Speaker.objects.get(item__pk='1').end_time is not None) 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, '')

View File

@ -255,4 +255,5 @@ class MediafileTest(TestCase):
bigfile.seek(1048575) bigfile.seek(1048575)
bigfile.write('0') bigfile.write('0')
self.assertEqual(object_4.get_filesize(), '1 MB') self.assertEqual(object_4.get_filesize(), '1 MB')
object_4.mediafile.delete() os.remove(mediafile_4_path)
self.assertEqual(object_4.get_filesize(), 'unknown')

View File

@ -2,9 +2,12 @@
import re import re
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.test.client import Client from django.test.client import Client
from openslides.config.api import config 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.participant.models import get_protected_perm, Group, User
from openslides.utils.test import TestCase from openslides.utils.test import TestCase
@ -93,7 +96,9 @@ class GroupViews(TestCase):
class LockoutProtection(TestCase): class LockoutProtection(TestCase):
""" """
Tests that a manager user can not lockout himself by doing 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): def setUp(self):
self.user = User.objects.get(pk=1) self.user = User.objects.get(pk=1)
@ -159,6 +164,17 @@ class LockoutProtection(TestCase):
field=None, field=None,
errors='You can not remove the permission to manage participants from the last group you are in.') 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): class TestUserSettings(TestCase):
def setUp(self): def setUp(self):

View File

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from mock import MagicMock, patch import warnings
from mock import MagicMock
from openslides.projector.projector import Overlay from openslides.projector.projector import Overlay
from openslides.utils.test import TestCase from openslides.utils.test import TestCase
@ -9,18 +11,11 @@ from openslides.utils.test import TestCase
class OverlayTest(TestCase): class OverlayTest(TestCase):
def test_error_in_html(self): 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')) get_projector_html = MagicMock(side_effect=Exception('no good error'))
overlay = Overlay('test_overlay', lambda: 'widget_html', get_projector_html) overlay = Overlay('test_overlay', lambda: 'widget_html', get_projector_html)
# Test in productive mode with warnings.catch_warnings(record=True) as warning:
with patch('openslides.projector.projector.settings.DEBUG', False): overlay.get_projector_html()
self.assertEqual(overlay.get_projector_html(), '') self.assertEqual(warning[0].message.message, 'Exception in overlay "test_overlay": no good error')
# Test in debug mode
with patch('openslides.projector.projector.settings.DEBUG', True):
self.assertRaisesMessage(
Exception,
'no good error',
overlay.get_projector_html)