Merge pull request #1208 from ostcar/customslide

Move projector.models.ProjectorSlide to core.models.CustomSlide
This commit is contained in:
Norman Jäckel 2014-01-29 04:09:52 -08:00
commit d49d087f4e
40 changed files with 216 additions and 204 deletions

3
fabfile.py vendored
View File

@ -43,8 +43,7 @@ def check():
""" """
Checks for PEP 8 errors in openslides and in tests. Checks for PEP 8 errors in openslides and in tests.
""" """
local('flake8 --max-line-length=150 --statistics openslides') local('flake8 --max-line-length=150 --statistics openslides tests')
local('flake8 --max-line-length=150 --statistics tests')
def prepare_commit(): def prepare_commit():

View File

@ -2,10 +2,10 @@
{% load tags %} {% load tags %}
<div class="{% if node.is_active_slide %}activeline{% endif %}"> <div class="{% if node.is_active_slide %}activeline{% endif %}">
{% if perms.agenda.can_manage_agenda or perms.projector.can_manage_projector %} {% if perms.agenda.can_manage_agenda or perms.core.can_manage_projector %}
<div class="manage"> <div class="manage">
<span style="width: 1px; white-space: nowrap;"> <span style="width: 1px; white-space: nowrap;">
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{{ node|absolute_url:'projector' }}" <a href="{{ node|absolute_url:'projector' }}"
class="activate_link btn {% if node.is_active_slide and active_type == 'text' %}btn-primary{% endif %} btn-mini" class="activate_link btn {% if node.is_active_slide and active_type == 'text' %}btn-primary{% endif %} btn-mini"
rel="tooltip" data-original-title="{% trans 'Show agenda item' %}"> rel="tooltip" data-original-title="{% trans 'Show agenda item' %}">

View File

@ -79,7 +79,7 @@
{% if perms.agenda.can_see_orga_items %} {% if perms.agenda.can_see_orga_items %}
<th class="duration">{% trans "Duration" %}</th> <th class="duration">{% trans "Duration" %}</th>
{% endif %} {% endif %}
{% if perms.agenda.can_manage_agenda or perms.projector.can_manage_projector %} {% if perms.agenda.can_manage_agenda or perms.core.can_manage_projector %}
<th class="manage">{% trans "Actions" %}</th> <th class="manage">{% trans "Actions" %}</th>
{% endif %} {% endif %}
</tr> </tr>
@ -93,9 +93,9 @@
{% if perms.agenda.can_see_orga_items %} {% if perms.agenda.can_see_orga_items %}
<td class="duration">{{ duration }} h</td> <td class="duration">{{ duration }} h</td>
{% endif %} {% endif %}
{% if perms.agenda.can_manage_agenda or perms.projector.can_manage_projector %} {% if perms.agenda.can_manage_agenda or perms.core.can_manage_projector %}
<td class="manage"> <td class="manage">
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<span> <span>
<a href="{% url 'projector_activate_slide' 'agenda' %}" <a href="{% url 'projector_activate_slide' 'agenda' %}"
class="activate_link btn {% if agenda_is_active %}btn-primary{% endif %} btn-mini" class="activate_link btn {% if agenda_is_active %}btn-primary{% endif %} btn-mini"

View File

