cleanup the agenda app

This commit is contained in:
Oskar Hahn 2012-07-04 12:50:33 +02:00
parent a72832842b
commit 29d25d30d6
8 changed files with 182 additions and 108 deletions

View File

@ -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'}),
)

View File

@ -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)

View File

@ -71,20 +71,27 @@
<th class="tabledrag-hide">{% trans "Weight" %}</th>
{% endif %}
</tr>
{% if items %}
<tr class="topline {% if overview %}activeline{% endif %}">
<tr class="topline{% if active_sid == 'agenda' %} activeline{% endif %}">
<td></td>
<td>
<b>{% trans "Agenda" %}</b>
<strong>{% trans "Agenda" %}</strong>
</td>
{% if perms.agenda.can_manage_agenda %}
<td></td>
{% endif %}
{% if perms.agenda.can_manage_agenda or perms.projector.can_manage_projector %}
<td></td>
<td>
{% if perms.projector.can_manage_projector %}
<span>
<a class="activate_link{% if active_sid == 'agenda' %} active{% endif %}" href="{% url projector_activate_slide 'agenda' %}" title="{% trans 'Activate item' %}">
<span></span>
</a>
</span>
{% endif %}
</td>
{% endif %}
</tr>
{% if items %}
{% for item in items %}
<tr class="draggable{% cycle ' odd' '' %}
{% if item.active %}activeline{% endif %}">

View File

@ -47,7 +47,8 @@ class ItemTest(TestCase):
self.assertFalse(self.item4 in self.item1.get_children())
l = Item.objects.all()
self.assertEqual(str(l), "[<Item: item1>, <Item: item1A>, <Item: item1Aa>, <Item: item2>]")
self.assertEqual(str(l),
"[<Item: item1>, <Item: item1A>, <Item: item1Aa>, <Item: item2>]")
def testForms(self):
for item in Item.objects.all():

View File

@ -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'^$',

View File

@ -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 <b>%s</b> 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 <b>%s</b> 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 <b>%s</b> 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 <b>%s</b> 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<form action="%s" method="post"><input type="hidden" value="%s" name="csrfmiddlewaretoken"><input type="submit" value="%s" /> <input type="button" value="%s"></form>' % (message, url, csrf(request)['csrf_token'], _("Yes"), _("No")))
messages.warning(
request,
"""
%s
<form action="%s" method="post">
<input type="hidden" value="%s" name="csrfmiddlewaretoken">
<input type="submit" value="%s">
<input type="button" value="%s">
</form>
"""
% (message, url, csrf(request)['csrf_token'], _("Yes"),
_("No"))
)
else:
messages.warning(request, '%s<form action="%s" method="post"><input type="hidden" value="%s" name="csrfmiddlewaretoken"><input type="submit" value="%s" /> <input type="submit" name="all" value="%s" /> <input type="button" value="%s"></form>' % (message, url, csrf(request)['csrf_token'], _("Yes"), _("Yes, with all child items."), _("No")))
messages.warning(
request,
"""
%s
<form action="%s" method="post">
<input type="hidden" value="%s" name="csrfmiddlewaretoken">
<input type="submit" value="%s">
<input type="submit" name="all" value="%s">
<input type="button" value="%s">
</form>
"""
% (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 <b>%s</b>?') % 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 <b>%s</b>?') % 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 = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" * ancestors.count()
story.append(Paragraph("%s%s" % (space, item.get_title()), stylesheet['Subitem']))
space = "&nbsp;" * 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',

View File

@ -31,9 +31,6 @@ $(function () {
$('tr').removeClass('activeline');
link.parent().parent().parent().addClass('activeline');
link.addClass('active');
},
error: function () {
alert("Ajax Error");
}
});
});

View File

@ -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 "<strong>%s</strong>" % string