From e083d6e1f29b37aceb3b4a1b7a5a56ef3e8f4084 Mon Sep 17 00:00:00 2001
From: Julian Rother <julian@cccv.de>
Date: Tue, 8 Nov 2022 20:35:29 +0100
Subject: [PATCH] Only show service email prefs to users with access

---
 tests/models/test_services.py                |  15 ++-
 tests/views/test_selfservice.py              |   6 +-
 tests/views/test_user.py                     |   8 +-
 uffd/models/service.py                       |  22 +++-
 uffd/templates/selfservice/self.html         |   7 +-
 uffd/templates/service/show.html             |  20 ++--
 uffd/templates/user/show.html                |   2 +-
 uffd/translations/de/LC_MESSAGES/messages.mo | Bin 40588 -> 40611 bytes
 uffd/translations/de/LC_MESSAGES/messages.po | 104 ++++++++++---------
 uffd/views/selfservice.py                    |   2 +-
 uffd/views/user.py                           |   2 +-
 11 files changed, 108 insertions(+), 80 deletions(-)

diff --git a/tests/models/test_services.py b/tests/models/test_services.py
index d6836b5f..2e411c9d 100644
--- a/tests/models/test_services.py
+++ b/tests/models/test_services.py
@@ -10,7 +10,7 @@ from tests.utils import UffdTestCase
 class TestServiceUser(UffdTestCase):
 	def setUp(self):
 		super().setUp()
-		db.session.add_all([Service(name='service1'), Service(name='service2', remailer_mode=RemailerMode.ENABLED_V1)])
+		db.session.add_all([Service(name='service1', limit_access=False), Service(name='service2', remailer_mode=RemailerMode.ENABLED_V1, limit_access=False)])
 		db.session.commit()
 
 	def test_auto_create(self):
@@ -79,6 +79,12 @@ class TestServiceUser(UffdTestCase):
 		self.assertEqual(service_user.real_email, user.primary_email.address)
 		service.enable_email_preferences = True
 		self.assertEqual(service_user.real_email, service_user.service_email.address)
+		service.limit_access = True
+		self.assertEqual(service_user.real_email, user.primary_email.address)
+		service.access_group = self.get_admin_group()
+		self.assertEqual(service_user.real_email, user.primary_email.address)
+		service.access_group = self.get_users_group()
+		self.assertEqual(service_user.real_email, service_user.service_email.address)
 
 	def test_get_by_remailer_email(self):
 		user = self.get_user()
@@ -158,6 +164,8 @@ class TestServiceUser(UffdTestCase):
 			[RemailerMode.DISABLED, RemailerMode.ENABLED_V1, RemailerMode.ENABLED_V2],
 			# service.enable_email_preferences
 			[True, False],
+			# service.limit_access, service.access_group
+			[(False, None), (True, None), (True, self.get_admin_group()), (True, self.get_users_group())],
 			# service_user.service_email
 			[None, email1, email2],
 			# service_user.remailer_overwrite_mode
@@ -169,8 +177,9 @@ class TestServiceUser(UffdTestCase):
 			self.app.config['REMAILER_LIMIT_TO_USERS'] = options[2]
 			service.remailer_mode = options[3]
 			service.enable_email_preferences = options[4]
-			service_user.service_email = options[5]
-			service_user.remailer_overwrite_mode = options[6]
+			service.limit_access, service.access_group = options[5]
+			service_user.service_email = options[6]
+			service_user.remailer_overwrite_mode = options[7]
 			a = {result for result in all_service_users if result.email == value}
 			b = set(ServiceUser.filter_query_by_email(ServiceUser.query, value).all())
 			if a != b:
diff --git a/tests/views/test_selfservice.py b/tests/views/test_selfservice.py
index 5bf3e8f4..1b598aa9 100644
--- a/tests/views/test_selfservice.py
+++ b/tests/views/test_selfservice.py
@@ -200,7 +200,7 @@ class TestSelfservice(UffdTestCase):
 		user_id = self.get_user().id
 		email = UserEmail(user=self.get_user(), address='new@example.com', verified=True)
 		db.session.add(email)
-		service = Service(name='service', enable_email_preferences=True)
+		service = Service(name='service', enable_email_preferences=True, limit_access=False)
 		db.session.add(service)
 		db.session.commit()
 		email_id = email.id