@ -21,7 +21,7 @@
{{ item }} {{ item }}
<small class="pull-right"> <small class="pull-right">
<a href="{% url 'item_overview' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a> <a href="{% url 'item_overview' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a>
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{{ item|absolute_url:'projector' }}" <a href="{{ item|absolute_url:'projector' }}"
class="activate_link btn btn-mini {% if item.is_active_slide and active_type != 'list_of_speakers' %}btn-primary{% endif %}" class="activate_link btn btn-mini {% if item.is_active_slide and active_type != 'list_of_speakers' %}btn-primary{% endif %}"
rel="tooltip" data-original-title="{% trans 'Show item' %}"> rel="tooltip" data-original-title="{% trans 'Show item' %}">
@ -67,7 +67,7 @@
<a href="{% url 'agenda_speaker_close' item.pk %}" class="btn btn-mini btn-danger">{% trans 'Close list' %}</a> <a href="{% url 'agenda_speaker_close' item.pk %}" class="btn btn-mini btn-danger">{% trans 'Close list' %}</a>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{{ item|absolute_url:'projector_list_of_speakers' }}" <a href="{{ item|absolute_url:'projector_list_of_speakers' }}"
class="activate_link btn btn-mini {% if item.is_active_slide and active_type == 'list_of_speakers' %}btn-primary{% endif %}" class="activate_link btn btn-mini {% if item.is_active_slide and active_type == 'list_of_speakers' %}btn-primary{% endif %}"
rel="tooltip" data-original-title="{% trans 'Show list of speakers' %}"> rel="tooltip" data-original-title="{% trans 'Show list of speakers' %}">

View File

@ -14,7 +14,7 @@ class AgendaWidget(Widget):
""" """
name = 'agenda' name = 'agenda'
verbose_name = ugettext_lazy('Agenda') verbose_name = ugettext_lazy('Agenda')
permission_required = 'projector.can_manage_projector' permission_required = 'core.can_manage_projector'
default_column = 1 default_column = 1
default_weight = 20 default_weight = 20
template_name = 'agenda/widget_item.html' template_name = 'agenda/widget_item.html'

View File

@ -22,7 +22,7 @@
<a href="{% url 'assignment_list' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a> <a href="{% url 'assignment_list' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a>
<a href="{% url 'assignment_pdf' assignment.id %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'Print election as PDF' %}" target="_blank"><i class="icon-print"></i> PDF</a> <a href="{% url 'assignment_pdf' assignment.id %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'Print election as PDF' %}" target="_blank"><i class="icon-print"></i> PDF</a>
<!-- activate projector --> <!-- activate projector -->
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{{ assignment|absolute_url:'projector' }}" <a href="{{ assignment|absolute_url:'projector' }}"
class="activate_link btn {% if assignment.is_active_slide %}btn-primary{% endif %} btn-mini" class="activate_link btn {% if assignment.is_active_slide %}btn-primary{% endif %} btn-mini"
rel="tooltip" data-original-title="{% trans 'Show election' %}"> rel="tooltip" data-original-title="{% trans 'Show election' %}">

View File

@ -53,7 +53,7 @@
<td><span class="label label-info">{{ object.get_status_display }}</status></td> <td><span class="label label-info">{{ object.get_status_display }}</status></td>
<td> <td>
<span style="width: 1px; white-space: nowrap;"> <span style="width: 1px; white-space: nowrap;">
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{{ object|absolute_url:'projector' }}" <a href="{{ object|absolute_url:'projector' }}"
class="activate_link btn {% if object.is_active_slide %}btn-primary{% endif %} btn-mini" class="activate_link btn {% if object.is_active_slide %}btn-primary{% endif %} btn-mini"
rel="tooltip" data-original-title="{% trans 'Show election' %}"> rel="tooltip" data-original-title="{% trans 'Show election' %}">

View File

@ -15,7 +15,7 @@
<small class="pull-right"> <small class="pull-right">
<a href="{{ assignment|absolute_url:'detail' }}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to election" %}</a> <a href="{{ assignment|absolute_url:'detail' }}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to election" %}</a>
<!-- activate projector --> <!-- activate projector -->
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{{ assignment|absolute_url:'projector' }}" <a href="{{ assignment|absolute_url:'projector' }}"
class="activate_link btn {% if assignment.is_active_slide %}btn-primary{% endif %} btn-mini" class="activate_link btn {% if assignment.is_active_slide %}btn-primary{% endif %} btn-mini"
rel="tooltip" data-original-title="{% trans 'Show election' %}"> rel="tooltip" data-original-title="{% trans 'Show election' %}">

View File

@ -13,7 +13,7 @@ class AssignmentWidget(Widget):
""" """
name = 'assignment' name = 'assignment'
verbose_name = ugettext_lazy('Elections') verbose_name = ugettext_lazy('Elections')
permission_required = 'projector.can_manage_projector' permission_required = 'core.can_manage_projector'
default_column = 1 default_column = 1
default_weight = 50 default_weight = 50
template_name = 'assignment/widget_assignment.html' template_name = 'assignment/widget_assignment.html'

View File

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import main_menu, signals, widgets # noqa from . import main_menu, signals, slides, widgets # noqa

View File

@ -10,7 +10,7 @@ class DashboardMainMenuEntry(MainMenuEntry):
Main menu entry to the dashboard. Main menu entry to the dashboard.
""" """
verbose_name = ugettext_lazy('Dashboard') verbose_name = ugettext_lazy('Dashboard')
permission_required = 'projector.can_see_dashboard' permission_required = 'core.can_see_dashboard'
default_weight = 10 default_weight = 10
icon_css_class = 'icon-home' icon_css_class = 'icon-home'
pattern_name = 'core_dashboard' pattern_name = 'core_dashboard'

View File

@ -0,0 +1,39 @@
from django.core.urlresolvers import reverse
from django.db import models
from django.utils.translation import ugettext_lazy, ugettext_noop
from openslides.utils.models import AbsoluteUrlMixin
from openslides.projector.models import SlideMixin
class CustomSlide(SlideMixin, AbsoluteUrlMixin, models.Model):
"""
Model for Slides, only for the projector.
"""
slide_callback_name = 'customslide'
title = models.CharField(max_length=256, verbose_name=ugettext_lazy('Title'))
text = models.TextField(null=True, blank=True, verbose_name=ugettext_lazy('Text'))
weight = models.IntegerField(default=0, verbose_name=ugettext_lazy('Weight'))
class Meta:
"""
General permissions that can not be placed at a specific app.
"""
permissions = (
('can_manage_projector', ugettext_noop('Can manage the projector')),
('can_see_projector', ugettext_noop('Can see the projector')),
('can_see_dashboard', ugettext_noop('Can see the dashboard')),
)
def __unicode__(self):
return self.title
def get_absolute_url(self, link='update'):
if link == 'update':
url = reverse('customslide_update', args=[str(self.pk)])
elif link == 'delete':
url = reverse('customslide_delete', args=[str(self.pk)])
else:
url = super(CustomSlide, self).get_absolute_url(link)
return url

View File

@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
from openslides.projector.api import register_slide_model
from .models import CustomSlide
register_slide_model(CustomSlide, 'core/customslide_slide.html')

View File

