Add Installer and Scenario fields to bookings 01/22701/2
authormaxbr <maxbr@mi.fu-berlin.de>
Wed, 5 Oct 2016 12:10:56 +0000 (14:10 +0200)
committermaxbr <maxbr@mi.fu-berlin.de>
Wed, 5 Oct 2016 12:20:13 +0000 (14:20 +0200)
JIRA: PHAROS-272

Change-Id: I28f44bfadb1dbe3cb0caca0a8038fba988cf26f9
Signed-off-by: maxbr <maxbr@mi.fu-berlin.de>
12 files changed:
tools/pharos-dashboard/src/booking/admin.py
tools/pharos-dashboard/src/booking/forms.py
tools/pharos-dashboard/src/booking/migrations/0002_auto_20161005_1202.py [new file with mode: 0644]
tools/pharos-dashboard/src/booking/models.py
tools/pharos-dashboard/src/booking/urls.py
tools/pharos-dashboard/src/booking/views.py
tools/pharos-dashboard/src/static/js/booking-calendar.js
tools/pharos-dashboard/src/templates/base.html
tools/pharos-dashboard/src/templates/booking/booking_calendar.html
tools/pharos-dashboard/src/templates/booking/booking_detail.html
tools/pharos-dashboard/src/templates/booking/booking_list.html [new file with mode: 0644]
tools/pharos-dashboard/src/templates/booking/booking_table.html

index 7a7f251..d883be1 100644 (file)
@@ -10,6 +10,8 @@
 
 from django.contrib import admin
 
-from booking.models import Booking
+from booking.models import *
 
-admin.site.register(Booking)
\ No newline at end of file
+admin.site.register(Booking)
+admin.site.register(Installer)
+admin.site.register(Scenario)
\ No newline at end of file
index 02ac887..2dbfacb 100644 (file)
 
 import django.forms as forms
 
+from booking.models import Installer, Scenario
+
 
 class BookingForm(forms.Form):
-    fields = ['start', 'end', 'purpose']
+    fields = ['start', 'end', 'purpose', 'installer', 'scenario']
 
     start = forms.DateTimeField()
     end = forms.DateTimeField()
-    purpose = forms.CharField(max_length=300)
\ No newline at end of file
+    purpose = forms.CharField(max_length=300)
+    installer = forms.ModelChoiceField(queryset=Installer.objects.all(), required=False)
+    scenario = forms.ModelChoiceField(queryset=Scenario.objects.all(), required=False)
\ No newline at end of file
diff --git a/tools/pharos-dashboard/src/booking/migrations/0002_auto_20161005_1202.py b/tools/pharos-dashboard/src/booking/migrations/0002_auto_20161005_1202.py
new file mode 100644 (file)
index 0000000..05684f0
--- /dev/null
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10 on 2016-10-05 12:02
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('booking', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Installer',
+            fields=[
+                ('id', models.AutoField(primary_key=True, serialize=False)),
+                ('name', models.CharField(max_length=30)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='Scenario',
+            fields=[
+                ('id', models.AutoField(primary_key=True, serialize=False)),
+                ('name', models.CharField(max_length=300)),
+            ],
+        ),
+        migrations.AddField(
+            model_name='booking',
+            name='installer',
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='booking.Installer'),
+        ),
+        migrations.AddField(
+            model_name='booking',
+            name='scenario',
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='booking.Scenario'),
+        ),
+    ]
index 200dc83..88ab558 100644 (file)
@@ -16,6 +16,20 @@ from jira import JIRAError
 from dashboard.models import Resource
 from django.conf import settings
 
+class Installer(models.Model):
+    id = models.AutoField(primary_key=True)
+    name = models.CharField(max_length=30)
+
+    def __str__(self):
+        return self.name
+
+class Scenario(models.Model):
+    id = models.AutoField(primary_key=True)
+    name = models.CharField(max_length=300)
+
+    def __str__(self):
+        return self.name
+
 
 class Booking(models.Model):
     id = models.AutoField(primary_key=True)
@@ -26,6 +40,8 @@ class Booking(models.Model):
     jira_issue_id = models.IntegerField(null=True)
     jira_issue_status = models.CharField(max_length=50)
 
+    installer = models.ForeignKey(Installer, models.DO_NOTHING, null=True)
+    scenario = models.ForeignKey(Scenario, models.DO_NOTHING, null=True)
     purpose = models.CharField(max_length=300, blank=False)
 
     class Meta:
@@ -40,27 +56,12 @@ class Booking(models.Model):
         except JIRAError:
             return None
 
