Limit User Booking Length and Extensions
[pharos-tools.git] / dashboard / src / booking / views.py
1 ##############################################################################
2 # Copyright (c) 2016 Max Breitenfeldt and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 from django.conf import settings
11 from django.contrib import messages
12 from django.contrib.auth.mixins import LoginRequiredMixin
13 from django.http import JsonResponse
14 from django.shortcuts import get_object_or_404
15 from django.urls import reverse
16 from django.utils import timezone
17 from django.views import View
18 from django.views.generic import FormView
19 from django.views.generic import TemplateView
20 from jira import JIRAError
21 from django.shortcuts import redirect
22
23 from account.jira_util import get_jira
24 from booking.forms import BookingForm, BookingEditForm
25 from booking.models import Booking
26 from dashboard.models import Resource
27
28 def create_jira_ticket(user, booking):
29     jira = get_jira(user)
30     issue_dict = {
31         'project': 'PHAROS',
32         'summary': str(booking.resource) + ': Access Request',
33         'description': booking.purpose,
34         'issuetype': {'name': 'Task'},
35         'components': [{'name': 'POD Access Request'}],
36         'assignee': {'name': booking.resource.owner.username}
37     }
38     issue = jira.create_issue(fields=issue_dict)
39     jira.add_attachment(issue, user.userprofile.pgp_public_key)
40     jira.add_attachment(issue, user.userprofile.ssh_public_key)
41     booking.jira_issue_id = issue.id
42     booking.save()
43
44
45 class BookingFormView(FormView):
46     template_name = "booking/booking_calendar.html"
47     form_class = BookingForm
48
49     def dispatch(self, request, *args, **kwargs):
50         self.resource = get_object_or_404(Resource, id=self.kwargs['resource_id'])
51         return super(BookingFormView, self).dispatch(request, *args, **kwargs)
52
53     def get_context_data(self, **kwargs):
54         title = 'Booking: ' + self.resource.name
55         context = super(BookingFormView, self).get_context_data(**kwargs)
56         context.update({'title': title, 'resource': self.resource})
57         #raise PermissionDenied('check')
58         return context
59
60     def get_success_url(self):
61         return reverse('booking:create', kwargs=self.kwargs)
62
63     def form_valid(self, form):
64         if not self.request.user.is_authenticated:
65             messages.add_message(self.request, messages.ERROR,
66                                  'You need to be logged in to book a Pod.')
67             return super(BookingFormView, self).form_invalid(form)
68
69         if form.cleaned_data['end'] - form.cleaned_data['start'] > timezone.timedelta(days=21):
70             messages.add_message(self.request, messages.ERROR,
71                                  'Bookings can be no more than 3 weeks long.')
72             return super(BookingFormView, self).form_invalid(form)
73
74         user = self.request.user
75         booking = Booking(start=form.cleaned_data['start'],
76                           end=form.cleaned_data['end'],
77                           purpose=form.cleaned_data['purpose'],
78                           opsys=form.cleaned_data['opsys'],
79                           installer=form.cleaned_data['installer'],
80                           scenario=form.cleaned_data['scenario'],
81                           resource=self.resource, user=user)
82         try:
83             booking.save()
84         except ValueError as err:
85             messages.add_message(self.request, messages.ERROR, err)
86             return super(BookingFormView, self).form_invalid(form)
87         try:
88             if settings.CREATE_JIRA_TICKET:
89                 create_jira_ticket(user, booking)
90         except JIRAError:
91             messages.add_message(self.request, messages.ERROR, 'Failed to create Jira Ticket. '
92                                                                'Please check your Jira '
93                                                                'permissions.')
94             booking.delete()
95             return super(BookingFormView, self).form_invalid(form)
96         messages.add_message(self.request, messages.SUCCESS, 'Booking saved')
97         return super(BookingFormView, self).form_valid(form)
98
99
100 class BookingEditFormView(FormView):
101     template_name = "booking/booking_calendar.html"
102     form_class = BookingEditForm
103
104     def is_valid(self):
105         return True
106
107     def dispatch(self, request, *args, **kwargs):
108         self.resource = get_object_or_404(Resource, id=self.kwargs['resource_id'])
109         self.original_booking = get_object_or_404(Booking, id=self.kwargs['booking_id'])
110         return super(BookingEditFormView, self).dispatch(request, *args, **kwargs)
111
112     def get_context_data(self, **kwargs):
113         title = 'Editing Booking on: ' + self.resource.name
114         context = super(BookingEditFormView, self).get_context_data(**kwargs)
115         context.update({'title': title, 'resource': self.resource, 'booking': self.original_booking})
116         return context
117
118     def get_form_kwargs(self):
119         kwargs = super(BookingEditFormView, self).get_form_kwargs()
120         kwargs['purpose'] = self.original_booking.purpose
121         kwargs['start'] = self.original_booking.start
122         kwargs['end'] = self.original_booking.end
123         try:
124             kwargs['installer'] = self.original_booking.installer
125         except AttributeError:
126             pass
127         try:
128             kwargs['scenario'] = self.original_booking.scenario
129         except AttributeError:
130             pass
131         return kwargs
132
133     def get_success_url(self):
134         return reverse('booking:create', args=(self.resource.id,))
135
136     def form_valid(self, form):
137
138         if not self.request.user.is_authenticated:
139             messages.add_message(self.request, messages.ERROR,
140                                  'You need to be logged in to book a Pod.')
141             return super(BookingEditFormView, self).form_invalid(form)
142
143         if not self.request.user == self.original_booking.user:
144             messages.add_message(self.request, messages.ERROR,
145                                  'You are not the owner of this booking.')
146             return super(BookingEditFormView, self).form_invalid(form)
147
148         #Do Conflict Checks
149         if self.original_booking.end != form.cleaned_data['end']:
150             if form.cleaned_data['end'] - self.original_booking.end > timezone.timedelta(days=7):
151                 messages.add_message(self.request, messages.ERROR,
152                                      'Extensions can not be longer than one week.')
153                 return super(BookingEditFormView, self).form_invalid(form)
154             elif self.original_booking.ext_count <= 0:
155                 messages.add_message(self.request, messages.ERROR,
156                                      'Cannot change end date after maximum number of extensions reached.')
157                 return super(BookingEditFormView, self).form_invalid(form)
158
159             else:
160                 self.original_booking.ext_count -= 1
161
162         if self.original_booking.start != form.cleaned_data['start']:
163             if timezone.now() > form.cleaned_data['start']:
164                 messages.add_message(self.request, messages.ERROR,
165                                      'Cannot change start date after it has occurred.')
166                 return super(BookingEditFormView, self).form_invalid(form)
167         self.original_booking.start = form.cleaned_data['start']
168         self.original_booking.end = form.cleaned_data['end']
169         self.original_booking.purpose = form.cleaned_data['purpose']
170         self.original_booking.installer = form.cleaned_data['installer']
171         self.original_booking.scenario = form.cleaned_data['scenario']
172         self.original_booking.reset = form.cleaned_data['reset']
173         try:
174             self.original_booking.save()
175         except ValueError as err:
176             messages.add_message(self.request, messages.ERROR, err)
177             return super(BookingEditFormView, self).form_invalid(form)
178
179         user = self.request.user
180         return super(BookingEditFormView, self).form_valid(form)
181
182 class BookingView(TemplateView):
183     template_name = "booking/booking_detail.html"
184
185
186     def get_context_data(self, **kwargs):
187         booking = get_object_or_404(Booking, id=self.kwargs['booking_id'])
188         title = 'Booking Details'
189         context = super(BookingView, self).get_context_data(**kwargs)
190         context.update({'title': title, 'booking': booking})
191         return context
192
193 class BookingDeleteView(TemplateView):
194     template_name = "booking/booking_delete.html"
195
196     def get_context_data(self, **kwargs):
197         booking = get_object_or_404(Booking, id=self.kwargs['booking_id'])
198         title = 'Delete Booking'
199         context = super(BookingDeleteView, self).get_context_data(**kwargs)
200         context.update({'title': title, 'booking': booking})
201         return context
202
203 def bookingDelete(request, booking_id):
204     booking = get_object_or_404(Booking, id=booking_id)
205     booking.delete()
206     messages.add_message(request, messages.SUCCESS, 'Booking deleted')
207     return redirect('../../../../')
208
209 class BookingListView(TemplateView):
210     template_name = "booking/booking_list.html"
211
212     def get_context_data(self, **kwargs):
213         bookings = Booking.objects.filter(end__gte=timezone.now())
214         title = 'Search Booking'
215         context = super(BookingListView, self).get_context_data(**kwargs)
216         context.update({'title': title, 'bookings': bookings})
217         return context
218
219
220 class ResourceBookingsJSON(View):
221     def get(self, request, *args, **kwargs):
222         resource = get_object_or_404(Resource, id=self.kwargs['resource_id'])
223         bookings = resource.booking_set.get_queryset().values('id', 'start', 'end', 'purpose',
224                                                               'jira_issue_status', 'opsys__name',
225                                                               'installer__name', 'scenario__name')
226         return JsonResponse({'bookings': list(bookings)})