Source code for wuttaweb.views.email

# -*- coding: utf-8; -*-
################################################################################
#
#  wuttaweb -- Web App for Wutta Framework
#  Copyright © 2024-2026 Lance Edgar
#
#  This file is part of Wutta Framework.
#
#  Wutta Framework is free software: you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the Free
#  Software Foundation, either version 3 of the License, or (at your option) any
#  later version.
#
#  Wutta Framework is distributed in the hope that it will be useful, but
#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
#  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
#  more details.
#
#  You should have received a copy of the GNU General Public License along with
#  Wutta Framework.  If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Views for email settings
"""

import colander

from wuttaweb.views import MasterView
from wuttaweb.forms.schema import EmailRecipients


[docs] class EmailSettingView(MasterView): # pylint: disable=abstract-method """ Master view for :term:`email settings <email setting>`. """ model_name = "email_setting" model_key = "key" model_title = "Email Setting" url_prefix = "/email/settings" filterable = False sortable = True sort_on_backend = False paginated = False creatable = False deletable = False labels = { "key": "Email Key", "replyto": "Reply-To", } grid_columns = [ "key", "subject", "to", "enabled", ] # TODO: why does this not work? sort_defaults = "key" form_fields = [ "key", "fallback_key", "description", "subject", "sender", "replyto", "to", "cc", "bcc", "notes", "enabled", ] def __init__(self, request, context=None): super().__init__(request, context=context) self.email_handler = self.app.get_email_handler()
[docs] def get_grid_data(self, columns=None, session=None): """ This view calls :meth:`~wuttjamaican:wuttjamaican.email.EmailHandler.get_email_settings()` on the :attr:`email_handler` to obtain its grid data. """ data = [] for setting in self.email_handler.get_email_settings().values(): data.append(self.normalize_setting(setting)) return data
def normalize_setting(self, setting): # pylint: disable=empty-docstring """ """ key = setting.__name__ setting = setting(self.config) return { "key": key, "fallback_key": setting.fallback_key or "", "description": setting.get_description() or "", "subject": self.email_handler.get_auto_subject( key, rendered=False, setting=setting ), "sender": self.email_handler.get_auto_sender(key), "replyto": self.email_handler.get_auto_replyto(key) or colander.null, "to": self.email_handler.get_auto_to(key), "cc": self.email_handler.get_auto_cc(key), "bcc": self.email_handler.get_auto_bcc(key), "notes": self.email_handler.get_notes(key) or colander.null, "enabled": self.email_handler.is_enabled(key), } def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ g = grid super().configure_grid(g) # key g.set_searchable("key") g.set_link("key") # subject g.set_searchable("subject") g.set_link("subject") # to g.set_renderer("to", self.render_to_short) # enabled g.set_renderer("enabled", "boolean") def render_to_short( # pylint: disable=empty-docstring,unused-argument self, setting, field, value ): """ """ recips = value if not recips: return None if len(recips) < 3: return ", ".join(recips) recips = ", ".join(recips[:2]) return f"{recips}, ..." def get_instance( # pylint: disable=empty-docstring,arguments-differ,unused-argument self, **kwargs ): """ """ key = self.request.matchdict["key"] setting = self.email_handler.get_email_setting(key, instance=False) if setting: return self.normalize_setting(setting) raise self.notfound() def get_instance_title(self, instance): # pylint: disable=empty-docstring """ """ setting = instance return setting["subject"] def configure_form(self, form): # pylint: disable=empty-docstring """ """ f = form super().configure_form(f) # fallback_key f.set_readonly("fallback_key") # description f.set_readonly("description") f.set_widget("description", "notes") # replyto f.set_required("replyto", False) # to f.set_node("to", EmailRecipients()) # cc f.set_node("cc", EmailRecipients()) # bcc f.set_node("bcc", EmailRecipients()) # notes f.set_widget("notes", "notes") f.set_required("notes", False) # enabled f.set_node("enabled", colander.Boolean()) def persist( # pylint: disable=too-many-branches,empty-docstring,arguments-differ,unused-argument self, setting, **kwargs ): """ """ session = self.Session() key = self.request.matchdict["key"] def save(name, value): self.app.save_setting( session, f"{self.config.appname}.email.{key}.{name}", value ) def delete(name): self.app.delete_setting( session, f"{self.config.appname}.email.{key}.{name}" ) # subject if setting["subject"]: save("subject", setting["subject"]) else: delete("subject") # sender if setting["sender"]: save("sender", setting["sender"]) else: delete("sender") # replyto if setting["replyto"]: save("replyto", setting["replyto"]) else: delete("replyto") # to if setting["to"]: save("to", setting["to"]) else: delete("to") # cc if setting["cc"]: save("cc", setting["cc"]) else: delete("cc") # bcc if setting["bcc"]: save("bcc", setting["bcc"]) else: delete("bcc") # notes if setting["notes"]: save("notes", setting["notes"]) else: delete("notes") # enabled save("enabled", "true" if setting["enabled"] else "false") def render_to_response(self, template, context): # pylint: disable=empty-docstring """ """ if self.viewing: setting = context["instance"] context["setting"] = setting context["has_html_template"] = self.email_handler.get_auto_body_template( setting["key"], "html", fallback_key=setting["fallback_key"] ) context["has_txt_template"] = self.email_handler.get_auto_body_template( setting["key"], "txt", fallback_key=setting["fallback_key"] ) return super().render_to_response(template, context)
[docs] def preview(self): """ View for showing a rendered preview of a given email template. This will render the email template according to the "mode" requested - i.e. HTML or TXT. """ key = self.request.matchdict["key"] setting = self.email_handler.get_email_setting(key) context = setting.sample_data() mode = self.request.params.get("mode", "html") if mode == "txt": body = self.email_handler.get_auto_txt_body( key, context, fallback_key=setting.fallback_key ) self.request.response.content_type = "text/plain" else: # html body = self.email_handler.get_auto_html_body( key, context, fallback_key=setting.fallback_key ) self.request.response.text = body return self.request.response
@classmethod def defaults(cls, config): # pylint: disable=empty-docstring """ """ cls._email_defaults(config) cls._defaults(config) @classmethod def _email_defaults(cls, config): """ """ route_prefix = cls.get_route_prefix() permission_prefix = cls.get_permission_prefix() model_title_plural = cls.get_model_title_plural() instance_url_prefix = cls.get_instance_url_prefix() # fix permission group config.add_wutta_permission_group( permission_prefix, model_title_plural, overwrite=False ) # preview config.add_route(f"{route_prefix}.preview", f"{instance_url_prefix}/preview") config.add_view( cls, attr="preview", route_name=f"{route_prefix}.preview", permission=f"{permission_prefix}.view", )
def defaults(config, **kwargs): # pylint: disable=missing-function-docstring base = globals() EmailSettingView = kwargs.get( # pylint: disable=invalid-name,redefined-outer-name "EmailSettingView", base["EmailSettingView"] ) EmailSettingView.defaults(config) def includeme(config): # pylint: disable=missing-function-docstring defaults(config)