Owner accounts: auth, password reset, CRM dashboard visibility (#19)
Flask-session login scoped to one client_id (never a request param), self-service + operator-triggered password reset via single-use tokens, and an Owner accounts tab on the CRM dashboard. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -234,3 +234,30 @@ def test_consume_expired_password_reset_token_fails():
|
||||
|
||||
def test_consume_unknown_token_fails():
|
||||
assert bdb.consume_password_reset_token("not-a-real-token", "new-password") is None
|
||||
|
||||
|
||||
# ---- login lookup / operator listing (#19) ----
|
||||
|
||||
def test_find_user_by_email_is_not_tenant_scoped():
|
||||
"""Login happens before client_id is known -- find_user_by_email looks up
|
||||
by the globally-unique email alone, unlike get_user_by_email."""
|
||||
u = bdb.create_user(CLIENT_A, "owner@example.com", "pw12345")
|
||||
found = bdb.find_user_by_email("owner@example.com")
|
||||
assert found["user_id"] == u["user_id"]
|
||||
assert bdb.find_user_by_email("nobody@example.com") is None
|
||||
|
||||
|
||||
def test_get_user_by_id():
|
||||
u = bdb.create_user(CLIENT_A, "owner@example.com", "pw12345")
|
||||
assert bdb.get_user(u["user_id"])["email"] == "owner@example.com"
|
||||
assert bdb.get_user("U-does-not-exist") is None
|
||||
|
||||
|
||||
def test_list_users_scoped_and_unscoped():
|
||||
a = bdb.create_user(CLIENT_A, "a@example.com", "pw12345")
|
||||
bdb.create_user(CLIENT_B, "b@example.com", "pw12345")
|
||||
scoped = bdb.list_users(CLIENT_A)
|
||||
assert [r["user_id"] for r in scoped] == [a["user_id"]]
|
||||
everyone = bdb.list_users()
|
||||
assert {r["client_id"] for r in everyone} == {CLIENT_A, CLIENT_B}
|
||||
assert "password_hash" not in everyone[0]
|
||||
|
||||
Reference in New Issue
Block a user