import logging from rest_framework import viewsets, status from rest_framework.response import Response from rest_framework.decorators import action from django.shortcuts import get_object_or_404 from hub.services.models import ServiceOffering, Lead from hub.services.odoo import OdooAPI from .models import ServiceInstance, ServiceBrokerUser from .serializers import ServiceInstanceProvisioningSerializer, CatalogSerializer from .authentication import ServiceBrokerAuthentication logger = logging.getLogger(__name__) class ServiceBrokerViewSet(viewsets.ViewSet): authentication_classes = [ServiceBrokerAuthentication] @action(detail=False, methods=["get"], url_path="catalog") def get_catalog(self, request): """ Return the catalog of services available to the authenticated user. """ # Get broker user and their allowed offerings broker_user = get_object_or_404(ServiceBrokerUser, user=request.user) offerings = broker_user.allowed_offerings.prefetch_related( "plans", "plans__prices", "plans__prices__currency", "plans__prices__term", "service", "cloud_provider", ).all() # Serialize the catalog serializer = CatalogSerializer({"services": offerings}) return Response(serializer.data) def _create_lead_from_provision_data(self, offering, plan, parameters, context): """Create a lead in Odoo from provisioning data""" # Get the first user from parameters as the main contact user_data = parameters["users"][0] lead = Lead( service=offering.service, offering=offering, plan=plan, name=user_data["full_name"], company=context["organization_display_name"], email=user_data["email"], phone="", # Not provided in broker API ) try: odoo = OdooAPI() lead.odoo_lead_id = odoo.create_lead(lead) lead.save() return lead except Exception as e: logger.error(f"Failed to create lead in Odoo: {str(e)}") raise @action( detail=False, methods=["put"], url_path="service_instances/(?P[^/.]+)", ) def provision_instance(self, request, instance_id): # Validate request data serializer = ServiceInstanceProvisioningSerializer(data=request.data) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) # Get broker user and check offering access broker_user = get_object_or_404(ServiceBrokerUser, user=request.user) offering = serializer.validated_data["service_id"] # This is now the offering if not broker_user.allowed_offerings.filter(id=offering.id).exists(): return Response( {"error": "Service offering not available for this user"}, status=status.HTTP_403_FORBIDDEN, ) # Check if instance already exists if ServiceInstance.objects.filter(instance_id=instance_id).exists(): return Response(status=status.HTTP_200_OK) try: # Create lead in Odoo lead = self._create_lead_from_provision_data( offering=offering, plan=serializer.validated_data["plan_id"], parameters=serializer.validated_data["parameters"], context=serializer.validated_data["context"], ) # Create service instance instance = ServiceInstance.objects.create( instance_id=instance_id, offering=offering, plan=serializer.validated_data["plan_id"], organization_guid=serializer.validated_data["organization_guid"], space_guid=serializer.validated_data["space_guid"], organization_name=serializer.validated_data["context"][ "organization_name" ], parameters=serializer.validated_data["parameters"], context=serializer.validated_data["context"], lead=lead, ) return Response( { "dashboard_url": f"/services/{offering.service.slug}", "operation": "provision", }, status=status.HTTP_201_CREATED, ) except Exception as e: logger.error(f"Error provisioning instance: {str(e)}") return Response( {"error": "Failed to provision service instance"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) @action( detail=False, methods=["delete"], url_path="service_instances/(?P[^/.]+)", ) def deprovision_instance(self, request, instance_id): instance = get_object_or_404(ServiceInstance, instance_id=instance_id) instance.delete() return Response(status=status.HTTP_200_OK)