fix(messages): the welcome reads in the reader's language, not the one it was created in
E31 S1: the welcome is rendered once, at account creation, so an account that switched language kept it in the old one (the owner's, English under a Hungarian UI). A stored copy is recognised by its opening line (derived from WELCOME) and served in the reader's language; other system messages stay as stored.
This commit is contained in:
@@ -94,13 +94,30 @@ def _system_partner() -> dict:
|
||||
return {"id": SYSTEM_PARTNER_ID, "name": SYSTEM_NAME, "avatar_url": None}
|
||||
|
||||
|
||||
def _serialize_msg(m: Message) -> dict:
|
||||
# The welcome's opening line in every language — how a stored copy is recognised. It was rendered
|
||||
# once, in the language of the day it was created, so an account that later switched language kept
|
||||
# reading it in the old one (E31 S1: the owner's, in English). Recognised here, it is served in the
|
||||
# reader's language instead. Derived from WELCOME itself, so only a change to an OPENING line would
|
||||
# orphan the copies already stored.
|
||||
_WELCOME_OPENINGS = {text.partition("\n")[0] for text in WELCOME.values()}
|
||||
|
||||
|
||||
def _system_body(body: str | None, lang: str | None) -> str | None:
|
||||
"""A system message's text for a reader of `lang`: the welcome in their language, any other as
|
||||
stored."""
|
||||
if body is None or lang is None or body.partition("\n")[0] not in _WELCOME_OPENINGS:
|
||||
return body
|
||||
return WELCOME.get(lang, WELCOME["en"])
|
||||
|
||||
|
||||
def _serialize_msg(m: Message, lang: str | None = None) -> dict:
|
||||
"""`lang`: the reader's language, for a system message's text (a user message is ciphertext)."""
|
||||
return {
|
||||
"id": m.id,
|
||||
"kind": m.kind,
|
||||
"sender_id": m.sender_id,
|
||||
"recipient_id": m.recipient_id,
|
||||
"body": m.body, # only set for system messages
|
||||
"body": _system_body(m.body, lang) if m.kind == "system" else m.body,
|
||||
"ciphertext": m.ciphertext,
|
||||
"iv": m.iv,
|
||||
"read_at": iso(m.read_at),
|
||||
@@ -124,7 +141,7 @@ def ensure_welcome(db: Session, user: User) -> None:
|
||||
db.add(m)
|
||||
db.commit()
|
||||
db.refresh(m)
|
||||
manager.push(user.id, {"type": "message", "message": _serialize_msg(m)})
|
||||
manager.push(user.id, {"type": "message", "message": _serialize_msg(m, lang_for_user(user))})
|
||||
|
||||
|
||||
# --- E2EE key directory / blob store -----------------------------------------
|
||||
@@ -313,7 +330,7 @@ def list_conversations(user: User = Depends(require_human), db: Session = Depend
|
||||
items.append(
|
||||
{
|
||||
"partner": partner,
|
||||
"last_message": _serialize_msg(m),
|
||||
"last_message": _serialize_msg(m, lang_for_user(user)),
|
||||
"unread": int(unread.get(pid, 0)),
|
||||
}
|
||||
)
|
||||
@@ -366,7 +383,7 @@ def get_thread(
|
||||
# refreshes live instead of waiting for the next 20s poll. The client re-fetches the
|
||||
# count on this signal, so no number is carried here.
|
||||
manager.push(user.id, {"type": "unread"})
|
||||
return {"partner": partner, "items": [_serialize_msg(m) for m in msgs]}
|
||||
return {"partner": partner, "items": [_serialize_msg(m, lang_for_user(user)) for m in msgs]}
|
||||
|
||||
|
||||
@router.post("")
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
"""E31 S1: the welcome message is rendered once, when the account is created, in the language of that day.
|
||||
An account that switched language afterwards kept reading it in the old one (the owner's: English under a
|
||||
Hungarian UI). It is served in the reader's language now; any other system message stays as stored.
|
||||
Needs the DB."""
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
import app.state as state
|
||||
from app.auth import current_user
|
||||
from app.db import get_db
|
||||
from app.main import app
|
||||
from app.models import Message, User
|
||||
from app.routes.messages import WELCOME
|
||||
|
||||
|
||||
def _client(db, user, monkeypatch, override_dep) -> TestClient:
|
||||
monkeypatch.setattr(state, "_configured_cache", True)
|
||||
override_dep(get_db, db.info["request"])
|
||||
override_dep(current_user, lambda: user)
|
||||
return TestClient(app)
|
||||
|
||||
|
||||
def _user_with_english_welcome(db) -> User:
|
||||
"""An account whose welcome was written in English, then switched to Hungarian."""
|
||||
user = User(email="welcome-hu@example.com", preferences={"language": "hu"})
|
||||
db.add(user)
|
||||
db.flush()
|
||||
db.add(Message(kind="system", sender_id=None, recipient_id=user.id, body=WELCOME["en"]))
|
||||
db.commit()
|
||||
return user
|
||||
|
||||
|
||||
def test_the_welcome_is_read_in_the_readers_language(db, monkeypatch, override_dep):
|
||||
user = _user_with_english_welcome(db)
|
||||
client = _client(db, user, monkeypatch, override_dep)
|
||||
|
||||
thread = client.get("/api/messages/conversations/0").json()["items"]
|
||||
assert [m["body"] for m in thread] == [WELCOME["hu"]]
|
||||
|
||||
convs = client.get("/api/messages/conversations").json()["items"]
|
||||
assert [c["last_message"]["body"] for c in convs if c["partner"]["id"] == 0] == [WELCOME["hu"]]
|
||||
|
||||
|
||||
def test_another_system_message_is_served_as_stored(db, monkeypatch, override_dep):
|
||||
user = _user_with_english_welcome(db)
|
||||
db.add(
|
||||
Message(kind="system", sender_id=None, recipient_id=user.id, body="Maintenance tonight.")
|
||||
)
|
||||
db.commit()
|
||||
client = _client(db, user, monkeypatch, override_dep)
|
||||
|
||||
bodies = [m["body"] for m in client.get("/api/messages/conversations/0").json()["items"]]
|
||||
assert bodies == [WELCOME["hu"], "Maintenance tonight."]
|
||||
Reference in New Issue
Block a user