1e14b8ea530753e5814ab472cc52aa50a8597f6f
[pharos-tools.git] / dashboard / 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
20 from resource_inventory.models import ResourceBundle, HostProfile, Image, Host
21 from resource_inventory.resource_manager import ResourceManager
22 from account.models import Lab
23 from booking.models import Booking
24 from booking.stats import StatisticsManager
25 from booking.forms import HostReImageForm
26 from api.models import JobFactory
27 from workflow.views import login
28 from booking.forms import QuickBookingForm
29 from booking.quick_deployer import create_from_form, drop_filter
30
31
32 def quick_create_clear_fields(request):
33     request.session['quick_create_forminfo'] = None
34
35
36 def quick_create(request):
37     if not request.user.is_authenticated:
38         return login(request)
39
40     if request.method == 'GET':
41         context = {}
42
43         r_manager = ResourceManager.getInstance()
44         profiles = {}
45         for lab in Lab.objects.all():
46             profiles[str(lab)] = r_manager.getAvailableHostTypes(lab)
47
48         context['lab_profile_map'] = profiles
49
50         context['form'] = QuickBookingForm(initial={}, chosen_users=[], default_user=request.user.username, user=request.user)
51
52         context.update(drop_filter(request.user))
53
54         return render(request, 'booking/quick_deploy.html', context)
55     if request.method == 'POST':
56         form = QuickBookingForm(request.POST, user=request.user)
57         context = {}
58         context['lab_profile_map'] = {}
59         context['form'] = form
60
61         if form.is_valid():
62             try:
63                 create_from_form(form, request)
64             except Exception as e:
65                 messages.error(request, "Whoops, looks like an error occurred. "
66                                         "Let the admins know that you got the following message: " + str(e))
67                 return render(request, 'workflow/exit_redirect.html', context)
68
69             messages.success(request, "We've processed your request. "
70                                       "Check Account->My Bookings for the status of your new booking")
71             return render(request, 'workflow/exit_redirect.html', context)
72         else:
73             messages.error(request, "Looks like the form didn't validate. Check that you entered everything correctly")
74             return render(request, 'booking/quick_deploy.html', context)
75
76
77 class BookingView(TemplateView):
78     template_name = "booking/booking_detail.html"
79
80     def get_context_data(self, **kwargs):
81         booking = get_object_or_404(Booking, id=self.kwargs['booking_id'])
82         title = 'Booking Details'
83         context = super(BookingView, self).get_context_data(**kwargs)
84         context.update({'title': title, 'booking': booking})
85         return context
86
87
88 class BookingDeleteView(TemplateView):
89     template_name = "booking/booking_delete.html"
90
91     def get_context_data(self, **kwargs):
92         booking = get_object_or_404(Booking, id=self.kwargs['booking_id'])
93         title = 'Delete Booking'
94         context = super(BookingDeleteView, self).get_context_data(**kwargs)
95         context.update({'title': title, 'booking': booking})
96         return context
97
98
99 def bookingDelete(request, booking_id):
100     booking = get_object_or_404(Booking, id=booking_id)
101     booking.delete()
102     messages.add_message(request, messages.SUCCESS, 'Booking deleted')
103     return redirect('../../../../')
104
105
106 class BookingListView(TemplateView):
107     template_name = "booking/booking_list.html"
108
109     def get_context_data(self, **kwargs):
110         bookings = Booking.objects.filter(end__gte=timezone.now())
111         title = 'Search Booking'
112         context = super(BookingListView, self).get_context_data(**kwargs)
113         context.update({'title': title, 'bookings': bookings})
114         return context
115
116
117 class ResourceBookingsJSON(View):
118     def get(self, request, *args, **kwargs):
119         resource = get_object_or_404(ResourceBundle, id=self.kwargs['resource_id'])
120         bookings = resource.booking_set.get_queryset().values(
121             'id',
122             'start',
123             'end',
124             'purpose',
125             'jira_issue_status',
126             'config_bundle__name'
127         )
128         return JsonResponse({'bookings': list(bookings)})
129
130
131 def build_image_mapping(lab, user):
132     mapping = {}
133     for profile in HostProfile.objects.filter(labs=lab):
134         images = Image.objects.filter(
135             from_lab=lab,
136             host_type=profile
137         ).filter(
138             Q(public=True) | Q(owner=user)
139         )
140         mapping[profile.name] = [{"name": image.name, "value": image.id} for image in images]
141     return mapping
142
143
144 def booking_detail_view(request, booking_id):
145     user = None
146     if request.user.is_authenticated:
147         user = request.user
148     else:
149         return render(request, "dashboard/login.html", {'title': 'Authentication Required'})
150
151     booking = get_object_or_404(Booking, id=booking_id)
152     allowed_users = set(list(booking.collaborators.all()))
153     allowed_users.add(booking.owner)
154     if user not in allowed_users:
155         return render(request, "dashboard/login.html", {'title': 'This page is private'})
156
157     context = {
158         'title': 'Booking Details',
159         'booking': booking,
160         'pdf': booking.pdf,
161         'user_id': user.id,
162         'image_mapping': build_image_mapping(booking.lab, user)
163     }
164
165     return render(
166         request,
167         "booking/booking_detail.html",
168         context
169     )
170
171
172 def booking_modify_image(request, booking_id):
173     form = HostReImageForm(request.POST)
174     if form.is_valid():
175         booking = Booking.objects.get(id=booking_id)
176         if request.user != booking.owner:
177             return HttpResponse("unauthorized")
178         if timezone.now() > booking.end:
179             return HttpResponse("unauthorized")
180         new_image = Image.objects.get(id=form.cleaned_data['image_id'])
181         host = Host.objects.get(id=form.cleaned_data['host_id'])
182         host.config.image = new_image
183         host.config.save()
184         JobFactory.reimageHost(new_image, booking, host)
185         return HttpResponse(new_image.name)
186     return HttpResponse("error")
187
188
189 def booking_stats_view(request):
190     return render(
191         request,
192         "booking/stats.html",
193         context={"data": StatisticsManager.getContinuousBookingTimeSeries(), "title": "Booking Statistics"}
194     )
195
196
197 def booking_stats_json(request):
198     try:
199         span = int(request.GET.get("days", 14))
200     except Exception:
201         span = 14
202     return JsonResponse(StatisticsManager.getContinuousBookingTimeSeries(span), safe=False)