1from__future__importannotations 2 3fromtypingimportAny 4 5fromplain.assets.urlsimportget_asset_url 6fromplain.auth.viewsimportAuthViewMixin 7fromplain.formsimportForm 8fromplain.httpimportResponse,ResponseRedirect 9fromplain.runtimeimportsettings10fromplain.utils.module_loadingimportimport_string11fromplain.viewsimportFormView,View121314classSupportFormView(AuthViewMixin,FormView):15template_name="support/page.html"1617defget_form(self)->Form:18form_slug=self.url_kwargs["form_slug"]19form_class=import_string(settings.SUPPORT_FORMS[form_slug])20returnform_class(**self.get_form_kwargs())2122defget_template_context(self)->dict[str,Any]:23context=super().get_template_context()24form_slug=self.url_kwargs["form_slug"]25context["form_action"]=self.request.build_absolute_uri()26context["form_template_name"]=f"support/forms/{form_slug}.html"27context["success_template_name"]=f"support/success/{form_slug}.html"28context["success"]=self.request.query_params.get("success")=="true"29returncontext3031defget_form_kwargs(self)->dict[str,Any]:32kwargs=super().get_form_kwargs()33kwargs["user"]=self.user34kwargs["form_slug"]=self.url_kwargs["form_slug"]35returnkwargs3637defform_valid(self,form:Any)->Response:38entry=form.save()39form.notify(entry)40returnsuper().form_valid(form)4142defget_success_url(self,form:Any)->str:43# Redirect to the same view and template so we44# don't have to create two additional views for iframe and non-iframe.45return"?success=true"464748classSupportIFrameView(SupportFormView):49template_name="support/iframe.html"5051defget_response(self)->Response:52response=super().get_response()5354# X-Frame-Options are typically in DEFAULT_RESPONSE_HEADERS,55# which will know to drop the header completely if an empty string.56# We can't del/pop it because DEFAULT_RESPONSE_HEADERS may add it back.57response.headers["X-Frame-Options"]=""5859returnresponse606162classSupportFormJSView(View):63defget(self)->ResponseRedirect:64returnResponseRedirect(get_asset_url("support/embed.js"))