Skip to content

Commit 2caa14a

Browse files
aapelivclaude
andcommitted
Backend: migrate notification translations and email ICS attachments toggles to feature flags
Move ENABLE_NOTIFICATION_TRANSLATIONS and ENABLE_EMAIL_ICS_ATTACHMENTS from env config onto per-user feature flags (notification_translations_enabled, email_ics_attachments_enabled, both defaulting True). Both are evaluated for the recipient user in the notification-email job via make_background_user_context, since that context has the user in scope; the ICS decision is threaded into render_email_notification as a keyword argument to keep the renderer pure. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent f3e159d commit 2caa14a

6 files changed

Lines changed: 49 additions & 11 deletions

File tree

app/backend.dev.env

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ SMS_SENDER_ID=invalid
3333
NOTIFICATION_EMAIL_SENDER=Couchers.org
3434
NOTIFICATION_EMAIL_ADDRESS=notify@couchers.org.invalid
3535
NOTIFICATION_PREFIX='[DEV] '
36-
ENABLE_NOTIFICATION_TRANSLATIONS=1
37-
ENABLE_EMAIL_ICS_ATTACHMENTS=1
3836

3937
REPORTS_EMAIL_RECIPIENT=reports@couchers.org.invalid
4038
CONTRIBUTOR_FORM_EMAIL_RECIPIENT=forms@couchers.org.invalid

app/backend/src/couchers/config.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@
6464
("NOTIFICATION_EMAIL_ADDRESS", str),
6565
# An optional prefix for email subject, e.g. [STAGING]
6666
("NOTIFICATION_PREFIX", str, ""),
67-
("ENABLE_NOTIFICATION_TRANSLATIONS", bool),
68-
("ENABLE_EMAIL_ICS_ATTACHMENTS", bool),
6967
# Address to send emails about reported users
7068
("REPORTS_EMAIL_RECIPIENT", str),
7169
# Address to send contributor forms when users sign up/fill the form

app/backend/src/couchers/notifications/background.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,18 @@ def _send_email_notification(session: Session, user: User, notification: Notific
4141
logger.info(f"Tried emailing {user} based on notification {notification.topic_action} but user is deleted")
4242
return
4343

44+
context = make_background_user_context(user.id)
45+
4446
loc_context = LocalizationContext.from_user(user)
45-
if not config["ENABLE_NOTIFICATION_TRANSLATIONS"]:
47+
if not context.get_boolean_value("notification_translations_enabled", default=True):
4648
loc_context = dataclasses.replace(loc_context, locale="en")
4749

48-
rendered = render_email_notification(user, notification, loc_context)
50+
rendered = render_email_notification(
51+
user,
52+
notification,
53+
loc_context,
54+
include_ics_attachments=context.get_boolean_value("email_ics_attachments_enabled", default=True),
55+
)
4956

5057
queue_email(
5158
session,

app/backend/src/couchers/notifications/render_email.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class RenderedEmailNotification:
4141

4242

4343
def render_email_notification(
44-
user: User, notification: Notification, loc_context: LocalizationContext
44+
user: User, notification: Notification, loc_context: LocalizationContext, *, include_ics_attachments: bool
4545
) -> RenderedEmailNotification:
4646
footer = get_email_footer(user, notification, loc_context)
4747

@@ -90,7 +90,7 @@ def render_email_notification(
9090
source_data = config["VERSION"] + f"/{custom_templated.template_name}"
9191

9292
list_unsubscribe_header = get_list_unsubscribe_header(notification)
93-
if config.get("ENABLE_EMAIL_ICS_ATTACHMENTS"):
93+
if include_ics_attachments:
9494
attachment = get_ics_attachment(notification, loc_context)
9595
else:
9696
attachment = None

app/backend/src/tests/conftest.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,6 @@ def testconfig():
173173
config["REPORTS_EMAIL_RECIPIENT"] = "reports@couchers.org.invalid"
174174
config["CONTRIBUTOR_FORM_EMAIL_RECIPIENT"] = "forms@couchers.org.invalid"
175175
config["MODS_EMAIL_RECIPIENT"] = "mods@couchers.org.invalid"
176-
config["ENABLE_EMAIL_ICS_ATTACHMENTS"] = True
177176

178177
config["STRIPE_API_KEY"] = ""
179178
config["STRIPE_WEBHOOK_SECRET"] = ""
@@ -246,8 +245,6 @@ def testconfig():
246245
config["SLACK_DONATIONS_CHANNEL"] = ""
247246
config["SLACK_MERCH_CHANNEL"] = ""
248247

249-
config["ENABLE_NOTIFICATION_TRANSLATIONS"] = False
250-
251248
yield None
252249

253250
config.clear()

app/backend/src/tests/test_calendar_events.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,44 @@ def test_host_request_attachments(db, moderator: Moderator):
175175
assert ics_event.status == "CANCELLED"
176176

177177

178+
def test_host_request_attachments_disabled(db, feature_flags, moderator: Moderator):
179+
feature_flags.set("email_ics_attachments_enabled", False)
180+
181+
host, host_token = generate_user(complete_profile=True)
182+
surfer, surfer_token = generate_user(complete_profile=True)
183+
184+
from_date = today() + timedelta(days=2)
185+
to_date = today() + timedelta(days=3)
186+
187+
with requests_session(surfer_token) as api:
188+
hr_id = api.CreateHostRequest(
189+
requests_pb2.CreateHostRequestReq(
190+
host_user_id=host.id,
191+
from_date=from_date.isoformat(),
192+
to_date=to_date.isoformat(),
193+
text=valid_request_text("can i stay plz"),
194+
)
195+
).host_request_id
196+
197+
with mock_notification_email():
198+
moderator.approve_host_request(hr_id)
199+
200+
# Host accepts: normally the surfer would get a calendar attachment, but the flag is off
201+
with requests_session(host_token) as api:
202+
with mock_notification_email() as mock:
203+
api.RespondHostRequest(
204+
requests_pb2.RespondHostRequestReq(
205+
host_request_id=hr_id,
206+
status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED,
207+
text="Accepting host request",
208+
)
209+
)
210+
211+
e = email_fields(mock)
212+
assert "accept" in e.subject and host.name in e.subject
213+
assert not e.attachments
214+
215+
178216
def _get_email_ics_attachment_calendar_event(e) -> ics.Event:
179217
assert len(e.attachments or []) == 1
180218
ics_attachment = e.attachments[0]

0 commit comments

Comments
 (0)