367a18d1c59f96bf161d4bd67c1ea506ea61e12c
[laas.git] / src / booking / views.py
1 ##############################################################################
2 # Copyright (c) 2016 Max Breitenfeldt and others.
3 # Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others.
4 #
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 ##############################################################################
10
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
20
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
31 import traceback
32
33
34 def quick_create_clear_fields(request):
35     request.session['quick_create_forminfo'] = None
36
37
38 def quick_create(request):
39     if not request.user.is_authenticated:
40         return login(request)
41
42     if request.method == 'GET':
43         context = {}
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)
50
51     if request.method == 'POST':
52         attrs = FormUtils.getLabData(user=request.user)
53         form = QuickBookingForm(request.POST, lab_data=attrs, user=request.user)
54
55         context = {}
56         context['lab_profile_map'] = {}
57         context['form'] = form
58
59         if form.is_valid():
60             try:
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:")
67                 traceback.print_exc()
68                 print(str(e))
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)
72         else:
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)
77
78
79 class BookingView(TemplateView):
80     template_name = "booking/booking_detail.html"
81
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)
88         context.update({
89             'title': title,
90             'booking': booking,
91             'downtime': downtime,
92             'contact_email': contact
93         })
94         return context
95
96
97 class BookingDeleteView(TemplateView):
98     template_name = "booking/booking_delete.html"
99
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})
105         return context
106
107
108 def bookingDelete(request, booking_id):
109     booking = get_object_or_404(Booking, id=booking_id)
110     booking.delete()
111     messages.add_message(request, messages.SUCCESS, 'Booking deleted')
112     return redirect('../../../../')
113
114
115 class BookingListView(TemplateView):
116     template_name = "booking/booking_list.html"
117
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})
123         return context
124
125
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(
130             'id',
131             'start',
132             'end',
133             'purpose',
134             'config_bundle__name'
135         )
136         return JsonResponse({'bookings': list(bookings)})
137
138
139 def build_image_mapping(lab, user):
140     mapping = {}
141     for profile in ResourceProfile.objects.filter(labs=lab):
142         images = Image.objects.filter(
143             from_lab=lab,
144             architecture=profile.architecture
145         ).filter(
146             Q(public=True) | Q(owner=user)
147         )
148         mapping[profile.name] = [{"name": image.name, "value": image.id} for image in images]
149     return mapping
150
151
152 def booking_detail_view(request, booking_id):
153     user = None
154     if request.user.is_authenticated:
155         user = request.user
156     else:
157         return render(request, "dashboard/login.html", {'title': 'Authentication Required'})
158
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'})
164
165     context = {
166         'title': 'Booking Details',
167         'booking': booking,
168         'pdf': booking.pdf,
169         'user_id': user.id,
170         'image_mapping': build_image_mapping(booking.lab, user),
171         'posix_username': GeneratedCloudConfig._normalize_username(None, user.username)
172     }
173
174     return render(
175         request,
176         "booking/booking_detail.html",
177         context
178     )
179
180
181 def booking_modify_image(request, booking_id):
182     form = HostReImageForm(request.POST)
183     if form.is_valid():
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
192         host.config.save()
193         JobFactory.reimageHost(new_image, booking, host)
194         return HttpResponse(new_image.name)
195     return HttpResponse("error")
196
197
198 def booking_stats_view(request):
199     return render(
200         request,
201         "booking/stats.html",
202         context={"data": StatisticsManager.getContinuousBookingTimeSeries(), "title": ""}
203     )
204
205
206 def booking_stats_json(request):
207     try:
208         span = int(request.GET.get("days", 14))
209     except Exception:
210         span = 14
211     return JsonResponse(StatisticsManager.getContinuousBookingTimeSeries(span), safe=False)