Implement Exoscale onboarding API endpoint #199

Merged
rixx merged 14 commits from 37-exoscale-onboarding into main 2025-10-03 07:04:44 +00:00
2 changed files with 13 additions and 6 deletions
Showing only changes of commit 4e5388e514 - Show all commits

View file

@ -3,6 +3,7 @@ import logging
from contextlib import suppress from contextlib import suppress
from django.conf import settings from django.conf import settings
from django.contrib.auth.decorators import login_not_required
from django.core.mail import send_mail from django.core.mail import send_mail
from django.db import transaction from django.db import transaction
from django.http import JsonResponse from django.http import JsonResponse
@ -10,6 +11,7 @@ from django.utils.decorators import method_decorator
from django.views import View from django.views import View
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from servala.api.permissions import OSBBasicAuthPermission
from servala.core.exoscale import get_exoscale_origin from servala.core.exoscale import get_exoscale_origin
from servala.core.models import BillingEntity, Organization, User from servala.core.models import BillingEntity, Organization, User
from servala.core.models.service import Plan, Service from servala.core.models.service import Plan, Service
@ -18,7 +20,8 @@ logger = logging.getLogger(__name__)
@method_decorator(csrf_exempt, name="dispatch") @method_decorator(csrf_exempt, name="dispatch")
class OSBServiceInstanceView(View): @method_decorator(login_not_required, name="dispatch")
class OSBServiceInstanceView(OSBBasicAuthPermission, View):
""" """
OSB API endpoint for service instance provisioning (onboarding). OSB API endpoint for service instance provisioning (onboarding).
Implements the PUT /v2/service_instances/:instance_id endpoint. Implements the PUT /v2/service_instances/:instance_id endpoint.
@ -29,7 +32,10 @@ class OSBServiceInstanceView(View):
return JsonResponse({"error": error}, status=400) return JsonResponse({"error": error}, status=400)
def _get_user(self, data): def _get_user(self, data):
email = data.get("email").strip().lower() email = data.get("email", "").strip().lower()
if not email:
raise ValueError("Email address is required but missing or empty")
full_name = data.get("full_name") or "" full_name = data.get("full_name") or ""
name_parts = full_name.split(" ", 1) name_parts = full_name.split(" ", 1)
first_name = name_parts[0] if name_parts else "" first_name = name_parts[0] if name_parts else ""
@ -58,7 +64,9 @@ class OSBServiceInstanceView(View):
"organization_guid" "organization_guid"
) )
organization_name = context.get("organization_name") organization_name = context.get("organization_name")
organization_display_name = context.get("organization_display_name") organization_display_name = context.get(
"organization_display_name", organization_name
)
users = parameters.get("users", []) users = parameters.get("users", [])
service_id = data.get("service_id") service_id = data.get("service_id")
plan_id = data.get("plan_id") plan_id = data.get("plan_id")
@ -83,7 +91,7 @@ class OSBServiceInstanceView(View):
try: try:
service = Service.objects.get(id=service_id) service = Service.objects.get(id=service_id)
plan = Plan.objects.get(id=plan_id, service=service) plan = Plan.objects.get(id=plan_id, service_offering__service=service)
except Service.DoesNotExist: except Service.DoesNotExist:
return self._error(f"Unknown service_id: {service_id}") return self._error(f"Unknown service_id: {service_id}")
except Plan.DoesNotExist: except Plan.DoesNotExist:
@ -152,7 +160,7 @@ The Servala Team"""
) )
def _send_service_welcome_email(self, request, organization, user, service, plan): def _send_service_welcome_email(self, request, organization, user, service, plan):
service_path = f"{organization.urls.services}{service.slug}/offering/{plan.service_offering_id}/" service_path = f"{organization.urls.services}{service.slug}/offering/{plan.service_offering.id}/"
service_url = request.build_absolute_uri(service_path) service_url = request.build_absolute_uri(service_path)
subject = f"Get started with {service.name} - {organization.name}" subject = f"Get started with {service.name} - {organization.name}"

View file

@ -168,7 +168,6 @@ INSTALLED_APPS = [
MIDDLEWARE = [ MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware", "django.middleware.security.SecurityMiddleware",
"servala.api.authentication.OSBBasicAuthentication",
"django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware", "django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware", "django.middleware.csrf.CsrfViewMiddleware",