forked from retoor/devplacepy
Add personal notes, DeepSearch history, backup offload, and gateway auth throttling
Also streamline the top navigation: drop the Tools dropdown, make Quizzes and Battles icon-only entries, and remove the Workspace, Containers and Editor entry points from the project detail page.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
import uuid_utils
|
||||
|
||||
from devplacepy.database import get_table
|
||||
from devplacepy.services.messaging import active_conversation
|
||||
|
||||
|
||||
def _make_user():
|
||||
uid = str(uuid_utils.uuid7())
|
||||
get_table("users").insert(
|
||||
{
|
||||
"uid": uid,
|
||||
"username": f"actconv_{uid[:8]}",
|
||||
"email": f"{uid[:8]}@actconv.test",
|
||||
"terms_version": "1",
|
||||
}
|
||||
)
|
||||
return uid
|
||||
|
||||
|
||||
def test_touch_writes_marker_then_throttles(local_db):
|
||||
viewer = _make_user()
|
||||
other = _make_user()
|
||||
active_conversation._last_write.pop(f"{viewer}:{other}", None)
|
||||
|
||||
active_conversation.touch_active_conversation(viewer, other)
|
||||
row = get_table("users").find_one(uid=viewer)
|
||||
assert row["active_conversation_uid"] == other
|
||||
first_stamp = row["active_conversation_at"]
|
||||
assert first_stamp
|
||||
|
||||
active_conversation.touch_active_conversation(viewer, other)
|
||||
assert get_table("users").find_one(uid=viewer)["active_conversation_at"] == first_stamp
|
||||
|
||||
active_conversation._last_write[f"{viewer}:{other}"] = (
|
||||
active_conversation.time.monotonic()
|
||||
- active_conversation.WRITE_THROTTLE_SECONDS
|
||||
- 1
|
||||
)
|
||||
active_conversation.touch_active_conversation(viewer, other)
|
||||
second_stamp = get_table("users").find_one(uid=viewer)["active_conversation_at"]
|
||||
assert second_stamp >= first_stamp
|
||||
|
||||
|
||||
def test_touch_is_a_noop_without_both_uids(local_db):
|
||||
viewer = _make_user()
|
||||
active_conversation.touch_active_conversation("", "someone")
|
||||
active_conversation.touch_active_conversation(viewer, "")
|
||||
row = get_table("users").find_one(uid=viewer)
|
||||
assert not row.get("active_conversation_uid")
|
||||
|
||||
|
||||
def test_is_actively_viewing_true_when_fresh(local_db):
|
||||
viewer = _make_user()
|
||||
other = _make_user()
|
||||
get_table("users").update(
|
||||
{
|
||||
"uid": viewer,
|
||||
"active_conversation_uid": other,
|
||||
"active_conversation_at": datetime.now(timezone.utc).isoformat(),
|
||||
},
|
||||
["uid"],
|
||||
)
|
||||
assert active_conversation.is_actively_viewing(viewer, other) is True
|
||||
|
||||
|
||||
def test_is_actively_viewing_false_when_stale(local_db):
|
||||
viewer = _make_user()
|
||||
other = _make_user()
|
||||
stale = datetime.now(timezone.utc) - timedelta(
|
||||
seconds=active_conversation.FRESH_SECONDS + 5
|
||||
)
|
||||
get_table("users").update(
|
||||
{
|
||||
"uid": viewer,
|
||||
"active_conversation_uid": other,
|
||||
"active_conversation_at": stale.isoformat(),
|
||||
},
|
||||
["uid"],
|
||||
)
|
||||
assert active_conversation.is_actively_viewing(viewer, other) is False
|
||||
|
||||
|
||||
def test_is_actively_viewing_false_for_a_different_conversation(local_db):
|
||||
viewer = _make_user()
|
||||
other = _make_user()
|
||||
someone_else = _make_user()
|
||||
get_table("users").update(
|
||||
{
|
||||
"uid": viewer,
|
||||
"active_conversation_uid": someone_else,
|
||||
"active_conversation_at": datetime.now(timezone.utc).isoformat(),
|
||||
},
|
||||
["uid"],
|
||||
)
|
||||
assert active_conversation.is_actively_viewing(viewer, other) is False
|
||||
|
||||
|
||||
def test_is_actively_viewing_false_when_missing_or_unknown(local_db):
|
||||
assert active_conversation.is_actively_viewing("", "other") is False
|
||||
assert active_conversation.is_actively_viewing("viewer", "") is False
|
||||
assert active_conversation.is_actively_viewing(str(uuid_utils.uuid7()), "other") is False
|
||||
@@ -4,7 +4,24 @@ from datetime import datetime, timezone
|
||||
|
||||
from devplacepy.database import get_table
|
||||
from devplacepy.utils import generate_uid
|
||||
from devplacepy.services.messaging.persist import stamp_content_revision
|
||||
from devplacepy.services.messaging.persist import persist_message, stamp_content_revision
|
||||
|
||||
|
||||
def _make_user(prefix):
|
||||
uid = generate_uid()
|
||||
get_table("users").insert(
|
||||
{
|
||||
"uid": uid,
|
||||
"username": f"{prefix}_{uid[:8]}",
|
||||
"email": f"{uid[:8]}@{prefix}.test",
|
||||
"terms_version": "1",
|
||||
}
|
||||
)
|
||||
return uid
|
||||
|
||||
|
||||
def _sender(uid):
|
||||
return {"uid": uid, "username": "sender", "role": "Member"}
|
||||
|
||||
|
||||
def test_stamp_content_revision_sets_updated_at(local_db):
|
||||
@@ -26,3 +43,84 @@ def test_stamp_content_revision_sets_updated_at(local_db):
|
||||
stored = get_table("messages").find_one(uid=uid)
|
||||
assert stored["updated_at"] == row["updated_at"]
|
||||
assert stored["content"] == "hello"
|
||||
|
||||
|
||||
def test_persist_message_dedupes_same_sender_and_client_id(local_db):
|
||||
sender_uid = _make_user("dedupe_sender")
|
||||
receiver_uid = _make_user("dedupe_receiver")
|
||||
sender = _sender(sender_uid)
|
||||
client_id = f"cid-{generate_uid()}"
|
||||
|
||||
first = persist_message(sender, receiver_uid, "hello once", client_id=client_id)
|
||||
assert first is not None
|
||||
|
||||
second = persist_message(sender, receiver_uid, "hello once", client_id=client_id)
|
||||
assert second is not None
|
||||
assert second["uid"] == first["uid"]
|
||||
|
||||
rows = list(
|
||||
get_table("messages").find(sender_uid=sender_uid, receiver_uid=receiver_uid)
|
||||
)
|
||||
assert len(rows) == 1
|
||||
|
||||
|
||||
def test_persist_message_does_not_dedupe_without_client_id(local_db):
|
||||
sender_uid = _make_user("nodedupe_sender")
|
||||
receiver_uid = _make_user("nodedupe_receiver")
|
||||
sender = _sender(sender_uid)
|
||||
|
||||
first = persist_message(sender, receiver_uid, "no client id here")
|
||||
second = persist_message(sender, receiver_uid, "no client id here")
|
||||
assert first["uid"] != second["uid"]
|
||||
|
||||
rows = list(
|
||||
get_table("messages").find(sender_uid=sender_uid, receiver_uid=receiver_uid)
|
||||
)
|
||||
assert len(rows) == 2
|
||||
|
||||
|
||||
def test_persist_message_does_not_dedupe_a_different_client_id(local_db):
|
||||
sender_uid = _make_user("diffid_sender")
|
||||
receiver_uid = _make_user("diffid_receiver")
|
||||
sender = _sender(sender_uid)
|
||||
|
||||
first = persist_message(sender, receiver_uid, "a", client_id="cid-a")
|
||||
second = persist_message(sender, receiver_uid, "b", client_id="cid-b")
|
||||
assert first["uid"] != second["uid"]
|
||||
|
||||
|
||||
def test_persist_message_suppresses_notification_when_receiver_is_actively_viewing(local_db):
|
||||
sender_uid = _make_user("active_sender")
|
||||
receiver_uid = _make_user("active_receiver")
|
||||
sender = _sender(sender_uid)
|
||||
|
||||
get_table("users").update(
|
||||
{
|
||||
"uid": receiver_uid,
|
||||
"active_conversation_uid": sender_uid,
|
||||
"active_conversation_at": datetime.now(timezone.utc).isoformat(),
|
||||
},
|
||||
["uid"],
|
||||
)
|
||||
|
||||
result = persist_message(sender, receiver_uid, "are you watching?", client_id="cid-watch")
|
||||
assert result is not None
|
||||
|
||||
notifications = list(
|
||||
get_table("notifications").find(user_uid=receiver_uid, type="message")
|
||||
)
|
||||
assert notifications == []
|
||||
|
||||
|
||||
def test_persist_message_notifies_when_receiver_is_not_actively_viewing(local_db):
|
||||
sender_uid = _make_user("inactive_sender")
|
||||
receiver_uid = _make_user("inactive_receiver")
|
||||
sender = _sender(sender_uid)
|
||||
|
||||
result = persist_message(sender, receiver_uid, "hello there", client_id="cid-plain")
|
||||
assert result is not None
|
||||
|
||||
notifications = list(
|
||||
get_table("notifications").find(user_uid=receiver_uid, type="message")
|
||||
)
|
||||
assert len(notifications) == 1
|
||||
|
||||
Reference in New Issue
Block a user