@ -43,7 +43,7 @@
<li>{% trans 'No items available.' %}</li> <li>{% trans 'No items available.' %}</li>
{% endfor %} {% endfor %}
</ul> </ul>
<a href="{% url 'customslide_new' %}" class="btn btn-mini right" style="margin: 10px 0;"> <a href="{% url 'customslide_create' %}" class="btn btn-mini right" style="margin: 10px 0;">
<i class="icon-plus"></i>{% trans 'New' %} <i class="icon-plus"></i>{% trans 'New' %}
</a> </a>
{% endblock %} {% endblock %}

View File

@ -27,4 +27,18 @@ urlpatterns = patterns(
url(r'^search/$', url(r'^search/$',
views.SearchView(), views.SearchView(),
name='core_search',)) name='core_search',),
# CustomSlide urls
url(r'^customslide/new/$',
views.CustomSlideCreateView.as_view(),
name='customslide_create'),
url(r'^customslide/(?P<pk>\d+)/edit/$',
views.CustomSlideUpdateView.as_view(),
name='customslide_update'),
url(r'^customslide/(?P<pk>\d+)/del/$',
views.CustomSlideDeleteView.as_view(),
name='customslide_delete'),
)

View File

@ -15,19 +15,20 @@ from openslides import get_git_commit_id, RELEASE
from openslides.config.api import config from openslides.config.api import config
from openslides.utils.plugins import get_plugin_description, get_plugin_verbose_name, get_plugin_version from openslides.utils.plugins import get_plugin_description, get_plugin_verbose_name, get_plugin_version
from openslides.utils.signals import template_manipulation from openslides.utils.signals import template_manipulation
from openslides.utils.views import AjaxMixin, TemplateView, View from openslides.utils import views as utils_views
from openslides.utils.widgets import Widget from openslides.utils.widgets import Widget
from .forms import SelectWidgetsForm from .forms import SelectWidgetsForm
from .models import CustomSlide
class DashboardView(AjaxMixin, TemplateView): class DashboardView(utils_views.AjaxMixin, utils_views.TemplateView):
""" """
Overview over all possible slides, the overlays and a live view: the Overview over all possible slides, the overlays and a live view: the
Dashboard of OpenSlides. This main view uses the widget api to collect all Dashboard of OpenSlides. This main view uses the widget api to collect all
widgets from all apps. See openslides.utils.widgets.Widget for more details. widgets from all apps. See openslides.utils.widgets.Widget for more details.
""" """
permission_required = 'projector.can_see_dashboard' # TODO: Rename this to core.can_see_dashboard permission_required = 'core.can_see_dashboard'
template_name = 'core/dashboard.html' template_name = 'core/dashboard.html'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -42,13 +43,13 @@ class DashboardView(AjaxMixin, TemplateView):
return context return context
class SelectWidgetsView(TemplateView): class SelectWidgetsView(utils_views.TemplateView):
""" """
Shows a form to select which widgets should be displayed on the own Shows a form to select which widgets should be displayed on the own
dashboard. The setting is saved in the session. dashboard. The setting is saved in the session.
""" """
# TODO: Use another base view class here, e. g. a FormView # TODO: Use another base view class here, e. g. a FormView
permission_required = 'projector.can_see_dashboard' # TODO: Rename this to core.can_see_dashboard permission_required = 'core.can_see_dashboard'
template_name = 'core/select_widgets.html' template_name = 'core/select_widgets.html'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -84,7 +85,7 @@ class SelectWidgetsView(TemplateView):
return redirect(reverse('core_dashboard')) return redirect(reverse('core_dashboard'))
class VersionView(TemplateView): class VersionView(utils_views.TemplateView):
""" """
Shows version infos. Shows version infos.
""" """
@ -155,7 +156,7 @@ class SearchView(_SearchView):
return models return models
class ErrorView(View): class ErrorView(utils_views.View):
""" """
View for Http 403, 404 and 500 error pages. View for Http 403, 404 and 500 error pages.
""" """
@ -180,3 +181,35 @@ class ErrorView(View):
context_instance=RequestContext(request, context)) context_instance=RequestContext(request, context))
response.status_code = self.status_code response.status_code = self.status_code
return response return response
class CustomSlideViewMixin(object):
"""
Mixin for for CustomSlide Views.
"""
permission_required = 'core.can_manage_projector'
template_name = 'core/customslide_update.html'
model = CustomSlide
success_url_name = 'core_dashboard'
url_name_args = []
class CustomSlideCreateView(CustomSlideViewMixin, utils_views.CreateView):
"""
Create a custom slide.
"""
pass
class CustomSlideUpdateView(CustomSlideViewMixin, utils_views.UpdateView):
"""
Update a custom slide.
"""
pass
class CustomSlideDeleteView(CustomSlideViewMixin, utils_views.DeleteView):
"""
Delete a custom slide.
"""
pass

View File

@ -1,16 +1,20 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from openslides.config.api import config from django.utils.translation import ugettext_lazy
from openslides.config.api import config
from openslides.projector.api import get_active_slide
from openslides.utils.widgets import Widget from openslides.utils.widgets import Widget
from .models import CustomSlide
class WelcomeWidget(Widget): class WelcomeWidget(Widget):
""" """
Welcome widget with static info for all users. Welcome widget with static info for all users.
""" """
name = 'welcome' name = 'welcome'
permission_required = 'projector.can_see_dashboard' permission_required = 'core.can_see_dashboard'
default_column = 1 default_column = 1
default_weight = 10 default_weight = 10
template_name = 'core/widget_welcome.html' template_name = 'core/widget_welcome.html'
@ -18,3 +22,23 @@ class WelcomeWidget(Widget):
def get_verbose_name(self): def get_verbose_name(self):
return config['welcome_title'] return config['welcome_title']
class CustonSlideWidget(Widget):
"""
Widget to control custom slides.
"""
name = 'custom_slide'
verbose_name = ugettext_lazy('Custom Slides')
permission_required = 'core.can_manage_projector'
default_column = 2
default_weight = 30
template_name = 'core/widget_customslide.html'
context = None
def get_context_data(self, **context):
return super(CustonSlideWidget, self).get_context_data(
slides=CustomSlide.objects.all().order_by('weight'),
welcomepage_is_active=(
get_active_slide().get('callback', 'default') == 'default'),
**context)

