From 29d25d30d6cea2ce9b5a2368a7a1912b0aaa3db0 Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Wed, 4 Jul 2012 12:50:33 +0200 Subject: [PATCH] cleanup the agenda app --- openslides/agenda/forms.py | 49 +++--- openslides/agenda/models.py | 69 ++++----- .../agenda/templates/agenda/overview.html | 17 ++- openslides/agenda/tests.py | 3 +- openslides/agenda/urls.py | 5 +- openslides/agenda/views.py | 140 +++++++++++++----- openslides/static/javascript/utils.js | 3 - openslides/utils/utils.py | 4 + 8 files changed, 182 insertions(+), 108 deletions(-) diff --git a/openslides/agenda/forms.py b/openslides/agenda/forms.py index acd07ccaf..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', '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 bcf2f1229..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,18 +39,25 @@ 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') - related_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_related_slide(self): + """ + 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): @@ -60,6 +70,9 @@ class Item(MPTTModel, SlideMixin): return _(self.get_related_type().capitalize()) def get_title(self): + """ + return the title of this item. + """ if self.related_sid is None: return self.title return self.get_related_slide().get_agenda_title() @@ -69,7 +82,6 @@ class Item(MPTTModel, SlideMixin): 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(), @@ -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): @@ -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/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/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/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