-    def authorization_test(self):
-        """
-        Return True if self.user is authorized to make this booking.
-        """
-        user = self.user
-        # Check if User is troubleshooter / admin
-        if user.has_perm('booking.add_booking'):
-            return True
-        # Check if User owns this resource
-        if user == self.resource.owner:
-            return True
-        return False
-
     def save(self, *args, **kwargs):
         """
         Save the booking if self.user is authorized and there is no overlapping booking.
         Raise PermissionError if the user is not authorized
         Raise ValueError if there is an overlapping booking
         """
-        if not self.authorization_test():
-            raise PermissionError('Insufficient permissions to save this booking.')
         if self.start >= self.end:
             raise ValueError('Start date is after end date')
         # conflicts end after booking starts, and start before booking ends
index 5320623..9e01316 100644 (file)
@@ -34,4 +34,6 @@ urlpatterns = [
 
     url(r'^detail/$', BookingView.as_view(), name='detail_prefix'),
     url(r'^detail/(?P<booking_id>[0-9]+)/$', BookingView.as_view(), name='detail'),
+
+    url(r'^list/$', BookingListView.as_view(), name='list')
 ]
index 2fe167a..413573d 100644 (file)
@@ -15,7 +15,6 @@ from django.contrib import messages
 from django.contrib.auth.mixins import LoginRequiredMixin
 from django.http import JsonResponse
 from django.shortcuts import get_object_or_404
-from django.shortcuts import redirect
 from django.urls import reverse
 from django.utils import timezone
 from django.views import View
@@ -65,13 +64,12 @@ class BookingFormView(LoginRequiredMixin, FormView):
 
     def form_valid(self, form):
         user = self.request.user
-        if not user.userprofile.ssh_public_key or not user.userprofile.pgp_public_key:
-            messages.add_message(self.request, messages.INFO,
-                                 'Please upload your private keys before booking')
-            return redirect('account:settings')
-        booking = Booking(start=form.cleaned_data['start'], end=form.cleaned_data['end'],
-                          purpose=form.cleaned_data['purpose'], resource=self.resource,
-                          user=user)
+        booking = Booking(start=form.cleaned_data['start'],
+                          end=form.cleaned_data['end'],
+                          purpose=form.cleaned_data['purpose'],
+                          installer=form.cleaned_data['installer'],
+                          scenario=form.cleaned_data['scenario'],
+                          resource=self.resource, user=user)
         try:
             booking.save()
         except ValueError as err:
@@ -98,10 +96,19 @@ class BookingView(TemplateView):
 
     def get_context_data(self, **kwargs):
         booking = get_object_or_404(Booking, id=self.kwargs['booking_id'])
-        jira_issue = booking.get_jira_issue()
         title = 'Booking Details'
         context = super(BookingView, self).get_context_data(**kwargs)
-        context.update({'title': title, 'booking': booking, 'jira_issue': jira_issue})
+        context.update({'title': title, 'booking': booking})
+        return context
+
+class BookingListView(TemplateView):
+    template_name = "booking/booking_list.html"
+
+    def get_context_data(self, **kwargs):
+        bookings = Booking.objects.filter(end__gte=timezone.now())
+        title = 'Search Booking'
+        context = super(BookingListView, self).get_context_data(**kwargs)
+        context.update({'title': title, 'bookings': bookings})
         return context
 
 
