From e2137d1fbc4c8eb99fe3353204d868ae13006866 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Thu, 25 Jun 2020 18:49:26 +0200
Subject: [PATCH] emails: allow user to define email sender name (#44411)

---
 hobo/emails/forms.py                 |  2 ++
 hobo/emails/views.py                 |  2 +-
 hobo/environment/models.py           |  1 +
 hobo/multitenant/settings_loaders.py |  5 ++--
 tests/test_emails.py                 |  5 ++--
 tests/test_settings_loaders.py       | 34 +++++++++++++++++++++++++++-
 6 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/hobo/emails/forms.py b/hobo/emails/forms.py
index a3305dd..b02391b 100644
--- a/hobo/emails/forms.py
+++ b/hobo/emails/forms.py
@@ -24,16 +24,18 @@ class ValidEmailField(forms.EmailField):
     def validate(self, value):
         validate_email(value)
         validate_email_address(value)
         validate_email_spf(value)
 
 
 class EmailsForm(forms.Form):
     default_from_email = ValidEmailField(label=_('Default From'))
+    email_sender_name = forms.CharField(label=_('Sender Name'), required=False,
+            help_text=_('(defaults to plateform title)'))
     global_email_prefix = forms.CharField(label=_('Prefix'), required=False,
             help_text=_('Custom prefix for emails subject (defaults to plateform title)'))
     email_signature = forms.CharField(label=_('Signature'), required=False,
             widget=forms.Textarea)
 
     def __init__(self, *args, **kwargs):
         super(EmailsForm, self).__init__(*args, **kwargs)
         self.fields['email_signature'].widget.attrs = {'rows': 4, 'cols': 80}
diff --git a/hobo/emails/views.py b/hobo/emails/views.py
index a61712d..5069d56 100644
--- a/hobo/emails/views.py
+++ b/hobo/emails/views.py
@@ -19,14 +19,14 @@ from django.utils.translation import ugettext as _
 from django.views.generic import TemplateView
 
 from hobo.environment.forms import VariablesFormMixin
 from .forms import EmailsForm
 
 
 class HomeView(VariablesFormMixin, TemplateView):
     template_name = 'hobo/emails_home.html'
-    variables = ['default_from_email', 'global_email_prefix', 'email_signature']
+    variables = ['default_from_email', 'email_sender_name', 'global_email_prefix', 'email_signature']
     form_class = EmailsForm
     success_message = _('Emails settings have been updated. '
                         'It will take a few seconds to be effective.')
 
 home = HomeView.as_view()
diff --git a/hobo/environment/models.py b/hobo/environment/models.py
index fbb62fb..34a69ff 100644
--- a/hobo/environment/models.py
+++ b/hobo/environment/models.py
@@ -42,16 +42,17 @@ from .mandayejs_app_settings import APP_SETTINGS_CLASSES, DEFAULT_APP_SETTINGS
 SECRET_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
 FLOAT_RE = re.compile(r'^\s*[0-9]+\.[0-9]+\s*')
 
 
 AUTO_VARIABLES = (
         'default_from_email',
         'global_email_prefix',
         'email_signature',
+        'email_sender_name',
         'global_title',
         'robots_txt',
         'meta_description',
         'meta_keywords',
 )
 
 class Variable(models.Model):
     name = models.CharField(max_length=100, verbose_name=_('name'))
diff --git a/hobo/multitenant/settings_loaders.py b/hobo/multitenant/settings_loaders.py
index 634d1bd..f65ee03 100644
--- a/hobo/multitenant/settings_loaders.py
+++ b/hobo/multitenant/settings_loaders.py
@@ -178,19 +178,20 @@ class TemplateVars(FileBaseSettingsLoader):
             tenant_settings.TEMPLATE_VARS = {}
 
         for key, value in variables.items():
             # prevent mixing settings and template vars
             if not key.startswith(SETTING_PREFIX):
                 tenant_settings.TEMPLATE_VARS[key] = value
 
         if variables.get('default_from_email'):
-            if variables.get('global_title'):
+            from_label = variables.get('email_sender_name') or variables.get('global_title')
+            if from_label:
                 tenant_settings.DEFAULT_FROM_EMAIL = '"%s" <%s>' % (
-                        variables['global_title'].replace('"', ' '), variables['default_from_email'])
+                        from_label.replace('"', ' '), variables['default_from_email'])
             else:
                 tenant_settings.DEFAULT_FROM_EMAIL = variables['default_from_email']
 
         tenant_settings.USER_PROFILE_CONFIG = hobo_json.get('profile')
 
 
 class SettingsVars(SettingsDictUpdateMixin, FileBaseSettingsLoader):
     FILENAME = 'hobo.json'