View File

@ -14,7 +14,7 @@ class PDFPresentationWidget(Widget):
""" """
name = 'presentations' name = 'presentations'
verbose_name = ugettext_lazy('Presentations') verbose_name = ugettext_lazy('Presentations')
permission_required = 'projector.can_manage_projector' permission_required = 'core.can_manage_projector'
default_column = 1 default_column = 1
default_weight = 75 default_weight = 75
template_name = 'mediafile/widget_pdfpresentation.html' template_name = 'mediafile/widget_pdfpresentation.html'

View File

@ -37,7 +37,7 @@
rel="tooltip" data-original-title="{% trans 'Print motion as PDF' %}" target="_blank"> rel="tooltip" data-original-title="{% trans 'Print motion as PDF' %}" target="_blank">
<i class="icon-print"></i> PDF</a> <i class="icon-print"></i> PDF</a>
<!-- activate projector --> <!-- activate projector -->
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{{ motion|absolute_url:'projector' }}" class="activate_link btn {% if motion.is_active_slide %}btn-primary{% endif %} btn-mini" rel="tooltip" data-original-title="{% trans 'Show motion' %}"> <a href="{{ motion|absolute_url:'projector' }}" class="activate_link btn {% if motion.is_active_slide %}btn-primary{% endif %} btn-mini" rel="tooltip" data-original-title="{% trans 'Show motion' %}">
<i class="icon-facetime-video {% if motion.is_active_slide %}icon-white{% endif %}"></i> <i class="icon-facetime-video {% if motion.is_active_slide %}icon-white{% endif %}"></i>
</a> </a>

View File

@ -78,7 +78,7 @@
{% endif %}</td> {% endif %}</td>
<td> <td>
<span style="width: 1px; white-space: nowrap;"> <span style="width: 1px; white-space: nowrap;">
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{{ motion|absolute_url:'projector' }}" class="activate_link btn {% if motion.is_active_slide %}btn-primary{% endif %} btn-mini" <a href="{{ motion|absolute_url:'projector' }}" class="activate_link btn {% if motion.is_active_slide %}btn-primary{% endif %} btn-mini"
rel="tooltip" data-original-title="{% trans 'Show motion' %}"> rel="tooltip" data-original-title="{% trans 'Show motion' %}">
<i class="icon-facetime-video {% if motion.is_active_slide %}icon-white{% endif %}"></i> <i class="icon-facetime-video {% if motion.is_active_slide %}icon-white{% endif %}"></i>

View File

@ -18,7 +18,7 @@
<div class="btn-toolbar"> <div class="btn-toolbar">
<a href="{% url 'motion_detail' motion.id %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to motion" %}</a> <a href="{% url 'motion_detail' motion.id %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to motion" %}</a>
<!-- activate projector --> <!-- activate projector -->
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{{ motion|absolute_url:'projector' }}" class="activate_link btn {% if motion.is_active_slide %}btn-primary{% endif %} btn-mini" rel="tooltip" data-original-title="{% trans 'Show motion' %}"> <a href="{{ motion|absolute_url:'projector' }}" class="activate_link btn {% if motion.is_active_slide %}btn-primary{% endif %} btn-mini" rel="tooltip" data-original-title="{% trans 'Show motion' %}">
<i class="icon-facetime-video {% if motion.is_active_slide %}icon-white{% endif %}"></i> <i class="icon-facetime-video {% if motion.is_active_slide %}icon-white{% endif %}"></i>
</a> </a>

View File

@ -13,7 +13,7 @@ class MotionWidget(Widget):
""" """
name = 'motion' name = 'motion'
verbose_name = ugettext_lazy('Motions') verbose_name = ugettext_lazy('Motions')
permission_required = 'projector.can_manage_projector' permission_required = 'core.can_manage_projector'
default_column = 1 default_column = 1
default_weight = 40 default_weight = 40
icon_css_class = 'icon-file' icon_css_class = 'icon-file'

View File

