1 ##############################################################################
2 # Copyright (c) 2016 Max Breitenfeldt and others.
3 # Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others.
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 ##############################################################################
11 from django.contrib import messages
12 from django.shortcuts import get_object_or_404
13 from django.http import JsonResponse, HttpResponse
14 from django.utils import timezone
15 from django.views import View
16 from django.views.generic import TemplateView
17 from django.shortcuts import redirect, render
18 from django.db.models import Q
19 from django.urls import reverse
21 from resource_inventory.models import ResourceBundle, ResourceProfile, Image, ResourceQuery
22 from account.models import Downtime, Lab
23 from booking.models import Booking
24 from booking.stats import StatisticsManager
25 from booking.forms import HostReImageForm
26 from workflow.forms import FormUtils
27 from api.models import JobFactory, GeneratedCloudConfig
28 from workflow.views import login
29 from booking.forms import QuickBookingForm
30 from booking.quick_deployer import create_from_form, drop_filter
34 def quick_create_clear_fields(request):
35 request.session['quick_create_forminfo'] = None
38 def quick_create(request):
39 if not request.user.is_authenticated:
42 if request.method == 'GET':
44 attrs = FormUtils.getLabData(user=request.user)
45 context['form'] = QuickBookingForm(lab_data=attrs, default_user=request.user.username, user=request.user)
46 context['lab_profile_map'] = {}
47 context.update(drop_filter(request.user))
48 context['contact_email'] = Lab.objects.filter(name="UNH_IOL").first().contact_email
49 return render(request, 'booking/quick_deploy.html', context)
51 if request.method == 'POST':
52 attrs = FormUtils.getLabData(user=request.user)
53 form = QuickBookingForm(request.POST, lab_data=attrs, user=request.user)
56 context['lab_profile_map'] = {}
57 context['form'] = form
61 booking = create_from_form(form, request)
62 messages.success(request, "We've processed your request. "
63 "Check Account->My Bookings for the status of your new booking")
64 return redirect(reverse('booking:booking_detail', kwargs={'booking_id': booking.id}))
65 except Exception as e:
66 print("Error occurred while handling quick deployment:")
69 messages.error(request, "Whoops, an error occurred: " + str(e))
70 context.update(drop_filter(request.user))
71 return render(request, 'booking/quick_deploy.html', context)
73 messages.error(request, "Looks like the form didn't validate. Check that you entered everything correctly")
74 context['status'] = 'false'
75 context.update(drop_filter(request.user))
76 return render(request, 'booking/quick_deploy.html', context)
79 class BookingView(TemplateView):
80 template_name = "booking/booking_detail.html"
82 def get_context_data(self, **kwargs):
83 booking = get_object_or_404(Booking, id=self.kwargs['booking_id'])
84 title = 'Booking Details'
85 contact = Lab.objects.filter(name="UNH_IOL").first().contact_email
86 downtime = Downtime.objects.filter(lab=booking.lab, start__lt=timezone.now, end__gt=timezone.now()).first()
87 context = super(BookingView, self).get_context_data(**kwargs)
92 'contact_email': contact
97 class BookingDeleteView(TemplateView):
98 template_name = "booking/booking_delete.html"
100 def get_context_data(self, **kwargs):
101 booking = get_object_or_404(Booking, id=self.kwargs['booking_id'])
102 title = 'Delete Booking'
103 context = super(BookingDeleteView, self).get_context_data(**kwargs)
104 context.update({'title': title, 'booking': booking})
108 def bookingDelete(request, booking_id):
109 booking = get_object_or_404(Booking, id=booking_id)
111 messages.add_message(request, messages.SUCCESS, 'Booking deleted')
112 return redirect('../../../../')
115 class BookingListView(TemplateView):
116 template_name = "booking/booking_list.html"
118 def get_context_data(self, **kwargs):
119 bookings = Booking.objects.filter(end__gte=timezone.now())
120 title = 'Search Booking'
121 context = super(BookingListView, self).get_context_data(**kwargs)
122 context.update({'title': title, 'bookings': bookings})
126 class ResourceBookingsJSON(View):
127 def get(self, request, *args, **kwargs):
128 resource = get_object_or_404(ResourceBundle, id=self.kwargs['resource_id'])
129 bookings = resource.booking_set.get_queryset().values(
134 'config_bundle__name'
136 return JsonResponse({'bookings': list(bookings)})
139 def build_image_mapping(lab, user):
141 for profile in ResourceProfile.objects.filter(labs=lab):
142 images = Image.objects.filter(
144 architecture=profile.architecture
146 Q(public=True) | Q(owner=user)
148 mapping[profile.name] = [{"name": image.name, "value": image.id} for image in images]
152 def booking_detail_view(request, booking_id):
154 if request.user.is_authenticated:
157 return render(request, "dashboard/login.html", {'title': 'Authentication Required'})
159 booking = get_object_or_404(Booking, id=booking_id)
160 allowed_users = set(list(booking.collaborators.all()))
161 allowed_users.add(booking.owner)
162 if user not in allowed_users:
163 return render(request, "dashboard/login.html", {'title': 'This page is private'})
166 'title': 'Booking Details',
170 'image_mapping': build_image_mapping(booking.lab, user),
171 'posix_username': GeneratedCloudConfig._normalize_username(None, user.username)
176 "booking/booking_detail.html",
181 def booking_modify_image(request, booking_id):
182 form = HostReImageForm(request.POST)
184 booking = Booking.objects.get(id=booking_id)
185 if request.user != booking.owner:
186 return HttpResponse("unauthorized")
187 if timezone.now() > booking.end:
188 return HttpResponse("unauthorized")
189 new_image = Image.objects.get(id=form.cleaned_data['image_id'])
190 host = ResourceQuery.get(id=form.cleaned_data['host_id'])
191 host.config.image = new_image
193 JobFactory.reimageHost(new_image, booking, host)
194 return HttpResponse(new_image.name)
195 return HttpResponse("error")
198 def booking_stats_view(request):
201 "booking/stats.html",
202 context={"data": StatisticsManager.getContinuousBookingTimeSeries(), "title": ""}
206 def booking_stats_json(request):
208 span = int(request.GET.get("days", 14))
211 return JsonResponse(StatisticsManager.getContinuousBookingTimeSeries(span), safe=False)