diff options
-rw-r--r-- | src/account/migrations/0002_auto_20180109_2002.py (renamed from src/account/migrations/0003_lab.py) | 18 | ||||
-rw-r--r-- | src/account/migrations/0002_userprofile_email_addr.py | 20 | ||||
-rw-r--r-- | src/api/serializers.py | 2 | ||||
-rw-r--r-- | src/booking/forms.py | 44 | ||||
-rw-r--r-- | src/booking/migrations/0002_booking_changeid.py (renamed from src/booking/migrations/0002_auto_20171213_1506.py) | 10 | ||||
-rw-r--r-- | src/booking/migrations/0003_auto_20180108_2024.py | 25 | ||||
-rw-r--r-- | src/booking/models.py | 8 | ||||
-rw-r--r-- | src/booking/urls.py | 1 | ||||
-rw-r--r-- | src/booking/views.py | 74 | ||||
-rw-r--r-- | src/notifier/migrations/0001_initial.py | 1 | ||||
-rw-r--r-- | src/static/js/booking-calendar.js | 15 | ||||
-rw-r--r-- | src/static/js/fullcalendar-options.js | 2 | ||||
-rw-r--r-- | src/templates/booking/booking_calendar.html | 22 | ||||
-rw-r--r-- | src/templates/booking/booking_detail.html | 9 |
14 files changed, 212 insertions, 39 deletions
diff --git a/src/account/migrations/0003_lab.py b/src/account/migrations/0002_auto_20180109_2002.py index c4643c5..5cf8a70 100644 --- a/src/account/migrations/0003_lab.py +++ b/src/account/migrations/0002_auto_20180109_2002.py @@ -1,14 +1,5 @@ -############################################################################## -# Copyright (c) 2016 Sawyer Bergeron 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 -############################################################################## - # -*- coding: utf-8 -*- -# Generated by Django 1.10 on 2018-01-09 15:34 +# Generated by Django 1.10 on 2018-01-09 20:02 from __future__ import unicode_literals from django.conf import settings @@ -20,7 +11,7 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('account', '0002_userprofile_email_addr'), + ('account', '0001_initial'), ] operations = [ @@ -34,4 +25,9 @@ class Migration(migrations.Migration): ('lab_user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), + migrations.AddField( + model_name='userprofile', + name='email_addr', + field=models.CharField(default='email@mail.com', max_length=300), + ), ] diff --git a/src/account/migrations/0002_userprofile_email_addr.py b/src/account/migrations/0002_userprofile_email_addr.py deleted file mode 100644 index bfbed17..0000000 --- a/src/account/migrations/0002_userprofile_email_addr.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10 on 2017-12-14 20:37 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='userprofile', - name='email_addr', - field=models.CharField(default='email@mail.com', max_length=300), - ), - ] diff --git a/src/api/serializers.py b/src/api/serializers.py index c371a92..794e139 100644 --- a/src/api/serializers.py +++ b/src/api/serializers.py @@ -21,7 +21,7 @@ class BookingSerializer(serializers.ModelSerializer): class Meta: model = Booking - fields = ('id', 'resource_id', 'start', 'end', 'opsys_name', 'installer_name', 'scenario_name', 'purpose') + fields = ('id', 'changeid', 'reset', 'resource_id', 'opsys_name', 'start', 'end', 'installer_name', 'scenario_name', 'purpose') class ServerSerializer(serializers.ModelSerializer): diff --git a/src/booking/forms.py b/src/booking/forms.py index 1f09c05..b4acd8f 100644 --- a/src/booking/forms.py +++ b/src/booking/forms.py @@ -11,10 +11,21 @@ import django.forms as forms from booking.models import Installer, Scenario, Opsys - +from datetime import datetime class BookingForm(forms.Form): - fields = ['start', 'end', 'purpose', 'opsys', 'installer', 'scenario'] + fields = ['start', 'end', 'purpose', 'opsys', 'reset', 'installer', 'scenario'] + + start = forms.DateTimeField() + end = forms.DateTimeField() + reset = forms.ChoiceField(choices = ((True, 'Yes'),(False, 'No')), label="Reset System", initial='False', required=False) + purpose = forms.CharField(max_length=300) + opsys = forms.ModelChoiceField(queryset=Opsys.objects.all(), required=False) + installer = forms.ModelChoiceField(queryset=Installer.objects.all(), required=False) + scenario = forms.ModelChoiceField(queryset=Scenario.objects.all(), required=False) + +class BookingEditForm(forms.Form): + fields = ['start', 'end', 'purpose', 'opsys', 'reset', 'installer', 'scenario'] start = forms.DateTimeField() end = forms.DateTimeField() @@ -22,3 +33,32 @@ class BookingForm(forms.Form): opsys = forms.ModelChoiceField(queryset=Opsys.objects.all(), required=False) installer = forms.ModelChoiceField(queryset=Installer.objects.all(), required=False) scenario = forms.ModelChoiceField(queryset=Scenario.objects.all(), required=False) + reset = forms.ChoiceField(choices = ((True, 'Yes'),(False, 'No')), label="Reset System", initial='False', required=True) + + + def __init__(self, *args, **kwargs ): + cloned_kwargs = {} + cloned_kwargs['purpose'] = kwargs.pop('purpose') + cloned_kwargs['start'] = kwargs.pop('start') + cloned_kwargs['end'] = kwargs.pop('end') + if 'installer' in kwargs: + cloned_kwargs['installer'] = kwargs.pop('installer') + if 'scenario' in kwargs: + cloned_kwargs['scenario'] = kwargs.pop('scenario') + super(BookingEditForm, self).__init__( *args, **kwargs) + + self.fields['purpose'].initial = cloned_kwargs['purpose'] + self.fields['start'].initial = cloned_kwargs['start'].strftime('%m/%d/%Y %H:%M') + self.fields['end'].initial = cloned_kwargs['end'].strftime('%m/%d/%Y %H:%M') + try: + self.fields['installer'].initial = cloned_kwargs['installer'].id + except KeyError: + pass + except AttributeError: + pass + try: + self.fields['scenario'].initial = cloned_kwargs['scenario'].id + except KeyError: + pass + except AttributeError: + pass diff --git a/src/booking/migrations/0002_auto_20171213_1506.py b/src/booking/migrations/0002_booking_changeid.py index 3e0a5fa..33af8fd 100644 --- a/src/booking/migrations/0002_auto_20171213_1506.py +++ b/src/booking/migrations/0002_booking_changeid.py @@ -25,4 +25,14 @@ class Migration(migrations.Migration): name='opsys', field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='booking.Opsys'), ), + migrations.AddField( + model_name='booking', + name='changeid', + field=models.TextField(default='no change ID'), + ), + migrations.AlterField( + model_name='booking', + name='changeid', + field=models.TextField(blank=True, default='no change ID', null=True), + ), ] diff --git a/src/booking/migrations/0003_auto_20180108_2024.py b/src/booking/migrations/0003_auto_20180108_2024.py new file mode 100644 index 0000000..93cecc2 --- /dev/null +++ b/src/booking/migrations/0003_auto_20180108_2024.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10 on 2018-01-08 20:24 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('booking', '0002_booking_changeid'), + ] + + operations = [ + migrations.AddField( + model_name='booking', + name='reset', + field=models.BooleanField(default=False), + ), + migrations.AlterField( + model_name='booking', + name='changeid', + field=models.TextField(blank=True, default='initial', null=True), + ), + ]
\ No newline at end of file diff --git a/src/booking/models.py b/src/booking/models.py index 0bf5961..9156484 100644 --- a/src/booking/models.py +++ b/src/booking/models.py @@ -13,6 +13,8 @@ from django.contrib.auth.models import User from django.db import models from jira import JIRA from jira import JIRAError +from django.utils.crypto import get_random_string +import hashlib from dashboard.models import Resource @@ -40,10 +42,12 @@ class Opsys(models.Model): class Booking(models.Model): id = models.AutoField(primary_key=True) + changeid = models.TextField(default='initial', blank=True, null=True) user = models.ForeignKey(User, models.CASCADE) # delete if user is deleted resource = models.ForeignKey(Resource, models.PROTECT) start = models.DateTimeField() end = models.DateTimeField() + reset = models.BooleanField(default=False) jira_issue_id = models.IntegerField(null=True) jira_issue_status = models.CharField(max_length=50) @@ -78,6 +82,10 @@ class Booking(models.Model): conflicting_dates = conflicting_dates.filter(start__lt=self.end) if conflicting_dates.count() > 0: raise ValueError('This booking overlaps with another booking') + if not self.changeid: + self.changeid = self.id + else: + self.changeid = hashlib.md5(self.changeid.encode() + get_random_string(length=32).encode()).hexdigest() return super(Booking, self).save(*args, **kwargs) def __str__(self): diff --git a/src/booking/urls.py b/src/booking/urls.py index 9e01316..403e32f 100644 --- a/src/booking/urls.py +++ b/src/booking/urls.py @@ -29,6 +29,7 @@ from booking.views import * urlpatterns = [ url(r'^(?P<resource_id>[0-9]+)/$', BookingFormView.as_view(), name='create'), + url(r'^(?P<resource_id>[0-9]+)/edit/(?P<booking_id>[0-9]+)/$', BookingEditFormView.as_view(), name='edit'), url(r'^(?P<resource_id>[0-9]+)/bookings_json/$', ResourceBookingsJSON.as_view(), name='bookings_json'), diff --git a/src/booking/views.py b/src/booking/views.py index da2fe11..ab3a04e 100644 --- a/src/booking/views.py +++ b/src/booking/views.py @@ -7,7 +7,6 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## - from django.conf import settings from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin @@ -21,11 +20,10 @@ from django.views.generic import TemplateView from jira import JIRAError from account.jira_util import get_jira -from booking.forms import BookingForm +from booking.forms import BookingForm, BookingEditForm from booking.models import Booking from dashboard.models import Resource - def create_jira_ticket(user, booking): jira = get_jira(user) issue_dict = { @@ -55,6 +53,7 @@ class BookingFormView(FormView): title = 'Booking: ' + self.resource.name context = super(BookingFormView, self).get_context_data(**kwargs) context.update({'title': title, 'resource': self.resource}) + #raise PermissionDenied('check') return context def get_success_url(self): @@ -92,6 +91,75 @@ class BookingFormView(FormView): return super(BookingFormView, self).form_valid(form) +class BookingEditFormView(FormView): + template_name = "booking/booking_calendar.html" + form_class = BookingEditForm + + def is_valid(self): + return True + + def dispatch(self, request, *args, **kwargs): + self.resource = get_object_or_404(Resource, id=self.kwargs['resource_id']) + self.original_booking = get_object_or_404(Booking, id=self.kwargs['booking_id']) + return super(BookingEditFormView, self).dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + title = 'Editing Booking on: ' + self.resource.name + context = super(BookingEditFormView, self).get_context_data(**kwargs) + context.update({'title': title, 'resource': self.resource}) + return context + + def get_form_kwargs(self): + kwargs = super(BookingEditFormView, self).get_form_kwargs() + kwargs['purpose'] = self.original_booking.purpose + kwargs['start'] = self.original_booking.start + kwargs['end'] = self.original_booking.end + try: + kwargs['installer'] = self.original_booking.installer + except AttributeError: + pass + try: + kwargs['scenario'] = self.original_booking.scenario + except AttributeError: + pass + return kwargs + + def get_success_url(self): + return reverse('booking:create', args=(self.resource.id,)) + + def form_valid(self, form): + + if not self.request.user.is_authenticated: + messages.add_message(self.request, messages.ERROR, + 'You need to be logged in to book a Pod.') + return super(BookingEditFormView, self).form_invalid(form) + + if not self.request.user == self.original_booking.user: + messages.add_message(self.request, messages.ERROR, + 'You are not the owner of this booking.') + return super(BookingEditFormView, self).form_invalid(form) + + #Do Conflict Checks + if self.original_booking.start != form.cleaned_data['start']: + if timezone.now() > form.cleaned_data['start']: + messages.add_message(self.request, messages.ERROR, + 'Cannot change start date after it has occurred.') + return super(BookingEditFormView, self).form_invalid(form) + self.original_booking.start = form.cleaned_data['start'] + self.original_booking.end = form.cleaned_data['end'] + self.original_booking.purpose = form.cleaned_data['purpose'] + self.original_booking.installer = form.cleaned_data['installer'] + self.original_booking.scenario = form.cleaned_data['scenario'] + self.original_booking.reset = form.cleaned_data['reset'] + try: + self.original_booking.save() + except ValueError as err: + messages.add_message(self.request, messages.ERROR, err) + return super(BookingEditFormView, self).form_invalid(form) + + user = self.request.user + return super(BookingEditFormView, self).form_valid(form) + class BookingView(TemplateView): template_name = "booking/booking_detail.html" diff --git a/src/notifier/migrations/0001_initial.py b/src/notifier/migrations/0001_initial.py index 78d2bad..cac4d04 100644 --- a/src/notifier/migrations/0001_initial.py +++ b/src/notifier/migrations/0001_initial.py @@ -12,7 +12,6 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('account', '0002_userprofile_email_addr'), ('dashboard', '0002_auto_20170505_0815'), ] diff --git a/src/static/js/booking-calendar.js b/src/static/js/booking-calendar.js index f634293..303a6b2 100644 --- a/src/static/js/booking-calendar.js +++ b/src/static/js/booking-calendar.js @@ -51,8 +51,23 @@ function loadEvents(url) { } $(document).ready(function () { + createEditViewSwitch(); $('#calendar').fullCalendar(calendarOptions); loadEvents(bookings_url); $('#starttimepicker').datetimepicker(timepickerOptions); $('#endtimepicker').datetimepicker(timepickerOptions); + $('#starttimeeditpicker').datetimepicker(timepickerOptions); + $('#endtimeeditpicker').datetimepicker(timepickerOptions); }); + +function createEditViewSwitch() { + var url = window.location.href; + var isEdit = url.substr(url.lastIndexOf('/')); + + if ( url.indexOf('edit') !== -1 ) { + document.getElementById('booking_form_div').style.display = 'none'; + calendarOptions.selectable = false; + } else { + document.getElementById('booking_edit_form_div').style.display = 'none'; + } +} diff --git a/src/static/js/fullcalendar-options.js b/src/static/js/fullcalendar-options.js index 22a1b95..a29103a 100644 --- a/src/static/js/fullcalendar-options.js +++ b/src/static/js/fullcalendar-options.js @@ -98,4 +98,4 @@ var calendarOptions = { eventResize: function (event) { sendEventToForm(event); } -};
\ No newline at end of file +}; diff --git a/src/templates/booking/booking_calendar.html b/src/templates/booking/booking_calendar.html index 16f0a4a..52193d5 100644 --- a/src/templates/booking/booking_calendar.html +++ b/src/templates/booking/booking_calendar.html @@ -56,6 +56,28 @@ {% endbuttons %} </form> </div> + <div id="booking_edit_form_div"> + {% bootstrap_form_errors form type='non_fields' %} + <form method="post" action="" class="form" id="bookingeditform"> + {% csrf_token %} + + <div class='input-group' id='starttimeeditpicker'> + {% bootstrap_field form.start addon_after='<span class="glyphicon glyphicon-calendar"></span>' %} + </div> + <div class='input-group' id='endtimeeditpicker'> + {% 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 %} + {% bootstrap_field form.reset %} + {% buttons %} + <button type="submit" class="btn btn btn-success"> + Confirm Edit + </button> + {% endbuttons %} + </form> + </div> {% else %} <p>Please <a href="{% url 'account:login' %}"> diff --git a/src/templates/booking/booking_detail.html b/src/templates/booking/booking_detail.html index cb937d3..dd0bf03 100644 --- a/src/templates/booking/booking_detail.html +++ b/src/templates/booking/booking_detail.html @@ -27,3 +27,12 @@ <p> <b>Scenario: </b> {{ booking.scenario }} </p> +{% if user.is_authenticated %} +{% if user.get_username == booking.user.username %} +<p> + <a href="{% url 'booking:edit' booking_id=booking.id resource_id=booking.resource.id %}" class="btn btn btn-success"> + Edit Booking + </a> +</p> +{% endif %} +{% endif %} |