@ -68,9 +68,9 @@ def create_builtin_groups_and_admin(sender, **kwargs):
return return
# Anonymous and Registered # Anonymous and Registered
ct_projector = ContentType.objects.get(app_label='projector', model='projectorslide') ct_core = ContentType.objects.get(app_label='core', model='customslide')
perm_1 = Permission.objects.get(content_type=ct_projector, codename='can_see_projector') perm_1 = Permission.objects.get(content_type=ct_core, codename='can_see_projector')
perm_2 = Permission.objects.get(content_type=ct_projector, codename='can_see_dashboard') perm_2 = Permission.objects.get(content_type=ct_core, codename='can_see_dashboard')
ct_agenda = ContentType.objects.get(app_label='agenda', model='item') ct_agenda = ContentType.objects.get(app_label='agenda', model='item')
ct_speaker = ContentType.objects.get(app_label='agenda', model='speaker') ct_speaker = ContentType.objects.get(app_label='agenda', model='speaker')
@ -110,7 +110,7 @@ def create_builtin_groups_and_admin(sender, **kwargs):
perm_12 = Permission.objects.get(content_type=ct_motion, codename='can_manage_motion') perm_12 = Permission.objects.get(content_type=ct_motion, codename='can_manage_motion')
perm_13 = Permission.objects.get(content_type=ct_assignment, codename='can_manage_assignment') perm_13 = Permission.objects.get(content_type=ct_assignment, codename='can_manage_assignment')
perm_14 = Permission.objects.get(content_type=ct_participant, codename='can_manage_participant') perm_14 = Permission.objects.get(content_type=ct_participant, codename='can_manage_participant')
perm_15 = Permission.objects.get(content_type=ct_projector, codename='can_manage_projector') perm_15 = Permission.objects.get(content_type=ct_core, codename='can_manage_projector')
perm_15a = Permission.objects.get(content_type=ct_mediafile, codename='can_manage') perm_15a = Permission.objects.get(content_type=ct_mediafile, codename='can_manage')
ct_config = ContentType.objects.get(app_label='config', model='configstore') ct_config = ContentType.objects.get(app_label='config', model='configstore')

View File

