From f8bf1f2a78dfa3d5188aa3d4654bc461c3755ad4 Mon Sep 17 00:00:00 2001
From: George Katsikas <giorgakis.katsikas@gmail.com>
Date: Wed, 31 Jul 2024 16:58:10 +0200
Subject: [PATCH] allow queryset resolution in json email config

---
 scipost_django/mails/core.py | 53 +++++++++++++++++++++++++-----------
 1 file changed, 37 insertions(+), 16 deletions(-)

diff --git a/scipost_django/mails/core.py b/scipost_django/mails/core.py
index 9ddf3a923..41ab535ac 100644
--- a/scipost_django/mails/core.py
+++ b/scipost_django/mails/core.py
@@ -272,14 +272,22 @@ class MailEngine:
                 was_list = isinstance(emails, list)
                 emails = emails if was_list else [emails]
 
-                valid_emails = [
+                valid_emails: list[str | list[str]] = [
                     valid_entry
                     for entry in emails
                     if (valid_entry := self._validate_email_addresses(entry))
                 ]
 
+                # Chain list of lists to a single list.
+                flattened_valid_emails = []
+                for entry in valid_emails:
+                    if isinstance(entry, list):
+                        flattened_valid_emails.extend(entry)
+                    else:
+                        flattened_valid_emails.append(entry)
+
                 # Remove duplicate recipients from email list
-                valid_emails = list(set(valid_emails))
+                valid_emails = list(set(flattened_valid_emails))
 
                 if len(valid_emails) == 0:
                     raise ConfigurationError(
@@ -294,24 +302,37 @@ class MailEngine:
         """
         Return email address given raw email, email prefix or database relation given in `entry`.
         """
+        # Separate entry from possible filter function.
+        entry, filter_func = entry.split("|") if "|" in entry else (entry, "")
+        filter_func, args = (
+            filter_func.split(":") if ":" in filter_func else (filter_func, "email")
+        )
+
+        # Email string
         if re.match("[^@]+@[^@]+\.[^@]+", entry):
-            # Email string
             return entry
-        # if the email address is given as a prefix of the form `[recipient]@`, add domain name:
+        # Domain prefixed `[recipient]@`
         elif re.match("[^@]+@$", entry):
-            return "%s%s" % (entry, get_current_domain())
-        elif self.template_variables["object"]:
-            mail_to = self.template_variables["object"]
-            for attr in entry.split("|")[0].split("."):
+            return f"{entry}{get_current_domain()}"
+        # Database relation
+        elif obj := self.template_variables["object"]:
+            obj = self.template_variables["object"]
+
+            print(obj, entry, filter_func, args)
+
+            # Recurse through object properties to get the email address.
+            for attr in entry.split("."):
                 try:
-                    mail_to = getattr(mail_to, attr)
-                    if inspect.ismethod(mail_to):
-                        mail_to = mail_to()
+                    obj = getattr(obj, attr)
+                    if isinstance(obj, models.Manager):
+                        obj = list(obj.values_list(args, flat=True))
+                    elif inspect.ismethod(obj):
+                        obj = obj()
                 except AttributeError:
-                    # Invalid property/mail
-                    if entry.endswith("|None"):
-                        # Allow None values
+                    # Allow None values
+                    if filter_func == "None":
                         return None
                     raise KeyError("The property (%s) does not exist." % entry)
-            return mail_to
-        raise KeyError("Neither an email adress nor db instance is given.")
+            return obj
+
+        raise KeyError("Neither an email address nor db instance is given.")
-- 
GitLab