@@ -109,5 +116,6 @@ class ResourceBookingsJSON(View):
     def get(self, request, *args, **kwargs):
         resource = get_object_or_404(Resource, id=self.kwargs['resource_id'])
         bookings = resource.booking_set.get_queryset().values('id', 'start', 'end', 'purpose',
-                                                              'jira_issue_status')
-        return JsonResponse({'bookings': list(bookings)})
\ No newline at end of file
+                                                              'jira_issue_status',
+                                                              'installer__name', 'scenario__name')
+        return JsonResponse({'bookings': list(bookings)})
index 9cb0f32..f634293 100644 (file)
@@ -1,11 +1,11 @@
 /*****************************************************************************
-* Copyright (c) 2016 Max Breitenfeldt and others.
-*
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Apache License, Version 2.0
-* which accompanies this distribution, and is available at
-* http://www.apache.org/licenses/LICENSE-2.0
-*****************************************************************************/
+ * Copyright (c) 2016 Max Breitenfeldt and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *****************************************************************************/
 
 
 function parseCalendarEvents(bookings) {
@@ -14,9 +14,21 @@ function parseCalendarEvents(bookings) {
         // convert ISO 8601 timestring to moment, needed for timezone handling
         start = moment(bookings[i]['start']);
         end = moment(bookings[i]['end']);
+
+        installer = bookings[i]['installer__name'];
+        if (installer === null) {
+            installer = '';
+        }
+
+        scenario = bookings[i]['scenario__name'];
+        if (scenario === null) {
+            scenario = '';
+        }
+        title = bookings[i]['purpose'] + ' ' + installer + ' ' + scenario;
+
         event = {
             id: bookings[i]['id'],
-            title: bookings[i]['purpose'],
+            title: title,
             start: start,
             end: end,
         };
index 5bb5547..2ce22a3 100644 (file)
                                 Slaves</a>
                         </li>
                         <li>
+                            {% if user.is_authenticated %}
                             <a href="{% url 'account:users' %}"><i
-                                    class="fa fa-fw"></i>Users
+                                    class="fa fa-fw"></i>User List
+                            </a>
+                            {% endif %}
+                        </li>
+                        <li>
+                            <a href="{% url 'booking:list' %}"><i
+                                    class="fa fa-fw"></i>Booking List
                             </a>
                         </li>
                         <li>
index de3e3b3..34f425c 100644 (file)
@@ -1,4 +1,4 @@
-{% extends "dashboard/table.html" %}
+{% extends "base.html" %}
 {% load staticfiles %}
 
 {% load bootstrap3 %}
@@ -45,7 +45,8 @@
                             {% bootstrap_field form.end addon_after='<span class="glyphicon glyphicon-calendar"></span>' %}
                         </div>
                         {% bootstrap_field form.purpose %}
-
+                        {% bootstrap_field form.installer %}
+                        {% bootstrap_field form.scenario %}
                         {% buttons %}
                             <button type="submit" class="btn btn btn-success">
                                 Book
@@ -69,7 +70,8 @@
                 <div class="modal-body" id="booking_detail_content">
                 </div>
                 <div class="modal-footer">
-                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Close
+                    </button>
                 </div>
             </div>
 
index d3f4753..4b016b2 100644 (file)
@@ -19,8 +19,8 @@
     <b>Purpose: </b> {{ booking.purpose }}
 </p>
 <p>
-    <b>Jira: </b>
-    <a href="{{ jira_issue | jira_issue_url }}">
-        {{ jira_issue }}
-    </a>
+    <b>Installer: </b> {{ booking.installer }}
+</p>
+<p>
+    <b>Scenario: </b> {{ booking.scenario }}
 </p>
\ No newline at end of file
diff --git a/tools/pharos-dashboard/src/templates/booking/booking_list.html b/tools/pharos-dashboard/src/templates/booking/booking_list.html
new file mode 100644 (file)
index 0000000..f2991e4
--- /dev/null
@@ -0,0 +1,50 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+
+{% block extrahead %}
+    <!-- DataTables CSS -->
+    <link href="{% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.css" %}"
+          rel="stylesheet">
+
+    <!-- DataTables Responsive CSS -->
+    <link href="{% static "bower_components/datatables-responsive/css/dataTables.responsive.css" %}"
+          rel="stylesheet">
+{% endblock extrahead %}
+
+{% block content %}
+    <div class="row">
+        <div class="col-lg-12">
+            <div class="panel panel-default">
+                <div class="panel-body">
+                    <div class="dataTables_wrapper">
+                        <table class="table table-striped table-bordered table-hover" id="table"
+                               cellspacing="0"
+                               width="100%">
+                            {% include "booking/booking_table.html" %}
+                        </table>
+                    </div>
+                    <!-- /.table-responsive -->
+                </div>
+                <!-- /.panel-body -->
+            </div>
+            <!-- /.panel -->
+        </div>
+        <!-- /.col-lg-12 -->
+    </div>
+{% endblock content %}
+
+{% block extrajs %}
+    <!-- DataTables JavaScript -->
+    <link href="{% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.css" %}"
+          rel="stylesheet">
+
+
+    <script src={% static "bower_components/datatables/media/js/jquery.dataTables.min.js" %}></script>
+    <script src={% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.min.js" %}></script>
+
+    <script type="text/javascript">
+        $(document).ready(function () {
+            $('#table').DataTable({});
+        });
+    </script>
+{% endblock extrajs %}
\ No newline at end of file
index 216eaf5..655b013 100644 (file)
@@ -7,7 +7,8 @@
     <th>Purpose</th>
     <th>Start</th>
     <th>End</th>
-    <th>Jira</th>
+    <th>Installer</th>
+    <th>Scenario</th>
 </tr>
 </thead>
 <tbody>
         <td>
             {{ booking.end }}
         </td>
-        <td><a target='_blank'
-               href={{ booking.get_jira_issue | jira_issue_url }}>{{ booking.get_jira_issue }}</a>
+        <td>
+            {{ booking.installer }}
+        </td>
+        <td>
+            {{ booking.scenario }}
         </td>
     </tr>
 {% endfor %}