Add ability to add, edit and delete layer notes

This allows adding an important notice to a layer e.g. "this layer is
deprecated, please use layer xyz instead". Only one layer note can be
added through the interface although the data structures allow multiple,
so notes may be added programmatically without disturbing user-added
ones.

With this change we also add a get_absolute_url() function to the
LayerItem model and change the calls to reverse() for layers to use it.

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
This commit is contained in:
Paul Eggleton 2013-02-27 19:11:58 +00:00
parent e6d7b215a6
commit 26ab9dbb28
8 changed files with 152 additions and 8 deletions

1
TODO
View File

@ -14,7 +14,6 @@ TODO:
* Captcha * Captcha
Later: Later:
* Allow adding/editing notes
* Usage links in list page? * Usage links in list page?
* Avoid page content changing size depending on whether scrollbar is there or not? * Avoid page content changing size depending on whether scrollbar is there or not?
* Style/extend about page? * Style/extend about page?

View File

@ -0,0 +1,34 @@
{% extends "base.html" %}
{% load i18n %}
{% comment %}
layerindex-web - delete confirmation template
Copyright (C) 2013 Intel Corporation
Licensed under the MIT license, see COPYING.MIT for details
{% endcomment %}
<!--
{% autoescape on %}
{% block title %}OpenEmbedded metadata index - delete {{ object_type }}{% endblock %}
{% endautoescape %}
-->
{% block content %}
{% autoescape on %}
<h2>Delete {{ object_type }}</h2>
<p>Are you sure you want to delete &quot;{{ object }}&quot;?</p>
<form action="" method="post">
{% csrf_token %}
<input type="submit" value="Delete" class='btn btn-warning' />
<a href="{{ return_url }}" class='btn'>Cancel</a>
</form>
{% endautoescape %}
{% endblock %}

View File

@ -33,6 +33,9 @@
<span class="pull-right"> <span class="pull-right">
{% if perms.layeritem.publish_layer or useredit %} {% if perms.layeritem.publish_layer or useredit %}
<a href="{% url edit_layer layeritem.name %}" class="btn">Edit layer</a> <a href="{% url edit_layer layeritem.name %}" class="btn">Edit layer</a>
{% if layeritem.layernote_set.count = 0 %}
<a href="{% url add_layernote layeritem.name %}" class="btn">Add note</a>
{% endif %}
{% endif %} {% endif %}
{% if layeritem.status = "N" and perms.layeritem.publish_layer %} {% if layeritem.status = "N" and perms.layeritem.publish_layer %}
<a href="{% url publish layeritem.name %}" class="btn btn-primary">Publish layer</a> <a href="{% url publish layeritem.name %}" class="btn btn-primary">Publish layer</a>
@ -48,7 +51,13 @@
<div class="row-fluid"> <div class="row-fluid">
{% for note in layeritem.layernote_set.all %} {% for note in layeritem.layernote_set.all %}
<div class="alert"> <div class="alert">
{{ note.text }} <p>{{ note.text }}</p>
{% if perms.layeritem.publish_layer or useredit %}
<p>
<a href="{% url edit_layernote layeritem.name note.pk %}" class="btn">Edit note</a>
<a href="{% url delete_layernote layeritem.name note.pk %}" class='btn'>Delete note</a>
</p>
{% endif %}
</div> </div>
{% endfor %} {% endfor %}
</div> </div>

View File

@ -0,0 +1,42 @@
{% extends "base.html" %}
{% load i18n %}
{% comment %}
layerindex-web - add/edit layer note form page template
Copyright (C) 2013 Intel Corporation
Licensed under the MIT license, see COPYING.MIT for details
{% endcomment %}
<!--
{% block title %}OpenEmbedded metadata index - {% if form.instance.pk %}add layer note{% else %}edit layer note{% endif %}{% endblock %}
-->
{% block content %}
{% autoescape on %}
<h2>Add layer note to {{ form.instance.layer.name }}</h2>
<p>This note will appear at the very top of the layer detail page. This would typically be used for important notices, e.g. &quot;This layer is obsolete, use layer xyz instead&quot;.</p>
<form id="edit_layernote_form" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save" class='btn' />
<a href="{% url layer_item form.instance.layer.name %}" class='btn'>Cancel</a>
</form>
{% endautoescape %}
{% endblock %}
{% block scripts %}
<script>
$(document).ready(function() {
$("#edit_layernote_form input:text, #edit_layernote_form textarea").first().focus();
});
</script>
{% endblock %}

View File

@ -4,7 +4,7 @@
# #
# Licensed under the MIT license, see COPYING.MIT for details # Licensed under the MIT license, see COPYING.MIT for details
from layerindex.models import LayerItem, LayerMaintainer from layerindex.models import LayerItem, LayerMaintainer, LayerNote
from django import forms from django import forms
from django.core.validators import URLValidator, RegexValidator, email_re from django.core.validators import URLValidator, RegexValidator, email_re
from django.forms.models import inlineformset_factory from django.forms.models import inlineformset_factory
@ -110,3 +110,13 @@ class SubmitLayerForm(forms.ModelForm):
val = URLValidator(verify_exists=False) val = URLValidator(verify_exists=False)
val(url) val(url)
return url return url
class EditNoteForm(forms.ModelForm):
class Meta:
model = LayerNote
fields = ('text',)
def clean_text(self):
text = self.cleaned_data['text'].strip()
return text

View File

