diff --git a/openslides/agenda/forms.py b/openslides/agenda/forms.py
index 2de5af684..c9cd348b2 100644
--- a/openslides/agenda/forms.py
+++ b/openslides/agenda/forms.py
@@ -10,39 +10,46 @@
:license: GNU GPL, see LICENSE for more details.
"""
-from django.forms import Form, ModelForm, IntegerField, ChoiceField, \
- ModelChoiceField, HiddenInput, Select, TextInput
+from django import forms
+from django.utils.translation import ugettext as _
from mptt.forms import TreeNodeChoiceField
from utils.forms import CssClassMixin
-from utils.translation_ext import ugettext as _
from agenda.models import Item
-class ItemForm(ModelForm, CssClassMixin):
- parent = TreeNodeChoiceField(queryset=Item.objects.all(), label=_("Parent item"), required=False)
+class ItemForm(forms.ModelForm, CssClassMixin):
+ """
+ Form to create of update an item.
+ """
+ parent = TreeNodeChoiceField(queryset=Item.objects.all(),
+ label=_("Parent item"), required=False)
+
class Meta:
model = Item
- exclude = ('closed', 'weight', 'releated_sid')
+ exclude = ('closed', 'weight', 'related_sid')
-def genweightchoices():
- l = []
- for i in range(-50, 51):
- l.append(('%d' % i, i))
- return l
+def gen_weight_choices():
+ """
+ Creates a list of tuples (n, n) for n from -49 to 50.
+ """
+ return zip(*(range(-50, 51), range(-50, 51)))
-class ItemOrderForm(Form, CssClassMixin):
- weight = ChoiceField(choices=genweightchoices(),
- widget=Select(attrs={'class': 'menu-weight'}),
- label="")
- self = IntegerField(widget=HiddenInput(attrs={'class': 'menu-mlid'}))
- parent = IntegerField(widget=HiddenInput(attrs={'class': 'menu-plid'}))
-
-
-class ConfigForm(Form, CssClassMixin):
- pass
-
+class ItemOrderForm(forms.Form, CssClassMixin):
+ """
+ Form to change the order of the items.
+ """
+ weight = forms.ChoiceField(
+ choices=gen_weight_choices(),
+ widget=forms.Select(attrs={'class': 'menu-weight'}),
+ )
+ self = forms.IntegerField(
+ widget=forms.HiddenInput(attrs={'class': 'menu-mlid'}),
+ )
+ parent = forms.IntegerField(
+ widget=forms.HiddenInput(attrs={'class': 'menu-plid'}),
+ )
diff --git a/openslides/agenda/models.py b/openslides/agenda/models.py
index 36e5df50b..532750c33 100644
--- a/openslides/agenda/models.py
+++ b/openslides/agenda/models.py
@@ -13,19 +13,22 @@
try:
import json
except ImportError:
+ # for python 2.5 support
import simplejson as json
from django.db import models
from django.core.urlresolvers import reverse
+from django.utils.translation import ugettext as _, ugettext_noop
from mptt.models import MPTTModel, TreeForeignKey
-from config.models import config
+from openslides.config.models import config
-from projector.projector import SlideMixin
-from projector.api import register_slidemodel, get_slide_from_sid
+from openslides.projector.projector import SlideMixin
+from openslides.projector.api import (register_slidemodel, get_slide_from_sid,
+ register_slidefunc, split_sid)
-from utils.translation_ext import ugettext as _
+from openslides.agenda.slides import agenda_show
class Item(MPTTModel, SlideMixin):
@@ -36,47 +39,56 @@ class Item(MPTTModel, SlideMixin):
"""
prefix = 'item'
- title = models.CharField(null=True, max_length=256, verbose_name=_("Title"))
+ title = models.CharField(null=True, max_length=255, verbose_name=_("Title"))
text = models.TextField(null=True, blank=True, verbose_name=_("Text"))
comment = models.TextField(null=True, blank=True, verbose_name=_("Comment"))
closed = models.BooleanField(default=False, verbose_name=_("Closed"))
weight = models.IntegerField(default=0, verbose_name=_("Weight"))
- parent = TreeForeignKey('self', null=True, blank=True, related_name='children')
- releated_sid = models.CharField(null=True, blank=True, max_length=64)
+ parent = TreeForeignKey('self', null=True, blank=True,
+ related_name='children')
+ related_sid = models.CharField(null=True, blank=True, max_length=63)
- def get_releated_slide(self):
- return get_slide_from_sid(self.releated_sid, True)
-
- def get_releated_type(self):
- return self.get_releated_slide().prefix
-
- def print_releated_type(self):
+ def get_related_slide(self):
"""
- Print the type of the releated item.
+ return the object, of which the item points.
+ """
+ return get_slide_from_sid(self.related_sid, True)
+
+ def get_related_type(self):
+ """
+ return the type of the releated slide.
+ """
+ return self.get_related_slide().prefix
+
+ def print_related_type(self):
+ """
+ Print the type of the related item.
For use in Template
- ??Why does {% trans item.print_releated_type|capfirst %} not work??
+ ??Why does {% trans item.print_related_type|capfirst %} not work??
"""
- return _(self.get_releated_type().capitalize())
+ return _(self.get_related_type().capitalize())
def get_title(self):
- if self.releated_sid is None:
+ """
+ return the title of this item.
+ """
+ if self.related_sid is None:
return self.title
- return self.get_releated_slide().get_agenda_title()
+ return self.get_related_slide().get_agenda_title()
def slide(self):
"""
Return a map with all Data for the Slide
"""
if config['presentation_argument'] == 'summary':
- print 'soweit schonmal'
data = {
'title': self.get_title(),
'items': self.get_children(),
'template': 'projector/AgendaSummary.html',
}
- elif self.releated_sid:
- data = self.get_releated_slide().slide()
+ elif self.related_sid:
+ data = self.get_related_slide().slide()
else:
data = {
'item': self,
@@ -92,16 +104,16 @@ class Item(MPTTModel, SlideMixin):
self.closed = closed
self.save()
- @property
- def active_parent(self):
- """
- Return True if the item has a active parent
- """
- sid = get_active_slide(only_sid=True).split()
- if len(sid) == 2 and sid[0] == self.prefix:
- if self.get_ancestors().filter(pk=sid[0]).exists():
- return True
- return False
+ ## @property
+ ## def active_parent(self):
+ ## """
+ ## Return True if the item has an active parent.
+ ## """
+ ## sid = get_active_slide(only_sid=True).split()
+ ## if len(sid) == 2 and sid[0] == self.prefix:
+ ## if self.get_ancestors().filter(pk=sid[0]).exists():
+ ## return True
+ ## return False
@property
def weight_form(self):
@@ -142,12 +154,12 @@ class Item(MPTTModel, SlideMixin):
* delete
"""
if link == 'view':
- if self.releated_sid:
- return self.get_releated_slide().get_absolute_url(link)
+ if self.related_sid:
+ return self.get_related_slide().get_absolute_url(link)
return reverse('item_view', args=[str(self.id)])
if link == 'edit':
- if self.releated_sid:
- return self.get_releated_slide().get_absolute_url(link)
+ if self.related_sid:
+ return self.get_related_slide().get_absolute_url(link)
return reverse('item_edit', args=[str(self.id)])
if link == 'delete':
return reverse('item_delete', args=[str(self.id)])
@@ -157,8 +169,8 @@ class Item(MPTTModel, SlideMixin):
class Meta:
permissions = (
- ('can_see_agenda', _("Can see agenda", fixstr=True)),
- ('can_manage_agenda', _("Can manage agenda", fixstr=True)),
+ ('can_see_agenda', ugettext_noop("Can see agenda")),
+ ('can_manage_agenda', ugettext_noop("Can manage agenda")),
)
class MPTTMeta:
@@ -166,21 +178,4 @@ class Item(MPTTModel, SlideMixin):
register_slidemodel(Item, control_template='agenda/control_item.html')
-
-# TODO: put this in another file
-
-from projector.api import register_slidefunc
-from agenda.slides import agenda_show
-
register_slidefunc('agenda', agenda_show, weight=-1, name=_('Agenda'))
-
-
-from django.dispatch import receiver
-from openslides.config.signals import default_config_value
-
-
-@receiver(default_config_value, dispatch_uid="agenda_default_config")
-def default_config(sender, key, **kwargs):
- return {
- 'agenda_countdown_time': 60,
- }.get(key)
diff --git a/openslides/agenda/templates/agenda/item_row.html b/openslides/agenda/templates/agenda/item_row.html
index a4bb9b353..caff874e9 100644
--- a/openslides/agenda/templates/agenda/item_row.html
+++ b/openslides/agenda/templates/agenda/item_row.html
@@ -19,8 +19,8 @@
{% endif %}
{{ item }}
- {% if item.releated_sid %}
- ({{ item.print_releated_type }})
+ {% if item.related_sid %}
+ ({{ item.print_related_type }})
{% endif %}
{% if perms.agenda.can_manage_agenda %}
diff --git a/openslides/agenda/templates/agenda/overview.html b/openslides/agenda/templates/agenda/overview.html
index 9dcb48b64..82f4355d5 100644
--- a/openslides/agenda/templates/agenda/overview.html
+++ b/openslides/agenda/templates/agenda/overview.html
@@ -71,20 +71,27 @@
{% trans "Weight" %} |
{% endif %}
- {% if items %}
-
+
|
- {% trans "Agenda" %}
+ {% trans "Agenda" %}
|
{% if perms.agenda.can_manage_agenda %}
|
{% endif %}
{% if perms.agenda.can_manage_agenda or perms.projector.can_manage_projector %}
- |
+
+ {% if perms.projector.can_manage_projector %}
+
+
+
+
+
+ {% endif %}
+ |
{% endif %}
-
+ {% if items %}
{% for item in items %}
diff --git a/openslides/agenda/templates/agenda/widget.html b/openslides/agenda/templates/agenda/widget.html
index 0a243579e..eed65fbb8 100644
--- a/openslides/agenda/templates/agenda/widget.html
+++ b/openslides/agenda/templates/agenda/widget.html
@@ -32,7 +32,7 @@
{% for p in item.get_ancestors %}
{% endfor %}
- {{ item }}{% if item.releated_sid %} ({{ item.print_releated_type }}){% endif %}
+ {{ item }}{% if item.related_sid %} ({{ item.print_related_type }}){% endif %}
{% if not item.is_leaf_node %}
{% endif %}
diff --git a/openslides/agenda/tests.py b/openslides/agenda/tests.py
index 6af7e387d..0906eaef2 100644
--- a/openslides/agenda/tests.py
+++ b/openslides/agenda/tests.py
@@ -47,7 +47,8 @@ class ItemTest(TestCase):
self.assertFalse(self.item4 in self.item1.get_children())
l = Item.objects.all()
- self.assertEqual(str(l), "[, , , ]")
+ self.assertEqual(str(l),
+ "[, , , ]")
def testForms(self):
for item in Item.objects.all():
diff --git a/openslides/agenda/urls.py b/openslides/agenda/urls.py
index 1f5c952ec..3fa098962 100644
--- a/openslides/agenda/urls.py
+++ b/openslides/agenda/urls.py
@@ -10,8 +10,9 @@
:license: GNU GPL, see LICENSE for more details.
"""
-from django.conf.urls.defaults import *
-from agenda.views import Overview, View, SetClosed, ItemUpdate, ItemCreate, ItemDelete, AgendaPDF
+from django.conf.urls.defaults import url, patterns
+from agenda.views import (Overview, View, SetClosed, ItemUpdate, ItemCreate,
+ ItemDelete, AgendaPDF)
urlpatterns = patterns('',
url(r'^$',
diff --git a/openslides/agenda/views.py b/openslides/agenda/views.py
index 10102d11f..c690209c0 100644
--- a/openslides/agenda/views.py
+++ b/openslides/agenda/views.py
@@ -11,28 +11,33 @@
"""
from reportlab.platypus import Paragraph
-from django.db.models import Model
+from django.core.context_processors import csrf
from django.core.urlresolvers import reverse
from django.contrib import messages
+from django.db import transaction
+from django.db.models import Model
from django.utils.translation import ugettext as _
-from django.core.context_processors import csrf
from django.views.generic.detail import SingleObjectMixin
from openslides.utils.pdf import stylesheet
-from openslides.utils.views import (TemplateView, RedirectView, UpdateView, CreateView,
- DeleteView, PDFView, FormView, DetailView)
+from openslides.utils.views import (TemplateView, RedirectView, UpdateView,
+ CreateView, DeleteView, PDFView, DetailView)
from openslides.utils.template import Tab
+from openslides.utils.utils import html_strong
from openslides.config.models import config
-from openslides.projector.api import get_active_slide, set_active_slide
+from openslides.projector.api import get_active_slide
from openslides.projector.projector import Widget, SLIDE
from openslides.agenda.models import Item
-from openslides.agenda.forms import ItemOrderForm, ItemForm, ConfigForm
+from openslides.agenda.forms import ItemOrderForm, ItemForm
class Overview(TemplateView):
+ """
+ Show all agenda items, and update there range via post.
+ """
permission_required = 'agenda.can_see_agenda'
template_name = 'agenda/overview.html'
@@ -40,14 +45,18 @@ class Overview(TemplateView):
context = super(Overview, self).get_context_data(**kwargs)
context.update({
'items': Item.objects.all(),
- 'overview': get_active_slide(only_sid=True) == 'agenda_show',
+ 'active_sid': get_active_slide(only_sid=True),
})
return context
+ @transaction.commit_manually
def post(self, request, *args, **kwargs):
- #todo: check for permission
context = self.get_context_data(**kwargs)
- #todo: check for any erros in the forms befor saving the data
+ if not request.user.has_perm('agenda.can_manage_agenda'):
+ messages.error(request,
+ _('You are not permitted to manage the agenda.'))
+ return self.render_to_response(context)
+ transaction.commit()
for item in Item.objects.all():
form = ItemOrderForm(request.POST, prefix="i%d" % item.id)
if form.is_valid():
@@ -58,12 +67,21 @@ class Overview(TemplateView):
item.weight = form.cleaned_data['weight']
item.parent = parent
Model.save(item)
-
+ else:
+ transaction.rollback()
+ messages.error(request,
+ _('Errors when reordering of the agenda'))
+ return self.render_to_response(context)
Item.objects.rebuild()
+ # TODO: assure, that it is a valid tree
+ transaction.commit()
return self.render_to_response(context)
class View(DetailView):
+ """
+ Show an agenda item.
+ """
permission_required = 'agenda.can_see_agenda'
template_name = 'agenda/view.html'
model = Item
@@ -72,7 +90,7 @@ class View(DetailView):
class SetClosed(RedirectView, SingleObjectMixin):
"""
- Close or open an Item.
+ Close or open an item.
"""
permission_required = 'agenda.can_manage_agenda'
allow_ajax = True
@@ -100,6 +118,9 @@ class SetClosed(RedirectView, SingleObjectMixin):
class ItemUpdate(UpdateView):
+ """
+ Update an existing item.
+ """
permission_required = 'agenda.can_manage_agenda'
template_name = 'agenda/edit.html'
model = Item
@@ -109,13 +130,18 @@ class ItemUpdate(UpdateView):
apply_url = 'item_edit'
def get_success_url(self):
- messages.success(self.request, _("Item %s was successfully modified.") % self.request.POST['title'])
+ messages.success(self.request,
+ _("Item %s was successfully modified.") \
+ % html_strong(self.request.POST['title']))
if 'apply' in self.request.POST:
return ''
return reverse(super(UpdateView, self).get_success_url())
class ItemCreate(CreateView):
+ """
+ Create a new item.
+ """
permission_required = 'agenda.can_manage_agenda'
template_name = 'agenda/edit.html'
model = Item
@@ -125,7 +151,9 @@ class ItemCreate(CreateView):
apply_url = 'item_edit'
def get_success_url(self):
- messages.success(self.request, _("Item %s was successfully created.") % self.request.POST['title'])
+ messages.success(self.request,
+ _("Item %s was successfully created.") \
+ % html_strong(self.request.POST['title']))
if 'apply' in self.request.POST:
return reverse(self.get_apply_url(), args=[self.object.id])
return reverse(super(CreateView, self).get_success_url())
@@ -133,7 +161,7 @@ class ItemCreate(CreateView):
class ItemDelete(DeleteView):
"""
- Delete an Item.
+ Delete an item.
"""
permission_required = 'agenda.can_manage_agenda'
model = Item
@@ -144,27 +172,69 @@ class ItemDelete(DeleteView):
if 'all' in request.POST:
self.object.delete(with_children=True)
- messages.success(request, _("Item %s and his children were successfully deleted.") % self.object)
+ messages.success(request,
+ _("Item %s and his children were successfully deleted.") \
+ % html_strong(self.object))
else:
self.object.delete(with_children=False)
- messages.success(request, _("Item %s was successfully deleted.") % self.object)
+ messages.success(request,
+ _("Item %s was successfully deleted.") \
+ % html_strong(self.object))
def gen_confirm_form(self, request, message, url, singleitem=False):
if singleitem:
- messages.warning(request, '%s' % (message, url, csrf(request)['csrf_token'], _("Yes"), _("No")))
+ messages.warning(
+ request,
+ """
+ %s
+
+ """
+ % (message, url, csrf(request)['csrf_token'], _("Yes"),
+ _("No"))
+ )
else:
- messages.warning(request, '%s' % (message, url, csrf(request)['csrf_token'], _("Yes"), _("Yes, with all child items."), _("No")))
+ messages.warning(
+ request,
+ """
+ %s
+
+ """
+ % (message, url, csrf(request)['csrf_token'], _("Yes"),
+ _("Yes, with all child items."), _("No"))
+ )
def confirm_form(self, request, object, item=None):
if item is None:
item = object
if item.get_children():
- self.gen_confirm_form(request, _('Do you really want to delete %s?') % item, item.get_absolute_url('delete'), False)
+ self.gen_confirm_form(
+ request,
+ _('Do you really want to delete %s?') % html_strong(item),
+ item.get_absolute_url('delete'),
+ False,
+ )
else:
- self.gen_confirm_form(request, _('Do you really want to delete %s?') % item, item.get_absolute_url('delete'), True)
+ self.gen_confirm_form(
+ request,
+ _('Do you really want to delete %s?') % html_strong(item),
+ item.get_absolute_url('delete'),
+ True,
+ )
class AgendaPDF(PDFView):
+ """
+ Create a full agenda-PDF.
+ """
permission_required = 'agenda.can_see_agenda'
filename = _('Agenda')
document_title = _('Agenda')
@@ -173,39 +243,31 @@ class AgendaPDF(PDFView):
for item in Item.objects.all():
ancestors = item.get_ancestors()
if ancestors:
- space = " " * ancestors.count()
- story.append(Paragraph("%s%s" % (space, item.get_title()), stylesheet['Subitem']))
+ space = " " * 6 * ancestors.count()
+ story.append(Paragraph("%s%s" % (space, item.get_title()),
+ stylesheet['Subitem']))
else:
story.append(Paragraph(item.get_title(), stylesheet['Item']))
-#
-# rene: empty for now so comment it out to keep it from appearing in the settings
-#
-#class Config(FormView):
-# permission_required = 'config.can_manage_config'
-# form_class = ConfigForm
-# template_name = 'agenda/config.html'
-#
-# def get_initial(self):
-# return {}
-#
-# def form_valid(self, form):
-# messages.success(self.request, _('Agenda settings successfully saved.'))
-# return super(Config, self).form_valid(form)
-
-
def register_tab(request):
+ """
+ register the agenda tab.
+ """
selected = True if request.path.startswith('/agenda/') else False
return Tab(
title=_('Agenda'),
url=reverse('item_overview'),
- permission=request.user.has_perm('agenda.can_see_agenda') or request.user.has_perm('agenda.can_manage_agenda'),
+ permission=request.user.has_perm('agenda.can_see_agenda')
+ or request.user.has_perm('agenda.can_manage_agenda'),
selected=selected,
)
def get_widgets(request):
+ """
+ return the agenda widget for the projector-tab.
+ """
return [
Widget(
name='agenda',
diff --git a/openslides/application/models.py b/openslides/application/models.py
index 7f358bd9f..172182f6a 100644
--- a/openslides/application/models.py
+++ b/openslides/application/models.py
@@ -415,7 +415,7 @@ class Application(models.Model, SlideMixin):
'You can not delete it.')
- for item in Item.objects.filter(releated_sid=self.sid):
+ for item in Item.objects.filter(related_sid=self.sid):
item.delete()
super(Application, self).delete()
diff --git a/openslides/application/views.py b/openslides/application/views.py
index e759b329f..b731704c6 100644
--- a/openslides/application/views.py
+++ b/openslides/application/views.py
@@ -683,7 +683,7 @@ class CreateAgendaItem(RedirectView):
def pre_redirect(self, request, *args, **kwargs):
self.application = Application.objects.get(pk=kwargs['application_id'])
- self.item = Item(releated_sid=self.application.sid)
+ self.item = Item(related_sid=self.application.sid)
self.item.save()
def get_redirect_url(self, **kwargs):
diff --git a/openslides/assignment/models.py b/openslides/assignment/models.py
index 03f3ef99f..d9828e273 100644
--- a/openslides/assignment/models.py
+++ b/openslides/assignment/models.py
@@ -112,12 +112,12 @@ class Assignment(models.Model, SlideMixin):
def vote_results(self):
"""
returns a table represented as a list with all candidates from all
- releated polls and their vote results.
+ related polls and their vote results.
"""
vote_results_dict = {}
- # All polls releated to this assigment
+ # All polls related to this assigment
polls = self.poll_set.all()
- # All PollOption-Objects releated to this assignment
+ # All PollOption-Objects related to this assignment
options = []
for poll in polls:
options += poll.get_options()
@@ -130,13 +130,13 @@ class Assignment(models.Model, SlideMixin):
for poll in polls:
try:
polloption = poll.get_options().get(candidate=candidate)
- # candidate is releated to this poll
+ # candidate is related to this poll
votes = {}
for vote in polloption.get_votes():
votes[vote.value] = vote.get_weight()
vote_results_dict[candidate].append(votes)
except AssignmentOption.DoesNotExist:
- # candidate not in releated to this poll
+ # candidate not in related to this poll
vote_results_dict[candidate].append(None)
return vote_results_dict
@@ -145,7 +145,7 @@ class Assignment(models.Model, SlideMixin):
return self.name
def delete(self):
- for item in Item.objects.filter(releated_sid=self.sid):
+ for item in Item.objects.filter(related_sid=self.sid):
item.delete()
super(Assignment, self).delete()
diff --git a/openslides/assignment/views.py b/openslides/assignment/views.py
index bc6ff8a34..f8058c543 100644
--- a/openslides/assignment/views.py
+++ b/openslides/assignment/views.py
@@ -463,7 +463,7 @@ class CreateAgendaItem(RedirectView):
def pre_redirect(self, request, *args, **kwargs):
self.assignment = Assignment.objects.get(pk=kwargs['assignment_id'])
- self.item = Item(releated_sid=self.assignment.sid)
+ self.item = Item(related_sid=self.assignment.sid)
self.item.save()
def get_redirect_url(self, **kwargs):
diff --git a/openslides/static/javascript/utils.js b/openslides/static/javascript/utils.js
index 0057ca1ff..b5bcb2a5a 100644
--- a/openslides/static/javascript/utils.js
+++ b/openslides/static/javascript/utils.js
@@ -31,9 +31,6 @@ $(function () {
$('tr').removeClass('activeline');
link.parent().parent().parent().addClass('activeline');
link.addClass('active');
- },
- error: function () {
- alert("Ajax Error");
}
});
});
diff --git a/openslides/utils/utils.py b/openslides/utils/utils.py
index b0abc20b0..82bc3fb5d 100644
--- a/openslides/utils/utils.py
+++ b/openslides/utils/utils.py
@@ -126,3 +126,7 @@ def encodedict(dict):
for key in dict:
newdict[key] = [unicode(dict[key][0].decode('utf-8'))]
return newdict
+
+
+def html_strong(string):
+ return "%s" % string