Plain is headed towards 1.0! Subscribe for development updates →

 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()