aboutsummaryrefslogtreecommitdiffstats
path: root/src/booking
diff options
context:
space:
mode:
Diffstat (limited to 'src/booking')
-rw-r--r--src/booking/forms.py22
-rw-r--r--src/booking/lib.py36
-rw-r--r--src/booking/quick_deployer.py40
-rw-r--r--src/booking/stats.py42
-rw-r--r--src/booking/views.py14
5 files changed, 90 insertions, 64 deletions
diff --git a/src/booking/forms.py b/src/booking/forms.py
index de427ab..df88cc6 100644
--- a/src/booking/forms.py
+++ b/src/booking/forms.py
@@ -10,12 +10,13 @@ import django.forms as forms
from django.forms.widgets import NumberInput
from workflow.forms import (
- SearchableSelectMultipleWidget,
MultipleSelectFilterField,
MultipleSelectFilterWidget,
FormUtils)
from account.models import UserProfile
from resource_inventory.models import Image, Installer, Scenario
+from workflow.forms import SearchableSelectMultipleField
+from booking.lib import get_user_items, get_user_field_opts
class QuickBookingForm(forms.Form):
@@ -27,16 +28,11 @@ class QuickBookingForm(forms.Form):
scenario = forms.ModelChoiceField(queryset=Scenario.objects.all(), required=False)
def __init__(self, data=None, user=None, *args, **kwargs):
- chosen_users = []
if "default_user" in kwargs:
default_user = kwargs.pop("default_user")
else:
default_user = "you"
self.default_user = default_user
- if "chosen_users" in kwargs:
- chosen_users = kwargs.pop("chosen_users")
- elif data and "users" in data:
- chosen_users = data.getlist("users")
super(QuickBookingForm, self).__init__(data=data, **kwargs)
@@ -44,15 +40,15 @@ class QuickBookingForm(forms.Form):
Image.objects.filter(public=True) | Image.objects.filter(owner=user)
)
- self.fields['users'] = forms.CharField(
- widget=SearchableSelectMultipleWidget(
- attrs=self.build_search_widget_attrs(chosen_users, default_user=default_user)
- ),
- required=False
+ self.fields['users'] = SearchableSelectMultipleField(
+ queryset=UserProfile.objects.select_related('user').exclude(user=user),
+ items=get_user_items(exclude=user),
+ required=False,
+ **get_user_field_opts()
)
+
attrs = FormUtils.getLabData(0)
- attrs['selection_data'] = 'false'
- self.fields['filter_field'] = MultipleSelectFilterField(widget=MultipleSelectFilterWidget(attrs=attrs))
+ self.fields['filter_field'] = MultipleSelectFilterField(widget=MultipleSelectFilterWidget(**attrs))
self.fields['length'] = forms.IntegerField(
widget=NumberInput(
attrs={
diff --git a/src/booking/lib.py b/src/booking/lib.py
new file mode 100644
index 0000000..8132c75
--- /dev/null
+++ b/src/booking/lib.py
@@ -0,0 +1,36 @@
+##############################################################################
+# Copyright (c) 2019 Parker Berberian, Sawyer Bergeron, and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+from account.models import UserProfile
+
+
+def get_user_field_opts():
+ return {
+ 'show_from_noentry': False,
+ 'show_x_results': 5,
+ 'results_scrollable': True,
+ 'selectable_limit': -1,
+ 'placeholder': 'Search for other users',
+ 'name': 'users',
+ 'disabled': False
+ }
+
+
+def get_user_items(exclude=None):
+ qs = UserProfile.objects.select_related('user').exclude(user=exclude)
+ items = {}
+ for up in qs:
+ item = {
+ 'id': up.id,
+ 'expanded_name': up.full_name,
+ 'small_name': up.user.username,
+ 'string': up.email_addr
+ }
+ items[up.id] = item
+ return items
diff --git a/src/booking/quick_deployer.py b/src/booking/quick_deployer.py
index 763c8a0..0e0cc5a 100644
--- a/src/booking/quick_deployer.py
+++ b/src/booking/quick_deployer.py
@@ -12,7 +12,6 @@ import json
import uuid
import re
from django.db.models import Q
-from django.contrib.auth.models import User
from datetime import timedelta
from django.utils import timezone
from account.models import Lab
@@ -97,25 +96,22 @@ class BookingPermissionException(Exception):
pass
-def parse_host_field(host_field_contents):
- host_json = json.loads(host_field_contents)
- lab_dict = host_json['labs'][0]
- lab_id = list(lab_dict.keys())[0]
- lab_user_id = int(lab_id.split("_")[-1])
- lab = Lab.objects.get(lab_user__id=lab_user_id)
+def parse_host_field(host_json):
+ lab, profile = (None, None)
+ lab_dict = host_json['lab']
+ for lab_info in lab_dict.values():
+ if lab_info['selected']:
+ lab = Lab.objects.get(lab_user__id=lab_info['id'])
- host_dict = host_json['hosts'][0]
- profile_id = list(host_dict.keys())[0]
- profile_id = int(profile_id.split("_")[-1])
- profile = HostProfile.objects.get(id=profile_id)
+ host_dict = host_json['host']
+ for host_info in host_dict.values():
+ if host_info['selected']:
+ profile = HostProfile.objects.get(pk=host_info['id'])
- # check validity of field data before trying to apply to models
- if len(host_json['labs']) != 1:
+ if lab is None:
raise NoLabSelectedError("No lab was selected")
- if not lab:
- raise LabDNE("Lab with provided ID does not exist")
- if not profile:
- raise HostProfileDNE("Host type with provided ID does not exist")
+ if profile is None:
+ raise HostProfileDNE("No Host was selected")
return lab, profile
@@ -321,12 +317,8 @@ def create_from_form(form, request):
)
booking.pdf = PDFTemplater.makePDF(booking)
- users_field = users_field[2:-2]
- if users_field: # may be empty after split, if no collaborators entered
- users_field = json.loads(users_field)
- for collaborator in users_field:
- user = User.objects.get(id=collaborator['id'])
- booking.collaborators.add(user)
+ for collaborator in users_field: # list of UserProfiles
+ booking.collaborators.add(collaborator.user)
booking.save()
@@ -334,6 +326,8 @@ def create_from_form(form, request):
JobFactory.makeCompleteJob(booking)
NotificationHandler.notify_new_booking(booking)
+ return booking
+
def drop_filter(user):
installer_filter = {}
diff --git a/src/booking/stats.py b/src/booking/stats.py
index b706577..383723a 100644
--- a/src/booking/stats.py
+++ b/src/booking/stats.py
@@ -25,34 +25,34 @@ class StatisticsManager(object):
some point in the given date span is the number of days to plot.
The last x value will always be the current time
"""
- x_set = set()
+ data = []
x = []
y = []
users = []
now = datetime.datetime.now(pytz.utc)
delta = datetime.timedelta(days=span)
end = now - delta
- bookings = Booking.objects.filter(start__lte=now, end__gte=end)
- for booking in bookings:
- x_set.add(booking.start)
- if booking.end < now:
- x_set.add(booking.end)
+ bookings = Booking.objects.filter(start__lte=now, end__gte=end).prefetch_related("collaborators")
+ for booking in bookings: # collect data from each booking
+ user_list = [u.pk for u in booking.collaborators.all()]
+ user_list.append(booking.owner.pk)
+ data.append((booking.start, 1, user_list))
+ data.append((booking.end, -1, user_list))
- x_set.add(now)
- x_set.add(end)
+ # sort based on time
+ data.sort(key=lambda i: i[0])
- x_list = list(x_set)
- x_list.sort(reverse=True)
- for time in x_list:
- x.append(str(time))
- active = Booking.objects.filter(start__lte=time, end__gt=time)
- booking_count = len(active)
- users_set = set()
- for booking in active:
- users_set.add(booking.owner)
- for user in booking.collaborators.all():
- users_set.add(user)
- y.append(booking_count)
- users.append(len(users_set))
+ # collect data
+ count = 0
+ active_users = {}
+ for datum in data:
+ x.append(str(datum[0])) # time
+ count += datum[1] # booking count
+ y.append(count)
+ for pk in datum[2]: # maintain count of each user's active bookings
+ active_users[pk] = active_users.setdefault(pk, 0) + datum[1]
+ if active_users[pk] == 0:
+ del active_users[pk]
+ users.append(len([x for x in active_users.values() if x > 0]))
return {"booking": [x, y], "user": [x, users]}
diff --git a/src/booking/views.py b/src/booking/views.py
index 8211a0c..bad7dc9 100644
--- a/src/booking/views.py
+++ b/src/booking/views.py
@@ -16,6 +16,7 @@ from django.views import View
from django.views.generic import TemplateView
from django.shortcuts import redirect, render
from django.db.models import Q
+from django.urls import reverse
from resource_inventory.models import ResourceBundle, HostProfile, Image, Host
from resource_inventory.resource_manager import ResourceManager
@@ -47,7 +48,7 @@ def quick_create(request):
context['lab_profile_map'] = profiles
- context['form'] = QuickBookingForm(initial={}, chosen_users=[], default_user=request.user.username, user=request.user)
+ context['form'] = QuickBookingForm(default_user=request.user.username, user=request.user)
context.update(drop_filter(request.user))
@@ -60,14 +61,13 @@ def quick_create(request):
if form.is_valid():
try:
- create_from_form(form, request)
+ booking = create_from_form(form, request)
+ messages.success(request, "We've processed your request. "
+ "Check Account->My Bookings for the status of your new booking")
+ return redirect(reverse('booking:booking_detail', kwargs={'booking_id': booking.id}))
except Exception as e:
messages.error(request, "Whoops, an error occurred: " + str(e))
- return render(request, 'workflow/exit_redirect.html', context)
-
- messages.success(request, "We've processed your request. "
- "Check Account->My Bookings for the status of your new booking")
- return render(request, 'workflow/exit_redirect.html', context)
+ return render(request, 'booking/quick_deploy.html', context)
else:
messages.error(request, "Looks like the form didn't validate. Check that you entered everything correctly")
return render(request, 'booking/quick_deploy.html', context)