Abstract Out Inline CSS for Account Views
[pharos-tools.git] / dashboard / src / workflow / booking_workflow.py
1 ##############################################################################
2 # Copyright (c) 2018 Sawyer Bergeron, Parker Berberian, 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.contrib import messages
11 from django.shortcuts import render
12 from django.contrib.auth.models import User
13 from django.utils import timezone
14
15 import json
16 from datetime import timedelta
17
18 from booking.models import Booking
19 from workflow.models import WorkflowStep
20 from workflow.forms import ResourceSelectorForm, SWConfigSelectorForm, BookingMetaForm
21 from resource_inventory.models import GenericResourceBundle, ResourceBundle, ConfigBundle
22
23
24 class Resource_Select(WorkflowStep):
25     template = 'booking/steps/resource_select.html'
26     title = "Select Resource"
27     description = "Select a resource template to use for your deployment"
28     short_title = "pod select"
29
30     def __init__(self, *args, **kwargs):
31         super(Resource_Select, self).__init__(*args, **kwargs)
32         self.repo_key = self.repo.SELECTED_GRESOURCE_BUNDLE
33         self.repo_check_key = False
34         self.confirm_key = "booking"
35
36     def get_default_entry(self):
37         return None
38
39     def get_context(self):
40         context = super(Resource_Select, self).get_context()
41         default = []
42         chosen_bundle = None
43         default_bundle = self.get_default_entry()
44         if default_bundle:
45             context['disabled'] = True
46             chosen_bundle = default_bundle
47             if chosen_bundle.id:
48                 default.append(chosen_bundle.id)
49             else:
50                 default.append("repo bundle")
51         else:
52             chosen_bundle = self.repo_get(self.repo_key, False)
53             if chosen_bundle:
54                 if chosen_bundle.id:
55                     default.append(chosen_bundle.id)
56                 else:
57                     default.append("repo bundle")
58
59         bundle = default_bundle
60         if not bundle:
61             bundle = chosen_bundle
62         edit = self.repo_get(self.repo.EDIT, False)
63         user = self.repo_get(self.repo.SESSION_USER)
64         context['form'] = ResourceSelectorForm(
65             data={"user": user},
66             chosen_resource=default,
67             bundle=bundle,
68             edit=edit
69         )
70         return context
71
72     def post_render(self, request):
73         form = ResourceSelectorForm(request.POST)
74         context = self.get_context()
75         if form.is_valid():
76             data = form.cleaned_data['generic_resource_bundle']
77             data = data[2:-2]
78             if not data:
79                 self.metastep.set_invalid("Please select a valid bundle")
80                 return render(request, self.template, context)
81             selected_bundle = json.loads(data)
82             selected_id = selected_bundle[0]['id']
83             gresource_bundle = None
84             try:
85                 selected_id = int(selected_id)
86                 gresource_bundle = GenericResourceBundle.objects.get(id=selected_id)
87             except ValueError:
88                 # we want the bundle in the repo
89                 gresource_bundle = self.repo_get(
90                     self.repo.GRESOURCE_BUNDLE_MODELS,
91                     {}
92                 ).get("bundle", GenericResourceBundle())
93             self.repo_put(
94                 self.repo_key,
95                 gresource_bundle
96             )
97             confirm = self.repo_get(self.repo.CONFIRMATION)
98             if self.confirm_key not in confirm:
99                 confirm[self.confirm_key] = {}
100             confirm[self.confirm_key]["resource name"] = gresource_bundle.name
101             self.repo_put(self.repo.CONFIRMATION, confirm)
102             messages.add_message(request, messages.SUCCESS, 'Form Validated Successfully', fail_silently=True)
103             self.metastep.set_valid("Step Completed")
104             return render(request, self.template, context)
105         else:
106             messages.add_message(request, messages.ERROR, "Form Didn't Validate", fail_silently=True)
107             self.metastep.set_invalid("Please complete the fields highlighted in red to continue")
108             return render(request, self.template, context)
109
110
111 class Booking_Resource_Select(Resource_Select):
112
113     def __init__(self, *args, **kwargs):
114         super(Booking_Resource_Select, self).__init__(*args, **kwargs)
115         self.repo_key = self.repo.BOOKING_SELECTED_GRB
116         self.confirm_key = "booking"
117
118     def get_default_entry(self):
119         default = self.repo_get(self.repo.GRESOURCE_BUNDLE_MODELS, {}).get("bundle")
120         mine = self.repo_get(self.repo_key)
121         if mine:
122             return None
123         try:
124             config_bundle = self.repo_get(self.repo.BOOKING_MODELS)['booking'].config_bundle
125             if default:
126                 return default  # select created grb, even if preselected config bundle
127             return config_bundle.bundle
128         except:
129             pass
130         return default
131
132     def get_context(self):
133         context = super(Booking_Resource_Select, self).get_context()
134         return context
135
136     def post_render(self, request):
137         response = super(Booking_Resource_Select, self).post_render(request)
138         models = self.repo_get(self.repo.BOOKING_MODELS, {})
139         if "booking" not in models:
140             models['booking'] = Booking()
141         booking = models['booking']
142         resource = self.repo_get(self.repo_key, False)
143         if resource:
144             try:
145                 booking.resource.template = resource
146             except:
147                 booking.resource = ResourceBundle(template=resource)
148         models['booking'] = booking
149         self.repo_put(self.repo.BOOKING_MODELS, models)
150         return response
151
152
153 class SWConfig_Select(WorkflowStep):
154     template = 'booking/steps/swconfig_select.html'
155     title = "Select Software Configuration"
156     description = "Choose the software and related configurations you want to have used for your deployment"
157     short_title = "pod config"
158
159     def post_render(self, request):
160         form = SWConfigSelectorForm(request.POST)
161         if form.is_valid():
162
163             bundle_json = form.cleaned_data['software_bundle']
164             bundle_json = bundle_json[2:-2]  # Stupid django string bug
165             if not bundle_json:
166                 self.metastep.set_invalid("Please select a valid config")
167                 return self.render(request)
168             bundle_json = json.loads(bundle_json)
169             bundle = None
170             try:
171                 id = int(bundle_json[0]['id'])
172                 bundle = ConfigBundle.objects.get(id=id)
173             except ValueError:
174                 bundle = self.repo_get(self.repo.CONFIG_MODELS).get("bundle")
175
176             models = self.repo_get(self.repo.BOOKING_MODELS, {})
177             if "booking" not in models:
178                 models['booking'] = Booking()
179             models['booking'].config_bundle = bundle
180             self.repo_put(self.repo.BOOKING_MODELS, models)
181             confirm = self.repo_get(self.repo.CONFIRMATION)
182             if "booking" not in confirm:
183                 confirm['booking'] = {}
184             confirm['booking']["configuration name"] = bundle.name
185             self.repo_put(self.repo.CONFIRMATION, confirm)
186             self.metastep.set_valid("Step Completed")
187             messages.add_message(request, messages.SUCCESS, 'Form Validated Successfully', fail_silently=True)
188         else:
189             self.metastep.set_invalid("Please select or create a valid config")
190             messages.add_message(request, messages.ERROR, "Form Didn't Validate", fail_silently=True)
191
192         return self.render(request)
193
194     def get_context(self):
195         context = super(SWConfig_Select, self).get_context()
196         default = []
197         bundle = None
198         chosen_bundle = None
199         created_bundle = self.repo_get(self.repo.CONFIG_MODELS, {}).get("bundle", False)
200         booking = self.repo_get(self.repo.BOOKING_MODELS, {}).get("booking", False)
201         try:
202             chosen_bundle = booking.config_bundle
203             default.append(chosen_bundle.id)
204             bundle = chosen_bundle
205         except:
206             if created_bundle:
207                 default.append("repo bundle")
208                 bundle = created_bundle
209                 context['disabled'] = True
210         edit = self.repo_get(self.repo.EDIT, False)
211         grb = self.repo_get(self.repo.BOOKING_SELECTED_GRB)
212         context['form'] = SWConfigSelectorForm(chosen_software=default, bundle=bundle, edit=edit, resource=grb)
213         return context
214
215
216 class Booking_Meta(WorkflowStep):
217     template = 'booking/steps/booking_meta.html'
218     title = "Extra Info"
219     description = "Tell us how long you want your booking, what it is for, and who else should have access to it"
220     short_title = "booking info"
221
222     def get_context(self):
223         context = super(Booking_Meta, self).get_context()
224         initial = {}
225         default = []
226         try:
227             models = self.repo_get(self.repo.BOOKING_MODELS, {})
228             booking = models.get("booking")
229             if booking:
230                 initial['purpose'] = booking.purpose
231                 initial['project'] = booking.project
232                 initial['length'] = (booking.end - booking.start).days
233             info = self.repo_get(self.repo.BOOKING_INFO_FILE, False)
234             if info:
235                 initial['info_file'] = info
236             users = models.get("collaborators", [])
237             for user in users:
238                 default.append(user.id)
239         except Exception:
240             pass
241
242         default_user = self.repo_get(self.repo.SESSION_USER)
243         if default_user is None:
244             # TODO: error
245             default_user = "you"
246         else:
247             default_user = default_user.username
248
249         context['form'] = BookingMetaForm(initial=initial, chosen_users=default, default_user=default_user)
250         return context
251
252     def post_render(self, request):
253         form = BookingMetaForm(data=request.POST)
254         context = self.get_context()
255
256         forms = self.repo_get(self.repo.BOOKING_FORMS, {})
257
258         forms["meta_form"] = form
259         self.repo_put(self.repo.BOOKING_FORMS, forms)
260
261         if form.is_valid():
262             models = self.repo_get(self.repo.BOOKING_MODELS, {})
263             if "booking" not in models:
264                 models['booking'] = Booking()
265             models['collaborators'] = []
266             confirm = self.repo_get(self.repo.CONFIRMATION)
267             if "booking" not in confirm:
268                 confirm['booking'] = {}
269
270             models['booking'].start = timezone.now()
271             models['booking'].end = timezone.now() + timedelta(days=int(form.cleaned_data['length']))
272             models['booking'].purpose = form.cleaned_data['purpose']
273             models['booking'].project = form.cleaned_data['project']
274             for key in ['length', 'project', 'purpose']:
275                 confirm['booking'][key] = form.cleaned_data[key]
276
277             user_data = form.cleaned_data['users']
278             confirm['booking']['collaborators'] = []
279             user_data = user_data[2:-2]  # fixes malformed string from querydict
280             if user_data:
281                 form_users = json.loads(user_data)
282                 for user_json in form_users:
283                     user = User.objects.get(pk=user_json['id'])
284                     models['collaborators'].append(user)
285                     confirm['booking']['collaborators'].append(user.username)
286
287             info_file = form.cleaned_data.get("info_file", False)
288             if info_file:
289                 self.repo_put(self.repo.BOOKING_INFO_FILE, info_file)
290
291             self.repo_put(self.repo.BOOKING_MODELS, models)
292             self.repo_put(self.repo.CONFIRMATION, confirm)
293             messages.add_message(request, messages.SUCCESS, 'Form Validated', fail_silently=True)
294             self.metastep.set_valid("Step Completed")
295         else:
296             messages.add_message(request, messages.ERROR, "Form didn't validate", fail_silently=True)
297             self.metastep.set_invalid("Please complete the fields highlighted in red to continue")
298             context['form'] = form  # TODO: store this form
299         return render(request, self.template, context)