Files
espresso_frame/server/tests/test_widget_lock.py
T
tfaour 9911151d8d
Build and push server image / test (push) Successful in 33s
Build and push server image / build-and-push (push) Successful in 2m32s
Build and push server image / deploy (push) Successful in 57s
Add per-photo-widget lock (freezes current photo until unlocked)
A "Lock this photo" button in the photos widget's dialog toggles
PhotoWidgetConfig.locked, which suppresses both the timer-elapsed
auto-advance and the advance/back button actions until unlocked. The
Layout tab canvas shows a lock badge on any locked photo widget's box.
2026-07-27 21:07:54 +00:00

101 lines
4.3 KiB
Python

"""routers/api_widgets.py's POST .../lock endpoint (models.PhotoWidgetConfig.
locked) -- same permission shape as test_widget_border.py's own endpoint,
just for a photos-only field instead of a shared Widget-level one."""
from __future__ import annotations
import time
from app.models import Frame, PhotoWidgetConfig, StaticWidgetConfig, Widget
from .conftest import csrf_headers, link_user, login, make_user
def _widget_id(db_session, widget_type="photos") -> int:
return db_session.query(Widget).filter_by(frame_id=1, widget_type=widget_type).one().id
def test_new_widget_defaults_to_unlocked(db_session):
widget_id = _widget_id(db_session)
assert db_session.get(PhotoWidgetConfig, widget_id).locked is False
def test_set_lock_persists(client, db_session):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
widget_id = _widget_id(db_session)
resp = client.post(f"/api/frames/1/widgets/{widget_id}/lock",
json={"locked": True}, headers=csrf_headers(client))
assert resp.status_code == 200, resp.text
assert resp.json() == {"status": "saved", "locked": True}
assert db_session.get(PhotoWidgetConfig, widget_id).locked is True
resp = client.post(f"/api/frames/1/widgets/{widget_id}/lock",
json={"locked": False}, headers=csrf_headers(client))
assert resp.status_code == 200, resp.text
assert db_session.get(PhotoWidgetConfig, widget_id).locked is False
def test_set_lock_404s_for_unknown_widget(client, db_session):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
resp = client.post("/api/frames/1/widgets/999999/lock",
json={"locked": True}, headers=csrf_headers(client))
assert resp.status_code == 404
def test_set_lock_rejects_non_photos_widget(client, db_session):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
# Built directly rather than through the placement-validated create
# endpoint -- the default frame's photos widget already covers the
# whole grid, and overlap isn't the thing under test here.
static_widget = Widget(frame_id=1, widget_type="static", x=0, y=0, w=1, h=1,
sort_order=99, created_at=time.time())
db_session.add(static_widget)
db_session.flush()
db_session.add(StaticWidgetConfig(widget_id=static_widget.id))
db_session.commit()
resp = client.post(f"/api/frames/1/widgets/{static_widget.id}/lock",
json={"locked": True}, headers=csrf_headers(client))
assert resp.status_code == 400
def test_set_lock_unrelated_user_404s(client, db_session):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
make_user(db_session, "mallory")
widget_id = _widget_id(db_session)
client.cookies.clear()
login(client, "mallory")
resp = client.post(f"/api/frames/1/widgets/{widget_id}/lock",
json={"locked": True}, headers=csrf_headers(client))
assert resp.status_code == 404
assert db_session.get(PhotoWidgetConfig, widget_id).locked is False
def test_set_lock_linked_but_not_controlling_user_409s(client, db_session):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
bob = make_user(db_session, "bob")
frame = db_session.get(Frame, 1)
link_user(db_session, bob, frame)
widget_id = _widget_id(db_session)
client.cookies.clear()
login(client, "bob")
resp = client.post(f"/api/frames/1/widgets/{widget_id}/lock",
json={"locked": True}, headers=csrf_headers(client))
assert resp.status_code == 409
assert resp.json()["detail"]["error"] == "not_controller"
def test_widgets_list_reports_locked_state(client, db_session):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
widget_id = _widget_id(db_session)
resp = client.get("/api/frames/1/widgets")
assert resp.status_code == 200, resp.text
assert next(w for w in resp.json()["widgets"] if w["id"] == widget_id)["locked"] is False
client.post(f"/api/frames/1/widgets/{widget_id}/lock",
json={"locked": True}, headers=csrf_headers(client))
resp = client.get("/api/frames/1/widgets")
assert next(w for w in resp.json()["widgets"] if w["id"] == widget_id)["locked"] is True