1from __future__ import annotations
2
3from typing import Any
4
5from plain.assets.urls import get_asset_url
6from plain.auth.views import AuthView
7from plain.forms import Form
8from plain.http import RedirectResponse, Response, ResponseBase
9from plain.runtime import settings
10from plain.utils.module_loading import import_string
11from plain.views import FormView, View
12
13
14class SupportFormView(AuthView, FormView):
15 template_name = "support/page.html"
16
17 def get_form(self) -> Form:
18 form_slug = self.url_kwargs["form_slug"]
19 form_class = import_string(settings.SUPPORT_FORMS[form_slug])
20 return form_class(**self.get_form_kwargs())
21
22 def get_template_context(self) -> dict[str, Any]:
23 context = super().get_template_context()
24 form_slug = self.url_kwargs["form_slug"]
25 context["form_action"] = self.request.build_absolute_uri()
26 context["form_template_name"] = f"support/forms/{form_slug}.html"
27 context["success_template_name"] = f"support/success/{form_slug}.html"
28 context["success"] = self.request.query_params.get("success") == "true"
29 return context
30
31 def get_form_kwargs(self) -> dict[str, Any]:
32 kwargs = super().get_form_kwargs()
33 kwargs["user"] = self.user
34 kwargs["form_slug"] = self.url_kwargs["form_slug"]
35 return kwargs
36
37 def form_valid(self, form: Any) -> Response:
38 entry = form.save()
39 form.notify(entry)
40 return super().form_valid(form)
41
42 def get_success_url(self, form: Any) -> str:
43 # Redirect to the same view and template so we
44 # don't have to create two additional views for iframe and non-iframe.
45 return "?success=true"
46
47
48class SupportIFrameView(SupportFormView):
49 template_name = "support/iframe.html"
50
51 def get_response(self) -> ResponseBase:
52 response = super().get_response()
53
54 # X-Frame-Options are typically in DEFAULT_RESPONSE_HEADERS.
55 # Set to None to signal the middleware to skip applying this default header.
56 # We can't del/pop it because middleware runs after and would add it back.
57 response.headers["X-Frame-Options"] = None # type: ignore[assignment]
58
59 return response
60
61
62class SupportFormJSView(View):
63 def get(self) -> RedirectResponse:
64 return RedirectResponse(get_asset_url("support/embed.js"))