@ -11,7 +11,7 @@
<small class="pull-right"> <small class="pull-right">
<a href="{% url 'user_group_overview' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a> <a href="{% url 'user_group_overview' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a>
<!-- activate projector --> <!-- activate projector -->
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{% url 'projector_activate_slide' group.sid %}" class="activate_link btn {% if group.active %}btn-primary{% endif %} btn-mini" rel="tooltip" data-original-title="{% trans 'Show group' %}"> <a href="{% url 'projector_activate_slide' group.sid %}" class="activate_link btn {% if group.active %}btn-primary{% endif %} btn-mini" rel="tooltip" data-original-title="{% trans 'Show group' %}">
<i class="icon-facetime-video {% if group.active %}icon-white{% endif %}"></i> <i class="icon-facetime-video {% if group.active %}icon-white{% endif %}"></i>
</a> </a>

View File

@ -48,7 +48,7 @@
</td> </td>
<td> <td>
<span style="width: 1px; white-space: nowrap;"> <span style="width: 1px; white-space: nowrap;">
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{{ group|absolute_url:'projector' }}" <a href="{{ group|absolute_url:'projector' }}"
class="activate_link btn {% if group.is_active_slide %}btn-primary{% endif %} btn-mini" class="activate_link btn {% if group.is_active_slide %}btn-primary{% endif %} btn-mini"
rel="tooltip" data-original-title="{% trans 'Show group' %}"> rel="tooltip" data-original-title="{% trans 'Show group' %}">

View File

@ -108,7 +108,7 @@
</td> </td>
<td> <td>
<span style="width: 1px; white-space: nowrap;"> <span style="width: 1px; white-space: nowrap;">
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{{ user|absolute_url:'projector' }}" class="activate_link btn {% if user.is_active_slide %}btn-primary{% endif %} btn-mini" <a href="{{ user|absolute_url:'projector' }}" class="activate_link btn {% if user.is_active_slide %}btn-primary{% endif %} btn-mini"
rel="tooltip" data-original-title="{% trans 'Show participant' %}"> rel="tooltip" data-original-title="{% trans 'Show participant' %}">
<i class="icon-facetime-video {% if user.is_active_slide %}icon-white{% endif %}"></i> <i class="icon-facetime-video {% if user.is_active_slide %}icon-white{% endif %}"></i>

View File

@ -11,7 +11,7 @@
<small class="pull-right"> <small class="pull-right">
<a href="{% url 'user_overview' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a> <a href="{% url 'user_overview' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a>
<!-- activate projector --> <!-- activate projector -->
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<a href="{% url 'projector_activate_slide' shown_user.sid %}" class="activate_link btn {% if shown_user.active %}btn-primary{% endif %} btn-mini" rel="tooltip" data-original-title="{% trans 'Show participant' %}"> <a href="{% url 'projector_activate_slide' shown_user.sid %}" class="activate_link btn {% if shown_user.active %}btn-primary{% endif %} btn-mini" rel="tooltip" data-original-title="{% trans 'Show participant' %}">
<i class="icon-facetime-video {% if shown_user.active %}icon-white{% endif %}"></i> <i class="icon-facetime-video {% if shown_user.active %}icon-white{% endif %}"></i>
</a> </a>

View File

@ -14,7 +14,7 @@ class UserWidget(Widget):
""" """
name = 'user' name = 'user'
verbose_name = ugettext_lazy('Participants') verbose_name = ugettext_lazy('Participants')
permission_required = 'projector.can_manage_projector' permission_required = 'core.can_manage_projector'
default_column = 1 default_column = 1
default_weight = 60 default_weight = 60
default_active = False default_active = False
@ -34,7 +34,7 @@ class GroupWidget(Widget):
""" """
name = 'group' name = 'group'
verbose_name = ugettext_lazy('Groups') verbose_name = ugettext_lazy('Groups')
permission_required = 'projector.can_manage_projector' permission_required = 'core.can_manage_projector'
default_column = 1 default_column = 1
default_weight = 70 default_weight = 70
default_active = False default_active = False

View File

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import signals, slides, widgets # noqa from . import signals, widgets # noqa

View File

@ -2,10 +2,7 @@
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import models
from django.utils.translation import ugettext_lazy, ugettext_noop
from openslides.utils.models import AbsoluteUrlMixin
from openslides.utils.utils import int_or_none from openslides.utils.utils import int_or_none
@ -105,35 +102,3 @@ class SlideMixin(object):
context.update({'slide': self, context.update({'slide': self,
slide_name: self}) slide_name: self})
return context return context
class ProjectorSlide(SlideMixin, AbsoluteUrlMixin, models.Model):
"""
Model for Slides, only for the projector. Also called custom slides.
"""
# TODO: Rename it to CustomSlide and move it to core app.
# Check and rename permissions.
slide_callback_name = 'projector_slide'
title = models.CharField(max_length=256, verbose_name=ugettext_lazy("Title"))
text = models.TextField(null=True, blank=True, verbose_name=ugettext_lazy("Text"))
weight = models.IntegerField(default=0, verbose_name=ugettext_lazy("Weight"))
class Meta:
permissions = (
('can_manage_projector', ugettext_noop("Can manage the projector")),
('can_see_projector', ugettext_noop("Can see the projector")),
('can_see_dashboard', ugettext_noop("Can see the dashboard")),
)
def __unicode__(self):
return self.title
def get_absolute_url(self, link='update'):
if link == 'update':
url = reverse('customslide_edit', args=[str(self.pk)])
elif link == 'delete':
url = reverse('customslide_delete', args=[str(self.pk)])
else:
url = super(ProjectorSlide, self).get_absolute_url(link)
return url

View File

@ -1,7 +0,0 @@
# -*- coding: utf-8 -*-
from openslides.projector.api import register_slide_model
from .models import ProjectorSlide
register_slide_model(ProjectorSlide, 'projector/projectorslide_slide.html')

View File

@ -14,7 +14,7 @@
</a> </a>
<!-- projector control buttons --> <!-- projector control buttons -->
{% if perms.projector.can_manage_projector %} {% if perms.core.can_manage_projector %}
<p> <p>
<a class="projector_edit btn" href="{% url 'projector_bigger' %}" title="{% trans 'Zoom in' %}"> <a class="projector_edit btn" href="{% url 'projector_bigger' %}" title="{% trans 'Zoom in' %}">
<i class="icon-zoom-in"></i> <i class="icon-zoom-in"></i>

View File

@ -27,18 +27,6 @@ urlpatterns = patterns(
views.OverlayMessageView.as_view(), views.OverlayMessageView.as_view(),
name='projector_overlay_message'), name='projector_overlay_message'),
url(r'^new/$',
views.CustomSlideCreateView.as_view(),
name='customslide_new'),
url(r'^(?P<pk>\d+)/edit/$',
views.CustomSlideUpdateView.as_view(),
name='customslide_edit'),
url(r'^(?P<pk>\d+)/del/$',
views.CustomSlideDeleteView.as_view(),
name='customslide_delete'),
url(r'^bigger/$', url(r'^bigger/$',
views.ProjectorControllView.as_view(), views.ProjectorControllView.as_view(),
{'direction': 'bigger'}, {'direction': 'bigger'},

View File

@ -3,21 +3,19 @@
from openslides.config.api import config from openslides.config.api import config
from openslides.mediafile.models import Mediafile from openslides.mediafile.models import Mediafile
from openslides.utils.tornado_webserver import ProjectorSocketHandler from openslides.utils.tornado_webserver import ProjectorSocketHandler
from openslides.utils.views import (CreateView, DeleteView, from openslides.utils.views import RedirectView, TemplateView
RedirectView, TemplateView, UpdateView)
from .api import (call_on_projector, get_active_slide, from .api import (call_on_projector, get_active_slide,
get_overlays, get_projector_content, get_projector_overlays, get_overlays, get_projector_content, get_projector_overlays,
get_projector_overlays_js, reset_countdown, set_active_slide, get_projector_overlays_js, reset_countdown, set_active_slide,
start_countdown, stop_countdown, update_projector_overlay) start_countdown, stop_countdown, update_projector_overlay)
from .models import ProjectorSlide
class ProjectorView(TemplateView): class ProjectorView(TemplateView):
""" """
The Projector-Page. The Projector-Page.
""" """
permission_required = 'projector.can_see_projector' permission_required = 'core.can_see_projector'
template_name = 'projector.html' template_name = 'projector.html'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -45,7 +43,7 @@ class ActivateView(RedirectView):
""" """
Activate a Slide. Activate a Slide.
""" """
permission_required = 'projector.can_manage_projector' permission_required = 'core.can_manage_projector'
url_name = 'core_dashboard' url_name = 'core_dashboard'
allow_ajax = True allow_ajax = True
@ -72,7 +70,7 @@ class ProjectorControllView(RedirectView):
""" """
Scale or scroll the projector. Scale or scroll the projector.
""" """
permission_required = 'projector.can_manage_projector' permission_required = 'core.can_manage_projector'
url_name = 'core_dashboard' url_name = 'core_dashboard'
allow_ajax = True allow_ajax = True
@ -106,7 +104,7 @@ class CountdownControllView(RedirectView):
""" """
Start, stop or reset the countdown. Start, stop or reset the countdown.
""" """
permission_required = 'projector.can_manage_projector' permission_required = 'core.can_manage_projector'
url_name = 'core_dashboard' url_name = 'core_dashboard'
allow_ajax = True allow_ajax = True
@ -141,7 +139,7 @@ class OverlayMessageView(RedirectView):
""" """
url_name = 'core_dashboard' url_name = 'core_dashboard'
allow_ajax = True allow_ajax = True
permission_required = 'projector.can_manage_projector' permission_required = 'core.can_manage_projector'
def pre_post_redirect(self, request, *args, **kwargs): def pre_post_redirect(self, request, *args, **kwargs):
if 'message' in request.POST: if 'message' in request.POST:
@ -162,7 +160,7 @@ class ActivateOverlay(RedirectView):
""" """
url_name = 'core_dashboard' url_name = 'core_dashboard'
allow_ajax = True allow_ajax = True
permission_required = 'projector.can_manage_projector' permission_required = 'core.can_manage_projector'
def pre_redirect(self, request, *args, **kwargs): def pre_redirect(self, request, *args, **kwargs):
overlay = get_overlays()[kwargs['name']] overlay = get_overlays()[kwargs['name']]
@ -180,36 +178,3 @@ class ActivateOverlay(RedirectView):
def get_ajax_context(self, **kwargs): def get_ajax_context(self, **kwargs):
return {'active': self.active, 'name': self.name} return {'active': self.active, 'name': self.name}
class CustomSlideCreateView(CreateView):
"""
Create a custom slide.
"""
permission_required = 'agenda.can_manage_agenda'
template_name = 'projector/new.html'
model = ProjectorSlide
context_object_name = 'customslide'
success_url_name = 'core_dashboard'
url_name_args = []
class CustomSlideUpdateView(UpdateView):
"""
Update a custom slide.
"""
permission_required = 'projector.can_manage_projector'
template_name = 'projector/new.html'
model = ProjectorSlide
context_object_name = 'customslide'
success_url_name = 'core_dashboard'
url_name_args = []
class CustomSlideDeleteView(DeleteView):
"""
Delete a custom slide.
"""
permission_required = 'projector.can_manage_projector'
model = ProjectorSlide
success_url_name = 'core_dashboard'

View File

@ -3,10 +3,8 @@
from django.core.context_processors import csrf from django.core.context_processors import csrf
from django.utils.translation import ugettext_lazy from django.utils.translation import ugettext_lazy
from openslides.projector.api import get_active_slide
from openslides.utils.widgets import Widget from openslides.utils.widgets import Widget
from .models import ProjectorSlide
from .signals import projector_overlays from .signals import projector_overlays
@ -16,7 +14,7 @@ class ProjectorLiveWidget(Widget):
""" """
name = 'live_view' name = 'live_view'
verbose_name = ugettext_lazy('Projector live view') verbose_name = ugettext_lazy('Projector live view')
permission_required = 'projector.can_see_projector' permission_required = 'core.can_see_projector'
default_column = 2 default_column = 2
default_weight = 10 default_weight = 10
template_name = 'projector/widget_live_view.html' template_name = 'projector/widget_live_view.html'
@ -28,7 +26,7 @@ class OverlayWidget(Widget):
""" """
name = 'overlays' # TODO: Use singular here name = 'overlays' # TODO: Use singular here
verbose_name = ugettext_lazy('Overlays') verbose_name = ugettext_lazy('Overlays')
permission_required = 'projector.can_manage_projector' permission_required = 'core.can_manage_projector'
default_column = 2 default_column = 2
default_weight = 20 default_weight = 20
template_name = 'projector/widget_overlay.html' template_name = 'projector/widget_overlay.html'
@ -44,22 +42,3 @@ class OverlayWidget(Widget):
return super(OverlayWidget, self).get_context_data( return super(OverlayWidget, self).get_context_data(
overlays=overlays, overlays=overlays,
**context) **context)
class CustonSlideWidget(Widget):
"""
Widget to control custom slides.
"""
name = 'custom_slide'
verbose_name = ugettext_lazy('Custom Slides')
permission_required = 'projector.can_manage_projector'
default_column = 2
default_weight = 30
template_name = 'projector/widget_custom_slide.html'
context = None
def get_context_data(self, **context):
return super(CustonSlideWidget, self).get_context_data(
slides=ProjectorSlide.objects.all().order_by('weight'),
welcomepage_is_active=get_active_slide().get('callback', 'default') == 'default',
**context)

View File

@ -7,6 +7,7 @@ from openslides import get_version
from openslides.agenda.models import Item from openslides.agenda.models import Item
from openslides.config.api import config from openslides.config.api import config
from openslides.core import views from openslides.core import views
from openslides.core.models import CustomSlide
from openslides.participant.models import User from openslides.participant.models import User
from openslides.utils.test import TestCase from openslides.utils.test import TestCase
@ -15,7 +16,7 @@ class SelectWidgetsViewTest(TestCase):
rf = RequestFactory() rf = RequestFactory()
@patch('openslides.core.views.SelectWidgetsForm') @patch('openslides.core.views.SelectWidgetsForm')
@patch('openslides.core.views.TemplateView.get_context_data') @patch('openslides.core.views.utils_views.TemplateView.get_context_data')
@patch('openslides.core.views.Widget') @patch('openslides.core.views.Widget')
def test_get_context_data(self, mock_Widget, mock_get_context_data, def test_get_context_data(self, mock_Widget, mock_get_context_data,
mock_SelectWidgetsForm): mock_SelectWidgetsForm):
@ -99,3 +100,46 @@ class SearchViewTest(TestCase):
self.assertEqual(Client().get('/search/').status_code, 403) self.assertEqual(Client().get('/search/').status_code, 403)
config['system_enable_anonymous'] = True config['system_enable_anonymous'] = True
self.assertEqual(Client().get('/search/').status_code, 200) self.assertEqual(Client().get('/search/').status_code, 200)
class CustomSlidesTest(TestCase):
def setUp(self):
self.admin_client = Client()
self.admin_client.login(username='admin', password='admin')
def test_create(self):
url = '/customslide/new/'
response = self.admin_client.get(url)
self.assertTemplateUsed(response, 'core/customslide_update.html')
response = self.admin_client.post(
url,
{'title': 'test_title_roo2xi2EibooHie1kohd', 'weight': '0'})
self.assertRedirects(response, '/dashboard/')
self.assertTrue(CustomSlide.objects.filter(
title='test_title_roo2xi2EibooHie1kohd').exists())
def test_update(self):
# Setup
url = '/customslide/1/edit/'
CustomSlide.objects.create(title='test_title_jeeDeB3aedei8ahceeso')
# Test
response = self.admin_client.get(url)
self.assertTemplateUsed(response, 'core/customslide_update.html')
self.assertContains(response, 'test_title_jeeDeB3aedei8ahceeso')
response = self.admin_client.post(
url,
{'title': 'test_title_ai8Ooboh5bahr6Ee7goo', 'weight': '0'})
self.assertRedirects(response, '/dashboard/')
self.assertEqual(CustomSlide.objects.get(pk=1).title,
'test_title_ai8Ooboh5bahr6Ee7goo')
def test_delete(self):
# Setup
url = '/customslide/1/del/'
CustomSlide.objects.create(title='test_title_oyie0em1chieM7YohX4H')
# Test
response = self.admin_client.get(url)
self.assertRedirects(response, '/customslide/1/edit/')
response = self.admin_client.post(url, {'yes': 'true'})
self.assertRedirects(response, '/dashboard/')
self.assertFalse(CustomSlide.objects.exists())

View File

@ -82,8 +82,8 @@ class DefaultGroups(TestCase):
def test_default_perms_anonymous(self): def test_default_perms_anonymous(self):
anonymous = Group.objects.get(pk=1) anonymous = Group.objects.get(pk=1)
default_perms = ('projector.can_see_projector', default_perms = ('core.can_see_projector',
'projector.can_see_dashboard', 'core.can_see_dashboard',
'agenda.can_see_agenda', 'agenda.can_see_agenda',
'agenda.can_see_orga_items', 'agenda.can_see_orga_items',
'motion.can_see_motion', 'motion.can_see_motion',

View File

@ -5,7 +5,6 @@ from django.test.client import Client, RequestFactory
from mock import call, MagicMock, patch from mock import call, MagicMock, patch
from openslides.config.api import config from openslides.config.api import config
from openslides.projector.models import ProjectorSlide
from openslides.projector import views from openslides.projector import views
from openslides.utils.test import TestCase from openslides.utils.test import TestCase
@ -114,43 +113,6 @@ class ProjectorControllViewTest(TestCase):
self.assertEqual(context, {'scale_level': 1, 'scroll_level': 2}) self.assertEqual(context, {'scale_level': 1, 'scroll_level': 2})
class CustomSlidesTest(TestCase):
def setUp(self):
self.admin_client = Client()
self.admin_client.login(username='admin', password='admin')
def test_create(self):
url = '/projector/new/'
response = self.admin_client.get(url)
self.assertTemplateUsed(response, 'projector/new.html')
response = self.admin_client.post(url, {'title': 'test_title_roo2xi2EibooHie1kohd', 'weight': '0'})
self.assertRedirects(response, '/dashboard/')
self.assertTrue(ProjectorSlide.objects.filter(title='test_title_roo2xi2EibooHie1kohd').exists())
def test_update(self):
# Setup
url = '/projector/1/edit/'
ProjectorSlide.objects.create(title='test_title_jeeDeB3aedei8ahceeso')
# Test
response = self.admin_client.get(url)
self.assertTemplateUsed(response, 'projector/new.html')
self.assertContains(response, 'test_title_jeeDeB3aedei8ahceeso')
response = self.admin_client.post(url, {'title': 'test_title_ai8Ooboh5bahr6Ee7goo', 'weight': '0'})
self.assertRedirects(response, '/dashboard/')
self.assertEqual(ProjectorSlide.objects.get(pk=1).title, 'test_title_ai8Ooboh5bahr6Ee7goo')
def test_delete(self):
# Setup
url = '/projector/1/del/'
ProjectorSlide.objects.create(title='test_title_oyie0em1chieM7YohX4H')
# Test
response = self.admin_client.get(url)
self.assertRedirects(response, '/projector/1/edit/')
response = self.admin_client.post(url, {'yes': 'true'})
self.assertRedirects(response, '/dashboard/')
self.assertFalse(ProjectorSlide.objects.exists())
class CountdownControllView(TestCase): class CountdownControllView(TestCase):
def setUp(self): def setUp(self):
self.admin_client = Client() self.admin_client = Client()