@@ -235,7 +235,7 @@ class TestSelfservice(UffdTestCase):
 		user_id = self.get_user().id
 		email = UserEmail(user=self.get_user(), address='new@example.com')
 		db.session.add(email)
-		service = Service(name='service', enable_email_preferences=True)
+		service = Service(name='service', enable_email_preferences=True, limit_access=False)
 		db.session.add(service)
 		db.session.commit()
 		email_id = email.id
@@ -262,7 +262,7 @@ class TestSelfservice(UffdTestCase):
 		user_id = self.get_user().id
 		email = UserEmail(user=self.get_user(), address='new@example.com', verified=True)
 		db.session.add(email)
-		service = Service(name='service', enable_email_preferences=True)
+		service = Service(name='service', enable_email_preferences=True, limit_access=False)
 		db.session.add(service)
 		db.session.commit()
 		with self.assertRaises(Exception):
diff --git a/tests/views/test_user.py b/tests/views/test_user.py
index e51d305f..a024b53d 100644
--- a/tests/views/test_user.py
+++ b/tests/views/test_user.py
@@ -220,8 +220,8 @@ class TestUserViews(UffdTestCase):
 	def test_update_email(self):
 		user = self.get_user()
 		email = UserEmail(user=user, address='foo@example.com')
-		service1 = Service(name='service1', enable_email_preferences=True)
-		service2 = Service(name='service2', enable_email_preferences=True)
+		service1 = Service(name='service1', enable_email_preferences=True, limit_access=False)
+		service2 = Service(name='service2', enable_email_preferences=True, limit_access=False)
 		db.session.add_all([service1, service2])
 		db.session.commit()
 		email1_id = user.primary_email.id
@@ -276,8 +276,8 @@ class TestUserViews(UffdTestCase):
 		db.session.commit()
 		user = self.get_user()
 		email = UserEmail(user=user, address='foo@example.com')
-		service1 = Service(name='service1', enable_email_preferences=True)
-		service2 = Service(name='service2', enable_email_preferences=True)
+		service1 = Service(name='service1', enable_email_preferences=True, limit_access=False)
+		service2 = Service(name='service2', enable_email_preferences=True, limit_access=False)
 		db.session.add_all([service1, service2])
 		db.session.commit()
 		email1_id = user.primary_email.id
diff --git a/uffd/models/service.py b/uffd/models/service.py
index 2143e674..ff31419b 100644
--- a/uffd/models/service.py
+++ b/uffd/models/service.py
@@ -8,7 +8,7 @@ from sqlalchemy.orm import relationship, validates
 from uffd.database import db
 from uffd.remailer import remailer
 from uffd.tasks import cleanup_task
-from .user import User, UserEmail
+from .user import User, UserEmail, user_groups
 
 class RemailerMode(enum.Enum):
 	DISABLED = 0
@@ -58,6 +58,10 @@ class ServiceUser(db.Model):
 	def has_access(self):
 		return not self.service.limit_access or self.service.access_group in self.user.groups
 
+	@property
+	def has_email_preferences(self):
+		return self.has_access and self.service.enable_email_preferences
+
 	remailer_overwrite_mode = Column(Enum(RemailerMode), default=None, nullable=True)
 
 	@property
@@ -88,7 +92,7 @@ class ServiceUser(db.Model):
 	# Actual e-mail address that mails from the service are sent to
 	@property
 	def real_email(self):
-		if self.service.enable_email_preferences and self.service_email:
+		if self.has_email_preferences and self.service_email:
 			return self.service_email.address
 		return self.user.primary_email.address
 
@@ -124,6 +128,7 @@ class ServiceUser(db.Model):
 		AliasedPrimaryEmail = db.aliased(UserEmail)
 		AliasedServiceEmail = db.aliased(UserEmail)
 		AliasedService = db.aliased(Service)
+		aliased_user_groups = db.aliased(user_groups)
 
 		query = query.join(cls.user.of_type(AliasedUser))
 		query = query.join(AliasedUser.primary_email.of_type(AliasedPrimaryEmail))
@@ -142,10 +147,21 @@ class ServiceUser(db.Model):
 			],
 			else_=(AliasedService.remailer_mode != RemailerMode.DISABLED)
 		)
