=== added file 'dashboard_app/forms.py'
@@ -0,0 +1,26 @@
+from django import forms
+from django.contrib.auth.models import Group
+from django.core.exceptions import ValidationError
+from django.utils.translation import ugettext as _
+
+from lava_projects.models import Project
+from dashboard_app.models import TestingEffort
+
+
+class TestingEffortForm(forms.Form):
+
+ name = forms.CharField(
+ label=_(u"Name"),
+ max_length=100)
+
+ description = forms.CharField(
+ required=False,
+ widget=forms.widgets.Textarea(),
+ label=_(u"Description"),
+ help_text=_(u"Description of this testing effort"))
+
+ tags = forms.CharField(
+ required=False,
+ label=_(u"Tags"),
+ max_length=1024,
+ help_text=_(u"Tags, separated by whitespace or commas"))
=== modified file 'dashboard_app/templates/dashboard_app/testing_effort_detail.html'
@@ -14,8 +14,17 @@
{% block sidebar %}
-<h3>{{ effort }}</h3>
-{{ effort.description|markdown }}
+<h3>Administration</h3>
+{% if belongs_to_user %}
+<ul>
+ <li><a href="{% url dashboard_app.views.testing_effort_update effort.pk %}">Update this effort</a>
+</ul>
+{% else %}
+<p>You cannot make any changes to this testing effort. Only the owner of the
+<a href="{{ effort.project.get_absolute_url }}">{{ effort.project }}</a> can do
+this.</p>
+{% endif %}
+
<h3>Tags</h3>
<p class="help_text">The concept of <q>testing efforts</q> is based on using
tags to associate test runs with a common goal or task. This testing effort
@@ -67,6 +76,10 @@
padding: 2pt;
}
</style>
+<h2>About {{ effort.name }}</h2>
+{{ effort.description|markdown }}
+<h2>Tests related to this effort</h2>
+<p>The following tests contain one of the tags associated with this effort</p>
<table class="special">
{% regroup test_run_list|dictsortreversed:"analyzer_assigned_date" by analyzer_assigned_date|date:"Y-m-d" as test_run_cluster_list %}
{% for test_run_cluster in test_run_cluster_list %}
=== added file 'dashboard_app/templates/dashboard_app/testing_effort_form.html'
@@ -0,0 +1,61 @@
+{% extends "dashboard_app/_content_with_sidebar.html" %}
+{% comment %}
+This template is a candidate for lava-server/form.html (generic form template)
+To make it work sensibly we need to move javascript and theme code to widgets
+and start using proper widget media references
+{% endcomment %}
+{% load humanize %}
+{% load markup %}
+{% load i18n %}
+
+
+{% block extrahead %}
+{{ block.super }}
+<script type="text/javascript" src="{{ STATIC_URL }}lava_markitup/jquery.markitup.js"></script>
+<script type="text/javascript" src="{{ STATIC_URL }}lava_markitup/sets/markdown/set.js"></script>
+<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}lava_markitup/skins/simple/style.css"/>
+<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}lava_markitup/sets/markdown/style.css"/>
+{% endblock %}
+
+
+{% block content %}
+<style type="text/css">
+ iframe { border: 1px dotted #333; }
+</style>
+<form method="post" action="">
+ {% block form_header %}
+ {% endblock %}
+ {% csrf_token %}
+ <table class="form_helper">
+ {% for field in form %}
+ {% block form_field %}
+ <tr>
+ <th><label for="{{ field.id_for_label }}">{{ field.label }}</label></th>
+ <td>
+ {% if field.errors %}
+ <div class="ui-state-error">
+ {{ field.errors }}
+ {{ field }}
+ </div>
+ {% else %}
+ {{ field }}
+ {% endif %}
+ <p class='help_text'>{{ field.help_text }}</p>
+ </td>
+ </tr>
+ {% endblock %}
+ {% endfor %}
+ </table>
+ {% block form_footer %}
+ <h2>Continue</h2>
+ <input type="submit" value="Save"/>
+ {% endblock %}
+</form>
+<script type="text/javascript">
+ mySettings.previewParserPath = "{% url lava.markitup.markdown %}";
+ $(document).ready(function() {
+ $("input[type=submit]").button();
+ $("#id_description").markItUp(mySettings);
+ });
+</script>
+{% endblock %}
=== modified file 'dashboard_app/urls.py'
@@ -67,4 +67,6 @@
url(r'^image_status/(?P<rootfs_type>[a-zA-Z0-9_-]+)\+(?P<hwpack_type>[a-zA-Z0-9_-]+)/test-history/(?P<test_id>[^/]+)/$', 'image_test_history'),
url(r'^efforts/$', 'testing_effort_list'),
url(r'^efforts/(?P<pk>[0-9]+)/$', 'testing_effort_detail'),
+ url(r'^efforts/(?P<pk>[0-9]+)/update/$', 'testing_effort_update'),
+ url(r'^efforts/(?P<project_identifier>[a-z0-9-]+)/\+new/$', 'testing_effort_create'),
)
=== modified file 'dashboard_app/views.py'
@@ -20,14 +20,17 @@
Views for the Dashboard application
"""
+import re
import json
+from django.contrib.auth.decorators import login_required
from django.contrib.sites.models import Site
from django.db.models.manager import Manager
from django.db.models.query import QuerySet
-from django.http import Http404, HttpResponse
+from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, redirect, get_object_or_404
-from django.template import RequestContext
+from django.template import RequestContext, loader
+from django.views.generic.create_update import create_object
from django.views.generic.list_detail import object_list, object_detail
from dashboard_app.models import (
@@ -37,12 +40,16 @@
DataReport,
DataView,
ImageHealth,
+ Tag,
Test,
TestResult,
TestRun,
TestingEffort,
)
-from dashboard_app.bread_crumbs import BreadCrumb, BreadCrumbTrail
+from lava_server.bread_crumbs import (
+ BreadCrumb,
+ BreadCrumbTrail,
+)
def _get_queryset(klass):
@@ -594,6 +601,7 @@
return render_to_response(
"dashboard_app/testing_effort_detail.html", {
'effort': effort,
+ 'belongs_to_user': effort.project.is_owned_by(request.user),
'test_run_list': effort.get_test_runs(
).select_related(
'denormalization',
@@ -606,3 +614,92 @@
effort=effort,
pk=pk),
}, RequestContext(request))
+
+
+from lava_projects.models import Project
+from lava_projects.views import project_detail
+from dashboard_app.forms import TestingEffortForm
+
+
+@BreadCrumb(
+ "Start a new test effort",
+ parent=project_detail,
+ needs=["project_identifier"])
+@login_required
+def testing_effort_create(request, project_identifier):
+ project = get_object_or_404(Project, identifier=project_identifier)
+ if request.method == 'POST':
+ form = TestingEffortForm(request.POST)
+ # Check the form
+ if form.is_valid():
+ # And make a project instance
+ effort = TestingEffort.objects.create(
+ name=form.cleaned_data['name'],
+ description=form.cleaned_data['description'],
+ project=project)
+ # Create all the required tags
+ effort.tags = [
+ Tag.objects.get_or_create(name=tag_name)[0]
+ for tag_name in re.split("[, ]+", form.cleaned_data["tags"])
+ if tag_name != ""]
+ return HttpResponseRedirect(effort.get_absolute_url())
+ else:
+ form = TestingEffortForm()
+ # Render to template
+ template_name = "dashboard_app/testing_effort_form.html"
+ t = loader.get_template(template_name)
+ c = RequestContext(request, {
+ 'form': form,
+ 'bread_crumb_trail': BreadCrumbTrail.leading_to(
+ testing_effort_create,
+ project=project,
+ project_identifier=project.identifier)
+ })
+ return HttpResponse(t.render(c))
+
+
+@BreadCrumb(
+ "Update",
+ parent=testing_effort_detail,
+ needs=["pk"])
+@login_required
+def testing_effort_update(request, pk):
+ try:
+ effort = TestingEffort.objects.get(pk=pk)
+ except TestingEffort.DoesNotExist:
+ raise Http404()
+ if not effort.project.is_owned_by(request.user):
+ return HttpReseponse("not allowed")
+ if request.method == 'POST':
+ form = TestingEffortForm(request.POST)
+ # Check the form
+ if form.is_valid():
+ # And update the effort object
+ effort.name=form.cleaned_data['name']
+ effort.description=form.cleaned_data['description']
+ # As well as tags
+ effort.tags = [
+ Tag.objects.get_or_create(name=tag_name)[0]
+ for tag_name in re.split("[, ]+", form.cleaned_data["tags"])
+ if tag_name != ""]
+ # Save the changes
+ effort.save()
+ return HttpResponseRedirect(effort.get_absolute_url())
+ else:
+ form = TestingEffortForm(initial={
+ 'name': effort.name,
+ 'description': effort.description,
+ 'tags': " ".join([tag.name for tag in effort.tags.order_by('name').all()])
+ })
+ # Render to template
+ template_name = "dashboard_app/testing_effort_form.html"
+ t = loader.get_template(template_name)
+ c = RequestContext(request, {
+ 'form': form,
+ 'effort': effort,
+ 'bread_crumb_trail': BreadCrumbTrail.leading_to(
+ testing_effort_update,
+ effort=effort,
+ pk=effort.pk)
+ })
+ return HttpResponse(t.render(c))