aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/views.py
diff options
context:
space:
mode:
authorSawyer Bergeron <sbergeron@iol.unh.edu>2021-10-15 14:14:46 -0400
committerSawyer Bergeron <sbergeron@iol.unh.edu>2021-10-15 14:20:02 -0400
commit35b9f39178cc502a5283a1b37a65f7dd0838ae05 (patch)
tree676ede483e2aa6a0ad8ebaef0c0300a155a22023 /src/api/views.py
parentb3ed8ebcf536c021330e7ccbc0376f6b89189348 (diff)
Merge User Booking API Rev 1 (Try 3)
Signed-off-by: Sawyer Bergeron <sbergeron@iol.unh.edu> Change-Id: Ie1eee0a59929f8da39f16bb6bc17ae3de4f1cba9 Signed-off-by: Sawyer Bergeron <sbergeron@iol.unh.edu>
Diffstat (limited to 'src/api/views.py')
-rw-r--r--src/api/views.py235
1 files changed, 231 insertions, 4 deletions
diff --git a/src/api/views.py b/src/api/views.py
index 2e5f33f..c0da1bc 100644
--- a/src/api/views.py
+++ b/src/api/views.py
@@ -8,9 +8,14 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
+import json
+import math
+import traceback
+import sys
+from datetime import timedelta
from django.contrib.auth.decorators import login_required
-from django.shortcuts import redirect
+from django.shortcuts import redirect, get_object_or_404
from django.utils.decorators import method_decorator
from django.utils import timezone
from django.views import View
@@ -23,12 +28,15 @@ from django.core.exceptions import ObjectDoesNotExist
from api.serializers.booking_serializer import BookingSerializer
from api.serializers.old_serializers import UserSerializer
from api.forms import DowntimeForm
-from account.models import UserProfile
+from account.models import UserProfile, Lab
from booking.models import Booking
-from api.models import LabManagerTracker, get_task
+from api.models import LabManagerTracker, AutomationAPIManager, get_task, APILog
from notifier.manager import NotificationHandler
from analytics.models import ActiveVPNUser
-import json
+from booking.quick_deployer import create_from_API
+from resource_inventory.models import ResourceTemplate
+from django.db.models import Q
+
"""
API views.
@@ -234,3 +242,222 @@ def done_jobs(request, lab_name=""):
lab_token = request.META.get('HTTP_AUTH_TOKEN')
lab_manager = LabManagerTracker.get(lab_name, lab_token)
return JsonResponse(lab_manager.get_done_jobs(), safe=False)
+
+
+def auth_and_log(request, endpoint):
+ """
+ Function to authenticate an API user and log info
+ in the API log model. This is to keep record of
+ all calls to the dashboard
+ """
+ user_token = request.META.get('HTTP_AUTH_TOKEN')
+ response = None
+
+ if user_token is None:
+ return HttpResponse('Unauthorized', status=401)
+
+ try:
+ token = Token.objects.get(key=user_token)
+ except Token.DoesNotExist:
+ token = None
+ response = HttpResponse('Unauthorized', status=401)
+
+ x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
+ if x_forwarded_for:
+ ip = x_forwarded_for.split(',')[0]
+ else:
+ ip = request.META.get('REMOTE_ADDR')
+
+ body = None
+
+ if request.method in ['POST', 'PUT']:
+ try:
+ body = json.loads(request.body.decode('utf-8')),
+ except Exception:
+ response = HttpResponse('Invalid Request Body', status=400)
+
+ APILog.objects.create(
+ user=token.user,
+ call_time=timezone.now(),
+ method=request.method,
+ endpoint=endpoint,
+ body=body,
+ ip_addr=ip
+ )
+
+ if response:
+ return response
+ else:
+ return token
+
+
+"""
+Booking API Views
+"""
+
+
+def user_bookings(request):
+ token = auth_and_log(request, 'booking')
+
+ if isinstance(token, HttpResponse):
+ return token
+
+ bookings = Booking.objects.filter(owner=token.user, end__gte=timezone.now())
+ output = [AutomationAPIManager.serialize_booking(booking)
+ for booking in bookings]
+ return JsonResponse(output, safe=False)
+
+
+@csrf_exempt
+def specific_booking(request, booking_id=""):
+ token = auth_and_log(request, 'booking/{}'.format(booking_id))
+
+ if isinstance(token, HttpResponse):
+ return token
+
+ booking = get_object_or_404(Booking, pk=booking_id, owner=token.user)
+ if request.method == "GET":
+ sbooking = AutomationAPIManager.serialize_booking(booking)
+ return JsonResponse(sbooking, safe=False)
+
+ if request.method == "DELETE":
+
+ if booking.end < timezone.now():
+ return HttpResponse("Booking already over", status=400)
+
+ booking.end = timezone.now()
+ booking.save()
+ return HttpResponse("Booking successfully cancelled")
+
+
+@csrf_exempt
+def extend_booking(request, booking_id="", days=""):
+ token = auth_and_log(request, 'booking/{}/extendBooking/{}'.format(booking_id, days))
+
+ if isinstance(token, HttpResponse):
+ return token
+
+ booking = get_object_or_404(Booking, pk=booking_id, owner=token.user)
+
+ if booking.end < timezone.now():
+ return HttpResponse("This booking is already over, cannot extend")
+
+ if days > 30:
+ return HttpResponse("Cannot extend a booking longer than 30 days")
+
+ if booking.ext_count == 0:
+ return HttpResponse("Booking has already been extended 2 times, cannot extend again")
+
+ booking.end += timedelta(days=days)
+ booking.ext_count -= 1
+ booking.save()
+
+ return HttpResponse("Booking successfully extended")
+
+
+@csrf_exempt
+def make_booking(request):
+ token = auth_and_log(request, 'booking/makeBooking')
+
+ if isinstance(token, HttpResponse):
+ return token
+
+ try:
+ booking = create_from_API(request.body, token.user)
+
+ except Exception:
+ finalTrace = ''
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ for i in traceback.format_exception(exc_type, exc_value, exc_traceback):
+ finalTrace += '<br>' + i.strip()
+ return HttpResponse(finalTrace, status=400)
+
+ sbooking = AutomationAPIManager.serialize_booking(booking)
+ return JsonResponse(sbooking, safe=False)
+
+
+"""
+Resource Inventory API Views
+"""
+
+
+def available_templates(request):
+ token = auth_and_log(request, 'resource_inventory/availableTemplates')
+
+ if isinstance(token, HttpResponse):
+ return token
+
+ # get available templates
+ # mirrors MultipleSelectFilter Widget
+ avt = []
+ for lab in Lab.objects.all():
+ for template in ResourceTemplate.objects.filter(Q(owner=token.user) | Q(public=True), lab=lab, temporary=False):
+ available_resources = lab.get_available_resources()
+ required_resources = template.get_required_resources()
+ least_available = 100
+
+ for resource, count_required in required_resources.items():
+ try:
+ curr_count = math.floor(available_resources[str(resource)] / count_required)
+ if curr_count < least_available:
+ least_available = curr_count
+ except KeyError:
+ least_available = 0
+
+ if least_available > 0:
+ avt.append((template, least_available))
+
+ savt = [AutomationAPIManager.serialize_template(temp)
+ for temp in avt]
+
+ return JsonResponse(savt, safe=False)
+
+
+def images_for_template(request, template_id=""):
+ _ = auth_and_log(request, 'resource_inventory/{}/images'.format(template_id))
+
+ template = get_object_or_404(ResourceTemplate, pk=template_id)
+ images = [AutomationAPIManager.serialize_image(config.image)
+ for config in template.getConfigs()]
+ return JsonResponse(images, safe=False)
+
+
+"""
+User API Views
+"""
+
+
+def all_users(request):
+ token = auth_and_log(request, 'users')
+
+ if token is None:
+ return HttpResponse('Unauthorized', status=401)
+
+ users = [AutomationAPIManager.serialize_userprofile(up)
+ for up in UserProfile.objects.filter(public_user=True)]
+
+ return JsonResponse(users, safe=False)
+
+
+"""
+Lab API Views
+"""
+
+
+def list_labs(request):
+ lab_list = []
+ for lab in Lab.objects.all():
+ lab_info = {
+ 'name': lab.name,
+ 'username': lab.lab_user.username,
+ 'status': lab.status,
+ 'project': lab.project,
+ 'description': lab.description,
+ 'location': lab.location,
+ 'info': lab.lab_info_link,
+ 'email': lab.contact_email,
+ 'phone': lab.contact_phone
+ }
+ lab_list.append(lab_info)
+
+ return JsonResponse(lab_list, safe=False)