@ -7,6 +7,7 @@
from django.db import models from django.db import models
from datetime import datetime from datetime import datetime
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
import os.path import os.path
class LayerItem(models.Model): class LayerItem(models.Model):
@ -88,6 +89,9 @@ class LayerItem(models.Model):
return True return True
return False return False
def get_absolute_url(self):
return reverse('layer_item', args=(self.name,));
def __unicode__(self): def __unicode__(self):
return self.name return self.name

View File

@ -7,7 +7,7 @@
from django.conf.urls.defaults import * from django.conf.urls.defaults import *
from django.views.generic import DetailView, ListView from django.views.generic import DetailView, ListView
from layerindex.models import LayerItem, Recipe from layerindex.models import LayerItem, Recipe
from layerindex.views import LayerListView, RecipeSearchView, MachineSearchView, PlainTextListView, LayerDetailView, edit_layer_view from layerindex.views import LayerListView, RecipeSearchView, MachineSearchView, PlainTextListView, LayerDetailView, edit_layer_view, edit_layernote_view, delete_layernote_view
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^$', url(r'^$',
@ -35,6 +35,12 @@ urlpatterns = patterns('',
LayerDetailView.as_view( LayerDetailView.as_view(
template_name='layerindex/detail.html'), template_name='layerindex/detail.html'),
name='layer_item'), name='layer_item'),
url(r'^layer/(?P<slug>[-\w]+)/addnote/$',
edit_layernote_view, {'template_name': 'layerindex/editlayernote.html'}, name="add_layernote"),
url(r'^layer/(?P<slug>[-\w]+)/editnote/(?P<pk>[-\w]+)/$',
edit_layernote_view, {'template_name': 'layerindex/editlayernote.html'}, name="edit_layernote"),
url(r'^layer/(?P<slug>[-\w]+)/deletenote/(?P<pk>[-\w]+)/$',
delete_layernote_view, {'template_name': 'layerindex/deleteconfirm.html'}, name="delete_layernote"),
url(r'^recipe/(?P<pk>[-\w]+)/$', url(r'^recipe/(?P<pk>[-\w]+)/$',
DetailView.as_view( DetailView.as_view(
model=Recipe, model=Recipe,

View File

@ -9,10 +9,10 @@ from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidde
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.template import RequestContext from django.template import RequestContext
from layerindex.models import LayerItem, LayerMaintainer, LayerDependency, Recipe, Machine from layerindex.models import LayerItem, LayerMaintainer, LayerDependency, LayerNote, Recipe, Machine
from datetime import datetime from datetime import datetime
from django.views.generic import DetailView, ListView from django.views.generic import DetailView, ListView
from layerindex.forms import SubmitLayerForm, LayerMaintainerFormSet from layerindex.forms import SubmitLayerForm, LayerMaintainerFormSet, EditNoteForm
from django.db import transaction from django.db import transaction
from django.contrib.auth.models import User, Permission from django.contrib.auth.models import User, Permission
from django.db.models import Q from django.db.models import Q
@ -23,6 +23,46 @@ import simplesearch
import settings import settings
def edit_layernote_view(request, template_name, slug, pk=None):
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
if pk:
# Edit mode
layernote = get_object_or_404(LayerNote, pk=pk)
else:
# Add mode
layernote = LayerNote()
layernote.layer = layeritem
if request.method == 'POST':
form = EditNoteForm(request.POST, instance=layernote)
if form.is_valid():
form.save()
return HttpResponseRedirect(layeritem.get_absolute_url())
else:
form = EditNoteForm(instance=layernote)
return render(request, template_name, {
'form': form,
})
def delete_layernote_view(request, template_name, slug, pk):
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
layernote = get_object_or_404(LayerNote, pk=pk)
if request.method == 'POST':
layernote.delete()
return HttpResponseRedirect(layeritem.get_absolute_url())
else:
return render(request, template_name, {
'object': layernote,
'object_type': layernote._meta.verbose_name,
'return_url': layeritem.get_absolute_url()
})
def edit_layer_view(request, template_name, slug=None): def edit_layer_view(request, template_name, slug=None):
useredit = False useredit = False
if slug: if slug:
@ -68,7 +108,7 @@ def edit_layer_view(request, template_name, slug=None):
d = Context({ d = Context({
'user_name': user.get_full_name(), 'user_name': user.get_full_name(),
'layer_name': layeritem.name, 'layer_name': layeritem.name,
'layer_url': request.build_absolute_uri(reverse('layer_item', args=(layeritem.name,))), 'layer_url': request.build_absolute_uri(layeritem.get_absolute_url()),
}) })
subject = '%s - %s' % (settings.SUBMIT_EMAIL_SUBJECT, layeritem.name) subject = '%s - %s' % (settings.SUBMIT_EMAIL_SUBJECT, layeritem.name)
from_email = settings.SUBMIT_EMAIL_FROM from_email = settings.SUBMIT_EMAIL_FROM
@ -105,7 +145,7 @@ def _statuschange(request, name, newstatus):
if w.status != newstatus: if w.status != newstatus:
w.change_status(newstatus, request.user.username) w.change_status(newstatus, request.user.username)
w.save() w.save()
return HttpResponseRedirect(reverse('layer_item', args=(name,))) return HttpResponseRedirect(w.get_absolute_url())
class LayerListView(ListView): class LayerListView(ListView):
context_object_name = 'layer_list' context_object_name = 'layer_list'