import logging import stripe from asgiref.sync import sync_to_async from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin from django.http import JsonResponse from django.shortcuts import redirect, render from django.urls import reverse, reverse_lazy from django.views import View from django.views.generic.edit import CreateView from core.forms import NewUserForm from core.lib.notify import raw_sendmsg from core.lib.products import assemble_plan_map from core.models import Plan, Session logger = logging.getLogger(__name__) # Create your views here class Home(LoginRequiredMixin, View): template_name = "index.html" def get(self, request): return render(request, self.template_name) class Billing(LoginRequiredMixin, View): template_name = "billing.html" async def get(self, request): if not settings.STRIPE_ENABLED: return redirect(reverse("home")) plans = await sync_to_async(list)(Plan.objects.all()) user_plans = await sync_to_async(list)(request.user.plans.all()) context = {"plans": plans, "user_plans": user_plans} return render(request, self.template_name, context) class Order(LoginRequiredMixin, View): async def get(self, request, plan_name): if not settings.STRIPE_ENABLED: return redirect(reverse("home")) plan = Plan.objects.get(name=plan_name) try: cast = { "payment_method_types": settings.ALLOWED_PAYMENT_METHODS, "mode": "subscription", "customer": request.user.stripe_id, "line_items": await assemble_plan_map( product_id_filter=plan.product_id ), "success_url": request.build_absolute_uri(reverse("success")), "cancel_url": request.build_absolute_uri(reverse("cancel")), } if request.user.is_superuser: cast["discounts"] = [{"coupon": settings.STRIPE_ADMIN_COUPON}] session = stripe.checkout.Session.create(**cast) await Session.objects.acreate(user=request.user, session=session.id) return redirect(session.url) # return JsonResponse({'id': session.id}) except Exception as e: # Raise a server error return JsonResponse({"error": str(e)}, status=500) class Cancel(LoginRequiredMixin, View): async def get(self, request, plan_name): if not settings.STRIPE_ENABLED: return redirect(reverse("home")) plan = Plan.objects.get(name=plan_name) try: subscriptions = stripe.Subscription.list( customer=request.user.stripe_id, price=plan.product_id ) for subscription in subscriptions["data"]: items = subscription["items"]["data"] for item in items: stripe.Subscription.delete(item["subscription"]) return render(request, "subscriptioncancel.html", {"plan": plan}) # return JsonResponse({'id': session.id}) except Exception as e: # Raise a server error logging.error(f"Error cancelling subscription for user: {e}") return JsonResponse({"error": "True"}, status=500) class Signup(CreateView): form_class = NewUserForm success_url = reverse_lazy("two_factor:login") template_name = "registration/signup.html" def form_valid(self, form): """If the form is valid, save the associated model.""" self.object = form.save() raw_sendmsg( f"New user signup: {self.object.username} - {self.object.email}", title="New user", topic=settings.NOTIFY_TOPIC, ) return super().form_valid(form) def get(self, request, *args, **kwargs): if not settings.REGISTRATION_OPEN: return render(request, "registration/registration_closed.html") return super().get(request, *args, **kwargs) class Portal(LoginRequiredMixin, View): async def get(self, request): if not settings.STRIPE_ENABLED: return redirect(reverse("home")) session = stripe.billing_portal.Session.create( customer=request.user.stripe_id, return_url=request.build_absolute_uri(reverse("billing")), ) return redirect(session.url)