diff --git a/tests/test_emails.py b/tests/test_emails.py
index 09beef6..ba00428 100644
--- a/tests/test_emails.py
+++ b/tests/test_emails.py
@@ -174,19 +174,20 @@ def test_valid_spf(client, admin_user, dns_resolver, smtp_server, settings):
 def test_no_spf_validation(client, admin_user, dns_resolver, smtp_server, settings):
     settings.ALLOWED_SPF_RECORDS = []
     client.post('/login/', {'username': 'admin', 'password': 'password'})
     response = client.post('/emails/', {'default_from_email': 'john.doe@example-invalid-spf.com'}, follow=True)
     assert response.status_code == 200
     assert 'Emails settings have been updated. It will take a few seconds to be effective.' in force_text(response.content)
 
 
-def test_emails_view(app, admin_user, dns_resolver, smtp_server, settings):
-    settings.ALLOWED_SPF_RECORDS = ['include:allowed_mx.com']
+def test_emails_view(app, admin_user, dns_resolver, smtp_server):
     app = login(app)
     resp = app.get('/emails/')
     resp.form['default_from_email'] = 'john.doe@example.com'
     resp.form['email_signature'] = 'my signature'
     resp.form['global_email_prefix'] = 'my prefix'
+    resp.form['email_sender_name'] = 'my name'
     resp = resp.form.submit()
     assert Variable.objects.filter(name='default_from_email')[0].value == 'john.doe@example.com'
     assert Variable.objects.filter(name='email_signature')[0].value == 'my signature'
     assert Variable.objects.filter(name='global_email_prefix')[0].value == 'my prefix'
+    assert Variable.objects.filter(name='email_sender_name')[0].value == 'my name'
diff --git a/tests/test_settings_loaders.py b/tests/test_settings_loaders.py
index eaafe40..5d2b46e 100644
--- a/tests/test_settings_loaders.py
+++ b/tests/test_settings_loaders.py
@@ -2,17 +2,17 @@ import json
 import os
 import pytest
 
 from django.conf import UserSettingsHolder
 
 from hobo.deploy.utils import get_hobo_json
 from hobo.environment.models import Authentic, Combo
 from hobo.multitenant.settings_loaders import Authentic as AuthenticLoader
-from hobo.multitenant.settings_loaders import BackofficeLoginHint
+from hobo.multitenant.settings_loaders import BackofficeLoginHint, TemplateVars
 from hobo.profile.models import AttributeDefinition
 
 pytestmark = pytest.mark.django_db
 
 
 def test_authentic_update_settings_from_path(tmpdir):
     a = Authentic(title='bar', slug='bar', base_url='http://bar.example.net')
     a.save()
@@ -93,8 +93,40 @@ def test_mellon_always_backoffice_login_hint_setting_from_path(tmpdir):
 
     # call settings loaders
     tenant_settings = UserSettingsHolder({})
     assert not getattr(tenant_settings, 'MELLON_LOGIN_HINTS', False)
 
     loader = BackofficeLoginHint()
     loader.update_settings_from_path(tenant_settings, path)
     assert tenant_settings.MELLON_LOGIN_HINTS == ['always_backoffice']
+
+
+def test_email_update_settings_from_path(tmpdir):
+    tenant_settings = UserSettingsHolder({})
+    loader = TemplateVars()
+
+    def update_settings(env):
+        path = os.path.join(str(tmpdir), 'hobo.json')
+        json.dump(env, open(path, 'w'))
+        loader.update_settings_from_path(tenant_settings, path)
+
+    tenant_settings.DEFAULT_FROM_EMAIL = 'webmaster@hobo.example.org'
+    env = {'services': [], 'variables': {}}
+    update_settings(env)
+    assert tenant_settings.DEFAULT_FROM_EMAIL == 'webmaster@hobo.example.org'
+    env['variables']['default_from_email'] = 'john.doe@example.com'
+    update_settings(env)
+    assert tenant_settings.DEFAULT_FROM_EMAIL == 'john.doe@example.com'
+    env['variables']['global_title'] = 'Publik'
+    update_settings(env)
+    assert tenant_settings.DEFAULT_FROM_EMAIL == '"Publik" <john.doe@example.com>'
+    env['variables']['email_sender_name'] = 'Jhon Doe'
+    update_settings(env)
+    assert tenant_settings.DEFAULT_FROM_EMAIL == '"Jhon Doe" <john.doe@example.com>'
+    env['variables']['default_from_email'] = 'foo@example.com'
+    update_settings(env)
+    assert tenant_settings.DEFAULT_FROM_EMAIL == '"Jhon Doe" <foo@example.com>'
+
+    # default_from_email needed for '"foo" <bar.example.com>' address format
+    tenant_settings.DEFAULT_FROM_EMAIL = '<webmaster@hobo.example.org>'
+    update_settings({'services': [], 'variables': {'global_title': 'Publik'}})
+    assert tenant_settings.DEFAULT_FROM_EMAIL == '<webmaster@hobo.example.org>'
-- 
2.27.0

