From 844c5d65457ac31a69fb29f72e87cebe8b30c071 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Mon, 29 Sep 2014 21:52:29 +0200 Subject: [PATCH] Categories management --- src/tixlbase/models.py | 2 +- src/tixlcontrol/permissions.py | 38 +++++----- src/tixlcontrol/urls.py | 7 +- src/tixlcontrol/views/item.py | 128 ++++++++++++++++++++++++++++++--- 4 files changed, 147 insertions(+), 28 deletions(-) diff --git a/src/tixlbase/models.py b/src/tixlbase/models.py index cc1119dec9..d2c6275f20 100644 --- a/src/tixlbase/models.py +++ b/src/tixlbase/models.py @@ -342,7 +342,7 @@ class ItemCategory(models.Model): verbose_name=_("Category name"), ) position = models.IntegerField( - null=True, blank=True + default=0 ) def __str__(self): diff --git a/src/tixlcontrol/permissions.py b/src/tixlcontrol/permissions.py index d584b0e0fd..64d1b0b3b0 100644 --- a/src/tixlcontrol/permissions.py +++ b/src/tixlcontrol/permissions.py @@ -4,23 +4,25 @@ from django.utils.translation import ugettext as _ from tixlbase.models import EventPermission -def event_permission_required(function, permission): - def wrapper(request, *args, **kw): - if not request.user.is_authenticated(): - return HttpResponseForbidden() - perm = EventPermission.objects.get( - event=request.event, - user=request.user - ) - allowed = False - try: - allowed = getattr(perm, permission) - except AttributeError: - pass - if allowed: - return function(request, *args, **kw) - return HttpResponseForbidden(_('You do not have permission to view this content.')) - return wrapper +def event_permission_required(permission): + def decorator(function): + def wrapper(request, *args, **kw): + if not request.user.is_authenticated(): + return HttpResponseForbidden() + perm = EventPermission.objects.get( + event=request.event, + user=request.user + ) + allowed = False + try: + allowed = getattr(perm, permission) + except AttributeError: + pass + if allowed: + return function(request, *args, **kw) + return HttpResponseForbidden(_('You do not have permission to view this content.')) + return wrapper + return decorator class EventPermissionRequiredMixin: @@ -29,4 +31,4 @@ class EventPermissionRequiredMixin: @classmethod def as_view(cls, **initkwargs): view = super(EventPermissionRequiredMixin, cls).as_view(**initkwargs) - return event_permission_required(view, cls.permission) + return event_permission_required(cls.permission)(view) diff --git a/src/tixlcontrol/urls.py b/src/tixlcontrol/urls.py index c3b048447f..d029c79ff8 100644 --- a/src/tixlcontrol/urls.py +++ b/src/tixlcontrol/urls.py @@ -22,7 +22,12 @@ urlpatterns += patterns( url(r'^items$', item.ItemList.as_view(), name='event.items'), url(r'^items/(?P\d+)/$', item.ItemUpdateGeneral.as_view(), name='event.item'), url(r'^items/(?P\d+)/variations$', item.ItemVariations.as_view(), name='event.item.variations'), - url(r'^categories$', item.CategoryList.as_view(), name='event.items.categories'), + url(r'^categories/$', item.CategoryList.as_view(), name='event.items.categories'), + url(r'^category/(?P\d+)/delete$', item.CategoryDelete.as_view(), name='event.items.categories.delete'), + url(r'^category/(?P\d+)/up$', item.category_move_up, name='event.items.categories.up'), + url(r'^category/(?P\d+)/down$', item.category_move_down, name='event.items.categories.down'), + url(r'^category/(?P\d+)/$', item.CategoryUpdate.as_view(), name='event.items.categories.edit'), + url(r'^category/add$', item.CategoryCreate.as_view(), name='event.items.categories.add'), url(r'^properties$', item.PropertyList.as_view(), name='event.items.properties'), ) )) diff --git a/src/tixlcontrol/views/item.py b/src/tixlcontrol/views/item.py index 0d1c920254..75793aed5a 100644 --- a/src/tixlcontrol/views/item.py +++ b/src/tixlcontrol/views/item.py @@ -1,14 +1,17 @@ from itertools import product from django.views.generic import ListView -from django.views.generic.edit import UpdateView +from django.views.generic.edit import CreateView, UpdateView, DeleteView from django.views.generic.base import TemplateView from django.views.generic.detail import SingleObjectMixin from django.core.urlresolvers import resolve, reverse +from django.http import HttpResponseRedirect from django import forms +from django.db.models import Q +from django.shortcuts import redirect from tixlbase.models import Item, ItemCategory, Property, ItemVariation -from tixlcontrol.permissions import EventPermissionRequiredMixin +from tixlcontrol.permissions import EventPermissionRequiredMixin, event_permission_required class ItemList(ListView): @@ -22,15 +25,124 @@ class ItemList(ListView): ) +class CategoryForm(forms.ModelForm): + + class Meta: + model = ItemCategory + localized_fields = '__all__' + fields = [ + 'name' + ] + + +class CategoryDelete(EventPermissionRequiredMixin, DeleteView): + model = ItemCategory + form_class = CategoryForm + template_name = 'tixlcontrol/items/category_delete.html' + permission = 'can_change_items' + context_object_name = 'category' + + def get_object(self, queryset=None): + url = resolve(self.request.path_info) + return self.request.event.categories.get( + id=url.kwargs['category'] + ) + + def delete(self, request, *args, **kwargs): + self.object = self.get_object() + self.object.items.update(category=None) + success_url = self.get_success_url() + self.object.delete() + return HttpResponseRedirect(success_url) + + def get_success_url(self): + return reverse('control:event.items.categories', kwargs={ + 'organizer': self.request.event.organizer.slug, + 'event': self.request.event.slug, + }) + '?deleted=true' + + +class CategoryUpdate(EventPermissionRequiredMixin, UpdateView): + model = ItemCategory + form_class = CategoryForm + template_name = 'tixlcontrol/items/category.html' + permission = 'can_change_items' + context_object_name = 'category' + + def get_object(self, queryset=None): + url = resolve(self.request.path_info) + return self.request.event.categories.get( + id=url.kwargs['category'] + ) + + def get_success_url(self): + return reverse('control:event.items.categories', kwargs={ + 'organizer': self.request.event.organizer.slug, + 'event': self.request.event.slug, + }) + '?updated=true' + + +class CategoryCreate(EventPermissionRequiredMixin, CreateView): + model = ItemCategory + form_class = CategoryForm + template_name = 'tixlcontrol/items/category.html' + permission = 'can_change_items' + context_object_name = 'category' + + def get_success_url(self): + return reverse('control:event.items.categories', kwargs={ + 'organizer': self.request.event.organizer.slug, + 'event': self.request.event.slug, + }) + '?created=true' + + def form_valid(self, form): + form.instance.event = self.request.event + return super().form_valid(form) + + class CategoryList(ListView): model = ItemCategory - context_object_name = 'items' - template_name = 'tixlcontrol/items/index.html' + context_object_name = 'categories' + template_name = 'tixlcontrol/items/categories.html' def get_queryset(self): - return ItemCategory.objects.filter( - event=self.request.event - ) + return self.request.event.categories.all() + + +def category_move(request, organizer, event, category, up=True): + category = request.event.categories.get( + id=category + ) + categories = list(request.event.categories.order_by("position")) + + index = categories.index(category) + if index != 0 and up: + categories[index - 1], categories[index] = categories[index], categories[index - 1] + elif index != len(categories) - 1 and not up: + categories[index + 1], categories[index] = categories[index], categories[index + 1] + + for i, cat in enumerate(categories): + if cat.position != i: + cat.position = i + cat.save() + + +@event_permission_required("can_change_items") +def category_move_up(request, organizer, event, category): + category_move(request, organizer, event, category, up=True) + return redirect(reverse('control:event.items.categories', kwargs={ + 'organizer': request.event.organizer.slug, + 'event': request.event.slug, + }) + '?ordered=true') + + +@event_permission_required("can_change_items") +def category_move_down(request, organizer, event, category): + category_move(request, organizer, event, category, up=False) + return redirect(reverse('control:event.items.categories', kwargs={ + 'organizer': request.event.organizer.slug, + 'event': request.event.slug, + }) + '?ordered=true') class PropertyList(ListView): @@ -165,7 +277,7 @@ class ItemVariations(TemplateView, SingleObjectMixin): # on the x-axis sort = lambda v: v[prop2.pk].pk - for val1 in prop1.values.all().order_by("id"): + for val1 in prop1.values.all(): formrow = [] # We are now inside a grid row. We iterate over all variations # which belong in this row and create forms for them. In order