From c40bfedd4a27c1b4cad13d3aafb78fcc960a1dde Mon Sep 17 00:00:00 2001 From: Paul Eggleton Date: Wed, 27 Feb 2013 10:20:24 +0000 Subject: [PATCH] Implement editing of layers Allow users with publish permission to edit any layer, and users with the same email address as one of the maintainers of a layer to edit that layer. Signed-off-by: Paul Eggleton --- TODO | 2 +- layerindex/detail.html | 13 ++- layerindex/forms.py | 10 ++- layerindex/models.py | 7 ++ layerindex/submitlayer.html | 155 +----------------------------------- layerindex/urls.py | 5 +- layerindex/views.py | 90 ++++++++++++++------- 7 files changed, 94 insertions(+), 188 deletions(-) diff --git a/TODO b/TODO index 96f35ee..d5e163f 100644 --- a/TODO +++ b/TODO @@ -15,6 +15,7 @@ TODO: * Show unpublished layers in a different style in the dependency list? Later: +* Allow adding/editing notes * Usage links in list page? * Avoid page content changing size depending on whether scrollbar is there or not? * Style/extend about page? @@ -22,7 +23,6 @@ Later: * Style machine list on detail * Provide a delete function for unpublished layers? * Show count of layers to be reviewed next to review button -* Ability for users to edit existing layers * Something to help with compatibility (although maybe this should just be handled using the existing versioned layer dependencies in layer.conf) * Query backend service? i.e. special URL to query information for external apps/scripts * Tool for finding/comparing duplicate recipes? diff --git a/layerindex/detail.html b/layerindex/detail.html index 0e54d73..b29ae82 100644 --- a/layerindex/detail.html +++ b/layerindex/detail.html @@ -26,10 +26,15 @@
diff --git a/layerindex/forms.py b/layerindex/forms.py index 30280ba..ed4685e 100644 --- a/layerindex/forms.py +++ b/layerindex/forms.py @@ -40,12 +40,20 @@ LayerMaintainerFormSet = inlineformset_factory(LayerItem, LayerMaintainer, form= class SubmitLayerForm(forms.ModelForm): # Additional form fields - deps = forms.ModelMultipleChoiceField(label='Other layers this layer depends upon', queryset=LayerItem.objects.all(), required=False, initial=[l.pk for l in LayerItem.objects.filter(name='openembedded-core')]) + deps = forms.ModelMultipleChoiceField(label='Other layers this layer depends upon', queryset=LayerItem.objects.all(), required=False) class Meta: model = LayerItem fields = ('name', 'layer_type', 'summary', 'description', 'vcs_url', 'vcs_subdir', 'vcs_web_url', 'vcs_web_tree_base_url', 'vcs_web_file_base_url', 'usage_url', 'mailing_list_url') + def __init__(self, *args, **kwargs): + super(self.__class__, self).__init__(*args, **kwargs) + if self.instance.pk: + self.fields['deps'].initial = [d.dependency.pk for d in self.instance.dependencies_set.all()] + else: + self.fields['deps'].initial = [l.pk for l in LayerItem.objects.filter(name='openembedded-core')] + self.was_saved = False + def checked_deps(self): val = [int(v) for v in self['deps'].value()] return val diff --git a/layerindex/models.py b/layerindex/models.py index 2bec315..f5398f3 100644 --- a/layerindex/models.py +++ b/layerindex/models.py @@ -75,6 +75,13 @@ class LayerItem(models.Model): def active_maintainers(self): return self.layermaintainer_set.filter(status='A') + def user_can_edit(self, user): + if user.is_authenticated(): + for maintainer in self.active_maintainers(): + if maintainer.email == user.email: + return True + return False + def __unicode__(self): return self.name diff --git a/layerindex/submitlayer.html b/layerindex/submitlayer.html index 1300161..75a4be5 100644 --- a/layerindex/submitlayer.html +++ b/layerindex/submitlayer.html @@ -1,5 +1,4 @@ -{% extends "base.html" %} -{% load i18n %} +{% extends "layerindex/editlayer.html" %} {% comment %} @@ -20,157 +19,11 @@
  • Submit layer
  • {% endblock %} -{% block content %} -{% autoescape on %} +{% block formtag %}
    -{% csrf_token %} - {% for hidden in form.hidden_fields %} - {{ hidden }} - {% endfor %} +{% endblock %} - {% for field in form.visible_fields %} -
    - {{ field.errors }} - {{ field.label_tag }} - {% if field.name = 'deps' %} -
    - - {% for deplayer in deplistlayers %} - {% if deplayer.id in form.checked_deps %} - - - {% if deplayer.status = 'N' %} - - {% else %} - - {% endif %} - - {% endif %} - {% endfor %} - {% for deplayer in deplistlayers %} - {% if not deplayer.id in form.checked_deps %} - - - {% if deplayer.status = 'N' %} - - {% else %} - - {% endif %} - - {% endif %} - {% endfor %} -
    -
    - {% else %} - {{ field }} - {% endif %} - {{ field.help_text }} -
    - {% endfor %} -

    Maintainers

    - {{ maintainerformset.non_form_errors }} - {{ maintainerformset.management_form }} - {% for maintainerform in maintainerformset %} -

    Maintainer {{forloop.counter}}

    - {% for hidden in maintainerform.hidden_fields %} - {{ hidden }} - {% endfor %} - - {% for field in maintainerform.visible_fields %} -
    - {{ field.errors }} - {{ field.label_tag }} - {{ field }} - {{ field.help_text }} -
    - {% endfor %} - {% endfor %} +{% block submitbuttons %} -
    - -{% endautoescape %} - -{% endblock %} - -{% block scripts %} - {% endblock %} diff --git a/layerindex/urls.py b/layerindex/urls.py index 3648910..fa6d900 100644 --- a/layerindex/urls.py +++ b/layerindex/urls.py @@ -7,14 +7,15 @@ from django.conf.urls.defaults import * from django.views.generic import DetailView, ListView from layerindex.models import LayerItem, Recipe -from layerindex.views import LayerListView, RecipeSearchView, MachineSearchView, PlainTextListView, LayerDetailView +from layerindex.views import LayerListView, RecipeSearchView, MachineSearchView, PlainTextListView, LayerDetailView, edit_layer_view urlpatterns = patterns('', url(r'^$', LayerListView.as_view( template_name='layerindex/index.html'), name='layer_list'), - url(r'^submit/$', 'layerindex.views.submit_layer', name="submit_layer"), + url(r'^submit/$', edit_layer_view, {'template_name': 'layerindex/submitlayer.html'}, name="submit_layer"), + url(r'^edit/(?P[-\w]+)/$', edit_layer_view, {'template_name': 'layerindex/editlayer.html'}, name="edit_layer"), url(r'^submit/thanks$', 'layerindex.views.submit_layer_thanks', name="submit_layer_thanks"), url(r'^recipes/$', RecipeSearchView.as_view( diff --git a/layerindex/views.py b/layerindex/views.py index 5f78842..0a55e0b 100644 --- a/layerindex/views.py +++ b/layerindex/views.py @@ -23,46 +23,70 @@ import simplesearch import settings -def submit_layer(request): - if request.method == 'POST': +def edit_layer_view(request, template_name, slug=None): + useredit = False + if slug: + # Edit mode + layeritem = get_object_or_404(LayerItem, name=slug) + if not (request.user.is_authenticated() and (request.user.has_perm('layerindex.publish_layer') or layeritem.user_can_edit(request.user))): + raise PermissionDenied + else: + # Submit mode layeritem = LayerItem() + + if request.method == 'POST': form = SubmitLayerForm(request.POST, instance=layeritem) maintainerformset = LayerMaintainerFormSet(request.POST, instance=layeritem) if form.is_valid() and maintainerformset.is_valid(): with transaction.commit_on_success(): form.save() maintainerformset.save() - # Save dependencies - for dep in form.cleaned_data['deps']: - deprec = LayerDependency() - deprec.layer = layeritem - deprec.dependency = dep - deprec.save() - # Send email - plaintext = get_template('layerindex/submitemail.txt') - perm = Permission.objects.get(codename='publish_layer') - users = User.objects.filter(Q(groups__permissions=perm) | Q(user_permissions=perm) ).distinct() - for user in users: - d = Context({ - 'user_name': user.get_full_name(), - 'layer_name': layeritem.name, - 'layer_url': request.build_absolute_uri(reverse('layer_item', args=(layeritem.name,))), - }) - subject = '%s - %s' % (settings.SUBMIT_EMAIL_SUBJECT, layeritem.name) - from_email = settings.SUBMIT_EMAIL_FROM - to_email = user.email - text_content = plaintext.render(d) - msg = EmailMessage(subject, text_content, from_email, [to_email]) - msg.send() - return HttpResponseRedirect(reverse('submit_layer_thanks')) + if slug: + new_deps = form.cleaned_data['deps'] + existing_deps = [deprec.dependency for deprec in layeritem.dependencies_set.all()] + for dep in new_deps: + if dep not in existing_deps: + deprec = LayerDependency() + deprec.layer = layeritem + deprec.dependency = dep + deprec.save() + for dep in existing_deps: + if dep not in new_deps: + layeritem.dependencies_set.filter(dependency=dep).delete() + else: + # Save dependencies + for dep in form.cleaned_data['deps']: + deprec = LayerDependency() + deprec.layer = layeritem + deprec.dependency = dep + deprec.save() + # Send email + plaintext = get_template('layerindex/submitemail.txt') + perm = Permission.objects.get(codename='publish_layer') + users = User.objects.filter(Q(groups__permissions=perm) | Q(user_permissions=perm) ).distinct() + for user in users: + d = Context({ + 'user_name': user.get_full_name(), + 'layer_name': layeritem.name, + 'layer_url': request.build_absolute_uri(reverse('layer_item', args=(layeritem.name,))), + }) + subject = '%s - %s' % (settings.SUBMIT_EMAIL_SUBJECT, layeritem.name) + from_email = settings.SUBMIT_EMAIL_FROM + to_email = user.email + text_content = plaintext.render(d) + msg = EmailMessage(subject, text_content, from_email, [to_email]) + msg.send() + return HttpResponseRedirect(reverse('submit_layer_thanks')) + form.was_saved = True else: - form = SubmitLayerForm() - maintainerformset = LayerMaintainerFormSet() + form = SubmitLayerForm(instance=layeritem) + maintainerformset = LayerMaintainerFormSet(instance=layeritem) - return render(request, 'layerindex/submitlayer.html', { + return render(request, template_name, { 'form': form, 'maintainerformset': maintainerformset, - 'deplistlayers': LayerItem.objects.all().order_by('name') + 'deplistlayers': LayerItem.objects.all().order_by('name'), + 'useredit': useredit }) def submit_layer_thanks(request): @@ -98,7 +122,9 @@ class LayerDetailView(DetailView): model = LayerItem slug_field = 'name' + # This is a bit of a mess. Surely there has to be a better way to handle this... def dispatch(self, request, *args, **kwargs): + self.user = request.user res = super(LayerDetailView, self).dispatch(request, *args, **kwargs) l = self.get_object() if l: @@ -107,6 +133,12 @@ class LayerDetailView(DetailView): raise PermissionDenied return res + def get_context_data(self, **kwargs): + context = super(LayerDetailView, self).get_context_data(**kwargs) + layer = context['layeritem'] + context['useredit'] = layer.user_can_edit(self.user) + return context + class RecipeSearchView(ListView): context_object_name = 'recipe_list' paginate_by = 50