+		has_access = db.or_(
+			db.not_(AliasedService.limit_access),
+			db.exists().where(db.and_(
+				aliased_user_groups.c.user_id == AliasedUser.id,
+				aliased_user_groups.c.group_id == AliasedService.access_group_id,
+			))
+		)
+		has_email_preferences = db.and_(
+			has_access,
+			AliasedService.enable_email_preferences,
+		)
 		real_email_matches = db.case(
 			whens=[
 				# pylint: disable=singleton-comparison
-				(db.and_(AliasedService.enable_email_preferences, cls.service_email != None), AliasedServiceEmail.address == email),
+				(db.and_(has_email_preferences, cls.service_email != None), AliasedServiceEmail.address == email),
 			],
 			else_=(AliasedPrimaryEmail.address == email)
 		)
diff --git a/uffd/templates/selfservice/self.html b/uffd/templates/selfservice/self.html
index 6fcb2ed2..6e032d5b 100644
--- a/uffd/templates/selfservice/self.html
+++ b/uffd/templates/selfservice/self.html
@@ -74,12 +74,14 @@
 
 <hr>
 
+{% set service_users_with_email_prefs = user.service_users|selectattr('has_email_preferences')|list %}
+{% set collapse_email_prefs = service_users_with_email_prefs|length > 2 %}
 <div class="row">
 	<div class="col-12 col-md-5">
 		<h5>{{_("E-Mail Preferences")}}</h5>
 		<p>
 			{{ _("Choose your primary e-mail address and the address password recovery e-mails will be sent to.") }}
-			{% if user.service_users|map(attribute='service')|selectattr('enable_email_preferences')|list|length %}
+			{% if service_users_with_email_prefs %}
 			{{ _("You can also select different addresses for different services.") }}
 			{% endif %}
 		</p>
@@ -104,8 +106,7 @@
 					{% endfor %}
 				</select>
 			</div>
-			{% set collapse_email_prefs = user.service_users|map(attribute='service')|selectattr('enable_email_preferences')|list|length > 2 %}
-			{% for service_user in user.service_users if service_user.service.enable_email_preferences %}
+			{% for service_user in service_users_with_email_prefs %}
 			{% if collapse_email_prefs and loop.index == 2 %}
 			<div id="collapsed-email-prefs">
 			{% endif %}
diff --git a/uffd/templates/service/show.html b/uffd/templates/service/show.html
index 5277fa41..08d03ba0 100644
--- a/uffd/templates/service/show.html
+++ b/uffd/templates/service/show.html
@@ -31,6 +31,16 @@
 			</select>
 		</div>
 
+		<div class="form-group col">
+			<div class="form-check">
+				<input class="form-check-input" type="checkbox" id="service-enable-email-preferences" name="enable_email_preferences" value="1" aria-label="enabled" {{ 'checked' if service.enable_email_preferences }}>
+				<label class="form-check-label" for="service-enable-email-preferences">{{ _('Allow users with access to select a different e-mail address for this service') }}</label>
+			<small class="form-text text-muted">
+				{{ _('If disabled, the service always uses the primary e-mail address.') }}
+			</small>
+			</div>
+		</div>
+
 		<div class="form-group col">
 			<label for="remailer-mode">
 				{{ _('Hide e-mail addresses with remailer') }}
@@ -78,16 +88,6 @@
 			</small>
 		</div>
 
-		<div class="form-group col">
-			<div class="form-check">
-				<input class="form-check-input" type="checkbox" id="service-enable-email-preferences" name="enable_email_preferences" value="1" aria-label="enabled" {{ 'checked' if service.enable_email_preferences }}>
-				<label class="form-check-label" for="service-enable-email-preferences">{{ _('Allow users to select a different e-mail address for this service') }}</label>
-			<small class="form-text text-muted">
-				{{ _('If disabled, the service always uses the primary e-mail address.') }}
-			</small>
-			</div>
-		</div>
-
 	</form>
 
 	{% if service.id %}
diff --git a/uffd/templates/user/show.html b/uffd/templates/user/show.html
index bc22d8e5..7a4f265d 100644
--- a/uffd/templates/user/show.html
+++ b/uffd/templates/user/show.html
@@ -146,7 +146,7 @@
 					{% endfor %}
 				</select>
 			</div>
-			{% for service_user in user.service_users if service_user.service.enable_email_preferences %}
+			{% for service_user in user.service_users if service_user.has_email_preferences %}
 			<div class="form-group col">
 				<label>{{ _("Address for %(name)s", name=service_user.service.name) }}</label>
 				<select name="service_{{ service_user.service.id }}_email" class="form-control">
