A tab names the account it was claimed for on every request, beacon and upload (X-Siftlode-Expect-Account); current_user and /auth/logout refuse a mismatch with 401 account_changed and keep the session, so a tab left showing the account signed in before reloads instead of writing to the new one. /auth/login clears a connect marker left by an abandoned connect, and a link completes only on a session that still holds. The prefs merge reads the row under a lock. A tab's sessionStorage records its own owner. A page the account loses is given up, address bar and remembered page included. The panel layouts are preferences; the storage contract also refuses a key handed to the Storage API or to usePref outside its kind. A refused sign-in as someone else and a failed sign-out say so. The chromium-only e2e specs are in the gate register, the member walk waits for its requests, and devices.spec checks the save itself.
45 lines
1.7 KiB
Python
45 lines
1.7 KiB
Python
"""PUT /api/me/preferences merges the keys it is sent into the stored ones, DB-lane.
|
|
|
|
A client saves its preferences a key at a time, and several at once on the boot that moves this
|
|
browser's copies to the account. Each merge must start from the row as stored when it runs, not as
|
|
the request first read it — two merges over the same earlier read keep only the last one's keys.
|
|
"""
|
|
|
|
from fastapi import Depends, Request
|
|
from sqlalchemy import update
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.auth import current_user
|
|
from app.db import SessionLocal, get_db
|
|
from app.models import User
|
|
|
|
_PW = "correct horse battery"
|
|
|
|
|
|
def test_a_save_keeps_a_key_another_save_stored_after_this_one_read_the_account(
|
|
client, db, make_user, override_dep
|
|
):
|
|
user = make_user(email="prefs@example.com", password=_PW)
|
|
assert (
|
|
client.post("/auth/password-login", json={"email": "prefs@example.com", "password": _PW})
|
|
).status_code == 200
|
|
|
|
def read_then_another_save(request: Request, session: Session = Depends(get_db)) -> User:
|
|
# The account as this request reads it, then a second save committing in the meantime.
|
|
caller = current_user(request, session)
|
|
with SessionLocal() as other:
|
|
other.execute(
|
|
update(User)
|
|
.where(User.id == caller.id)
|
|
.values(preferences={"seenVersion": "1.2.3"})
|
|
)
|
|
other.commit()
|
|
return caller
|
|
|
|
override_dep(current_user, read_then_another_save)
|
|
r = client.put("/api/me/preferences", json={"startOnHome": False})
|
|
|
|
assert r.status_code == 200
|
|
db.expire_all()
|
|
assert db.get(User, user.id).preferences == {"seenVersion": "1.2.3", "startOnHome": False}
|