1from __future__ import annotations
2
3from typing import Any
4
5from plain.auth import get_user_model
6from plain.email import TemplateEmail
7from plain.models import Model
8from plain.models.forms import ModelForm
9from plain.runtime import settings
10
11from .models import SupportFormEntry
12
13
14class SupportForm(ModelForm):
15 """
16 The form is the customization point for users.
17 So any behavior modifications should be possible here.
18 """
19
20 class Meta:
21 model = SupportFormEntry
22 fields = ["name", "email", "message"]
23
24 def __init__(self, user: Model | None, form_slug: str, *args: Any, **kwargs: Any):
25 super().__init__(*args, **kwargs)
26 self.user = user # User provided directly by authed request
27 self.form_slug = form_slug
28 if self.user:
29 self.fields["email"].initial = user.email # type: ignore[attr-defined]
30
31 def find_user(self) -> Model | None:
32 # If the user isn't logged in (typical in an iframe, depending on session cookie settings),
33 # we can still try to look them up by email
34 # to associate the entry with them.
35 #
36 # Note that since they aren't logged in, this doesn't necessarily
37 # confirm that this wasn't an impersonation attempt.
38 # Subsequent conversations over email will confirm that they have access to the email.
39 email = self.cleaned_data.get("email")
40 if not email:
41 return None
42 UserModel = get_user_model()
43 try:
44 return UserModel.query.get(email=email)
45 except UserModel.DoesNotExist:
46 return None
47
48 def save(self, commit: bool = True) -> SupportFormEntry:
49 instance = super().save(commit=False)
50 instance.user = self.user or self.find_user()
51 instance.form_slug = self.form_slug
52 if commit:
53 instance.save()
54 return instance
55
56 def notify(self, instance: SupportFormEntry) -> None:
57 """
58 Notify the support team of a new support form entry.
59
60 Sends an immediate email by default.
61 """
62 email = TemplateEmail(
63 template="support_form_entry",
64 subject=f"Support request from {instance.name}",
65 to=[settings.SUPPORT_EMAIL],
66 reply_to=[str(instance.email)],
67 context={
68 "support_form_entry": instance,
69 },
70 )
71 email.send()