diff --git a/uffd/translations/de/LC_MESSAGES/messages.mo b/uffd/translations/de/LC_MESSAGES/messages.mo
index 0897f2eba472b656935ffde9314eb66162e0fef2..18d96bb2f77e2483e726cbbf418892af96e7fd69 100644
GIT binary patch
delta 6382
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
boRvQ}vqT}PG`%P@ElnY@G;Om+bc!<o40bq9

delta 6360
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
Ik4|w00LWrE3jhEB

diff --git a/uffd/translations/de/LC_MESSAGES/messages.po b/uffd/translations/de/LC_MESSAGES/messages.po
index 5738094a..667d221f 100644
--- a/uffd/translations/de/LC_MESSAGES/messages.po
+++ b/uffd/translations/de/LC_MESSAGES/messages.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PROJECT VERSION\n"
 "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2022-11-06 01:46+0100\n"
+"POT-Creation-Date: 2022-11-08 20:12+0100\n"
 "PO-Revision-Date: 2021-05-25 21:18+0200\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language: de\n"
@@ -160,7 +160,7 @@ msgstr "GID"
 #: uffd/templates/mfa/setup.html:157 uffd/templates/mfa/setup.html:158
 #: uffd/templates/mfa/setup.html:169 uffd/templates/role/list.html:14
 #: uffd/templates/rolemod/list.html:9 uffd/templates/rolemod/show.html:44
-#: uffd/templates/selfservice/self.html:189
+#: uffd/templates/selfservice/self.html:190
 #: uffd/templates/service/index.html:14 uffd/templates/service/show.html:20
 #: uffd/templates/service/show.html:133 uffd/templates/user/show.html:193
 #: uffd/templates/user/show.html:225
@@ -170,7 +170,7 @@ msgstr "Name"
 #: uffd/templates/group/list.html:16 uffd/templates/group/show.html:33
 #: uffd/templates/invite/new.html:36 uffd/templates/role/list.html:15
 #: uffd/templates/role/show.html:48 uffd/templates/rolemod/list.html:10
-#: uffd/templates/rolemod/show.html:26 uffd/templates/selfservice/self.html:190
+#: uffd/templates/rolemod/show.html:26 uffd/templates/selfservice/self.html:191
 #: uffd/templates/user/show.html:194 uffd/templates/user/show.html:226
 msgid "Description"
 msgstr "Beschreibung"
@@ -195,7 +195,7 @@ msgstr "Abbrechen"
 
 #: uffd/templates/group/show.html:11 uffd/templates/role/show.html:19
 #: uffd/templates/role/show.html:21 uffd/templates/selfservice/self.html:61
-#: uffd/templates/selfservice/self.html:204 uffd/templates/service/api.html:11
+#: uffd/templates/selfservice/self.html:205 uffd/templates/service/api.html:11
 #: uffd/templates/service/oauth2.html:11 uffd/templates/service/show.html:12
 #: uffd/templates/user/show.html:29 uffd/templates/user/show.html:181
 msgid "Are you sure?"
@@ -459,7 +459,7 @@ msgstr ""
 msgid "One address per line"
 msgstr "Eine Adresse pro Zeile"
 
-#: uffd/templates/mfa/auth.html:6 uffd/templates/selfservice/self.html:158
+#: uffd/templates/mfa/auth.html:6 uffd/templates/selfservice/self.html:159
 #: uffd/templates/user/show.html:176
 msgid "Two-Factor Authentication"
 msgstr "Zwei-Faktor-Authentifizierung"
@@ -567,11 +567,11 @@ msgstr ""
 msgid "Disable two-factor authentication"
 msgstr "Zwei-Faktor-Authentifizierung (2FA) deaktivieren"
 
-#: uffd/templates/mfa/setup.html:18 uffd/templates/selfservice/self.html:164
+#: uffd/templates/mfa/setup.html:18 uffd/templates/selfservice/self.html:165
 msgid "Two-factor authentication is currently <strong>enabled</strong>."
 msgstr "Die Zwei-Faktor-Authentifizierung ist derzeit <strong>aktiviert</strong>."
 
-#: uffd/templates/mfa/setup.html:20 uffd/templates/selfservice/self.html:166
+#: uffd/templates/mfa/setup.html:20 uffd/templates/selfservice/self.html:167
 msgid "Two-factor authentication is currently <strong>disabled</strong>."
 msgstr ""
 "Die Zwei-Faktor-Authentifizierung ist derzeit "
@@ -1059,11 +1059,11 @@ msgstr "Primäre E-Mail-Adresse kann nicht gelöscht werden"
 msgid "Retry verification"
 msgstr "Bestätigungslink neusenden"
 
-#: uffd/templates/selfservice/self.html:79
+#: uffd/templates/selfservice/self.html:81
 msgid "E-Mail Preferences"
 msgstr "E-Mail-Einstellungen"
 
-#: uffd/templates/selfservice/self.html:81
+#: uffd/templates/selfservice/self.html:83
 msgid ""
 "Choose your primary e-mail address and the address password recovery "
 "e-mails will be sent to."
@@ -1071,50 +1071,50 @@ msgstr ""
 "Wähle deine primäre Adresse und die Adresse für Passwort-"
 "Zurücksetzen-E-Mails aus."
 
-#: uffd/templates/selfservice/self.html:83
+#: uffd/templates/selfservice/self.html:85
 msgid "You can also select different addresses for different services."
 msgstr ""
 "Du kannst für unterschiedliche Dienste unterschiedliche Adressen "
 "verwenden."
 
-#: uffd/templates/selfservice/self.html:86
+#: uffd/templates/selfservice/self.html:88
 msgid "Adresses must be verified before you can select them here."
 msgstr "Adressen müssen bestätigt sein, damit du sie hier auswählen kannst."
 
-#: uffd/templates/selfservice/self.html:91
+#: uffd/templates/selfservice/self.html:93
 msgid "Primary Address"
 msgstr "Primäre Adresse"
 
-#: uffd/templates/selfservice/self.html:99
+#: uffd/templates/selfservice/self.html:101
 msgid "Address for Password Reset E-Mails"
 msgstr "Adresse für Passwort-Zurücksetzen-E-Mails"
 
-#: uffd/templates/selfservice/self.html:101
-#: uffd/templates/selfservice/self.html:115 uffd/templates/user/show.html:143
+#: uffd/templates/selfservice/self.html:103
+#: uffd/templates/selfservice/self.html:116 uffd/templates/user/show.html:143
 #: uffd/templates/user/show.html:153
 msgid "Use primary address"
 msgstr "Primäre Adresse verwenden"
 
-#: uffd/templates/selfservice/self.html:113
+#: uffd/templates/selfservice/self.html:114
 #, python-format
 msgid "Address for Service \"%(name)s\""
 msgstr "Adresse für Dienst „%(name)s“"
 
-#: uffd/templates/selfservice/self.html:124
+#: uffd/templates/selfservice/self.html:125
 msgid "Show more settings ..."
 msgstr "Weitere Einstellungen anzeigen ..."
 
-#: uffd/templates/selfservice/self.html:126
+#: uffd/templates/selfservice/self.html:127
 msgid "Update E-Mail Preferences"
 msgstr "E-Mail-Einstellungen speichern"
 
-#: uffd/templates/selfservice/self.html:135
+#: uffd/templates/selfservice/self.html:136
 #: uffd/templates/session/login.html:16 uffd/templates/signup/start.html:36
 #: uffd/templates/user/show.html:163
 msgid "Password"
 msgstr "Passwort"
 
-#: uffd/templates/selfservice/self.html:136
+#: uffd/templates/selfservice/self.html:137
 msgid ""
 "Your login password for the Single-Sign-On. Only enter it on the Single-"
 "Sign-On login page! No other legit websites will ask you for this "
@@ -1125,22 +1125,22 @@ msgstr ""
 " Webseite wird dich nach diesem Passwort fragen. Es wird auch niemals für"
 " Support-Anfragen benötigt."
 
-#: uffd/templates/selfservice/self.html:141
+#: uffd/templates/selfservice/self.html:142
 #: uffd/templates/selfservice/set_password.html:9
 msgid "New Password"
 msgstr "Neues Passwort"
 
-#: uffd/templates/selfservice/self.html:147
+#: uffd/templates/selfservice/self.html:148
 #: uffd/templates/selfservice/set_password.html:16
 #: uffd/templates/signup/start.html:43
 msgid "Repeat Password"
 msgstr "Passwort wiederholen"
 
-#: uffd/templates/selfservice/self.html:149
+#: uffd/templates/selfservice/self.html:150
 msgid "Change Password"
 msgstr "Passwort ändern"
 
-#: uffd/templates/selfservice/self.html:159
+#: uffd/templates/selfservice/self.html:160
 msgid ""
 "Setting up Two-Factor Authentication (2FA) adds an additional step to the"
 " Single-Sign-On login and increases the security of your account "
@@ -1150,17 +1150,17 @@ msgstr ""
 "Anmeldung im Single-Sign-On hinzu und verbessert damit die Sicherheit "
 "deines Accounts erheblich."
 
-#: uffd/templates/selfservice/self.html:169
+#: uffd/templates/selfservice/self.html:170
 msgid "Manage two-factor authentication"
 msgstr "Zwei-Faktor-Authentifizierung (2FA) verwalten"
 
-#: uffd/templates/selfservice/self.html:177 uffd/templates/user/list.html:20
+#: uffd/templates/selfservice/self.html:178 uffd/templates/user/list.html:20
 #: uffd/templates/user/show.html:39 uffd/templates/user/show.html:188
 #: uffd/views/role.py:21
 msgid "Roles"
 msgstr "Rollen"
 
-#: uffd/templates/selfservice/self.html:178
+#: uffd/templates/selfservice/self.html:179
 msgid ""
 "Aside from a set of base permissions, your roles determine the "
 "permissions of your account."
@@ -1168,7 +1168,7 @@ msgstr ""
 "Deine Berechtigungen werden, von einigen Basis-Berechtigungen abgesehen, "
 "von deinen Rollen bestimmt"
 
-#: uffd/templates/selfservice/self.html:180
+#: uffd/templates/selfservice/self.html:181
 #, python-format
 msgid ""
 "See <a href=\"%(services_url)s\">Services</a> for an overview of your "
@@ -1177,13 +1177,13 @@ msgstr ""
 "Auf <a href=\"%(services_url)s\">Dienste</a> erhälst du einen Überblick "
 "über deine aktuellen Berechtigungen."
 
-#: uffd/templates/selfservice/self.html:184
+#: uffd/templates/selfservice/self.html:185
 msgid "Administrators and role moderators can invite you to new roles."
 msgstr ""
 "Accounts mit Adminrechten oder Rollen-Moderationsrechten können dich zu "
 "Rollen einladen."
 
-#: uffd/templates/selfservice/self.html:199
+#: uffd/templates/selfservice/self.html:200
 msgid ""
 "Some permissions in this role require you to setup two-factor "
 "authentication"
@@ -1191,11 +1191,11 @@ msgstr ""
 "Einige Berechtigungen dieser Rolle erfordern das Einrichten von Zwei-"
 "Faktor-Authentifikation"
 
-#: uffd/templates/selfservice/self.html:205
+#: uffd/templates/selfservice/self.html:206
 msgid "Leave"
 msgstr "Verlassen"
 
-#: uffd/templates/selfservice/self.html:212
+#: uffd/templates/selfservice/self.html:213
 msgid "You currently don't have any roles"
 msgstr "Du hast derzeit keine Rollen"
 
@@ -1231,7 +1231,7 @@ msgstr "Zugriff auf Mail-Weiterleitungen"
 msgid "Resolve remailer addresses"
 msgstr "Auflösen von Remailer-Adressen"
 
-#: uffd/templates/service/api.html:51 uffd/templates/service/show.html:38
+#: uffd/templates/service/api.html:51 uffd/templates/service/show.html:48
 msgid "This option has no effect: Remailer config options are unset"
 msgstr "Diese Option hat keine Auswirkung: Remailer ist nicht konfiguriert"
 
@@ -1308,25 +1308,37 @@ msgstr "Alle Account haben Zugriff (veraltet)"
 msgid "Members of group \"%(group_name)s\" have access"
 msgstr "Mitglieder der Gruppe \"%(group_name)s\" haben Zugriff"
 
-#: uffd/templates/service/show.html:36
+#: uffd/templates/service/show.html:37
+msgid ""
+"Allow users with access to select a different e-mail address for this "
+"service"
+msgstr ""
+"Ermögliche Nutzern mit Zugriff auf diesen Dienst eine andere E-Mail-"
+"Adresse auszuwählen"
+
+#: uffd/templates/service/show.html:39
+msgid "If disabled, the service always uses the primary e-mail address."
+msgstr "Wenn deaktiviert, wird immer die primäre E-Mail-Adresse verwendet."
+
+#: uffd/templates/service/show.html:46
 msgid "Hide e-mail addresses with remailer"
 msgstr "E-Mail-Adressen mit Remailer verstecken"
 
-#: uffd/templates/service/show.html:43 uffd/templates/service/show.html:66
+#: uffd/templates/service/show.html:53 uffd/templates/service/show.html:76
 msgid "Remailer disabled"
 msgstr "Remailer deaktiviert"
 
-#: uffd/templates/service/show.html:46 uffd/templates/service/show.html:69
+#: uffd/templates/service/show.html:56 uffd/templates/service/show.html:79
 msgid "Remailer enabled"
 msgstr "Remailer aktiviert"
 
-#: uffd/templates/service/show.html:49 uffd/templates/service/show.html:72
+#: uffd/templates/service/show.html:59 uffd/templates/service/show.html:82
 msgid "Remailer enabled (deprecated, case-sensitive format)"
 msgstr ""
 "Remailer aktiviert (veraltetes, Groß-/Kleinschreibung-unterscheidendes "
 "Format)"
 
-#: uffd/templates/service/show.html:53
+#: uffd/templates/service/show.html:63
 msgid ""
 "Some services notify users about changes to their e-mail address. "
 "Modifying this setting immediatly affects the e-mail addresses of all "
@@ -1337,15 +1349,15 @@ msgstr ""
 "-Mail-Adressen aller Nutzer aus und kann zu massenhaftem Versand von "
 "Benachrichtigungs-E-Mails führen."
 
-#: uffd/templates/service/show.html:59
+#: uffd/templates/service/show.html:69
 msgid "Overwrite remailer setting for specific users"
 msgstr "Überschreibe Remailer-Einstellung für ausgewählte Nutzer"
 
-#: uffd/templates/service/show.html:62
+#: uffd/templates/service/show.html:72
 msgid "Login names"
 msgstr "Anmeldenamen"
 
-#: uffd/templates/service/show.html:77
+#: uffd/templates/service/show.html:87
 msgid ""
 "Useful for testing remailer before enabling it for all users. Specify "
 "users as a comma-seperated list of login names."
@@ -1353,16 +1365,6 @@ msgstr ""
 "Hilfreich zum Testen des Remailers vor dem Aktivieren für alle Nutzer. Um"
 " Nutzer auszuwählen, liste ihre Anmeldenamen mit Komma getrennt auf."
 
-#: uffd/templates/service/show.html:84
-msgid "Allow users to select a different e-mail address for this service"
-msgstr ""
-"Ermögliche Nutzern für diesen Dienst eine andere E-Mail-Adresse "
-"auszuwählen"
-
-#: uffd/templates/service/show.html:86
-msgid "If disabled, the service always uses the primary e-mail address."
-msgstr "Wenn deaktiviert, wird immer die primäre E-Mail-Adresse verwendet."
-
 #: uffd/templates/session/deviceauth.html:15
 msgid "Log into a service on another device without entering your password."
 msgstr ""
diff --git a/uffd/views/selfservice.py b/uffd/views/selfservice.py
index b4cbd4c8..3459d01a 100644
--- a/uffd/views/selfservice.py
+++ b/uffd/views/selfservice.py
@@ -187,7 +187,7 @@ def update_email_preferences():
 	else:
 		request.user.recovery_email = verified_emails.filter_by(id=request.form['recovery_email']).one()
 	for service_user in request.user.service_users:
-		if not service_user.service.enable_email_preferences:
+		if not service_user.has_email_preferences:
 			continue
 		value = request.form.get(f'service_{service_user.service.id}_email', 'primary')
 		if value == 'primary':
diff --git a/uffd/views/user.py b/uffd/views/user.py
index b3ba6788..04fb953b 100644
--- a/uffd/views/user.py
+++ b/uffd/views/user.py
@@ -113,7 +113,7 @@ def update(id):
 	else:
 		user.recovery_email = verified_emails.filter_by(id=request.form['recovery_email']).one()
 	for service_user in user.service_users:
-		if not service_user.service.enable_email_preferences:
+		if not service_user.has_email_preferences:
 			continue
 		value = request.form.get(f'service_{service_user.service.id}_email', 'primary')
 		if value == 'primary':
-- 
GitLab