# retoor import time from datetime import datetime, timezone import requests from tests.conftest import BASE_URL from devplacepy.database import get_table from devplacepy.utils import generate_uid _counter_notes = [0] AJAX_notes = {"X-Requested-With": "fetch"} def _session_notes(): _counter_notes[0] += 1 name = f"nte{int(time.time() * 1000)}{_counter_notes[0]}" s = requests.Session() s.post( f"{BASE_URL}/auth/signup", data={ "username": name, "email": f"{name}@t.dev", "password": "secret123", "confirm_password": "secret123", "birth_date": "1990-01-01", "accept_terms": "1", }, allow_redirects=True, ) return s, name def _uid_notes(username): return get_table("users").find_one(username=username)["uid"] def _make_post_notes(owner_uid, title): uid = generate_uid() get_table("posts").insert( { "deleted_at": None, "deleted_by": None, "uid": uid, "user_uid": owner_uid, "slug": f"{uid[-8:]}-note-post", "title": title, "content": "note target content", "topic": "random", "project_uid": None, "image": None, "stars": 0, "created_at": datetime.now(timezone.utc).isoformat(), } ) return uid def test_note_set_creates_row(app_server): s, name = _session_notes() post_uid = _make_post_notes(_uid_notes(name), "Note target") r = s.post( f"{BASE_URL}/notes/post/{post_uid}", headers=AJAX_notes, data={"content": "Remember to check this later."}, ) assert r.status_code == 200 assert r.json()["content"] == "Remember to check this later." row = get_table("notes").find_one( user_uid=_uid_notes(name), target_uid=post_uid, deleted_at=None ) assert row is not None assert row["content"] == "Remember to check this later." def test_note_set_replaces_existing_content(app_server): s, name = _session_notes() post_uid = _make_post_notes(_uid_notes(name), "Note replace target") s.post( f"{BASE_URL}/notes/post/{post_uid}", headers=AJAX_notes, data={"content": "First draft."}, ) s.post( f"{BASE_URL}/notes/post/{post_uid}", headers=AJAX_notes, data={"content": "Second draft."}, ) rows = list( get_table("notes").find( user_uid=_uid_notes(name), target_uid=post_uid, deleted_at=None ) ) assert len(rows) == 1 assert rows[0]["content"] == "Second draft." def test_note_delete_soft_deletes(app_server): s, name = _session_notes() post_uid = _make_post_notes(_uid_notes(name), "Note delete target") s.post( f"{BASE_URL}/notes/post/{post_uid}", headers=AJAX_notes, data={"content": "Delete me."}, ) r = s.post(f"{BASE_URL}/notes/post/{post_uid}/delete", headers=AJAX_notes) assert r.json() == {"deleted": True} assert ( get_table("notes").count( user_uid=_uid_notes(name), target_uid=post_uid, deleted_at=None ) == 0 ) row = get_table("notes").find_one(user_uid=_uid_notes(name), target_uid=post_uid) assert row is not None assert row["deleted_at"] is not None assert row["deleted_by"] == _uid_notes(name) def test_note_revives_after_delete(app_server): s, name = _session_notes() post_uid = _make_post_notes(_uid_notes(name), "Note revive target") s.post( f"{BASE_URL}/notes/post/{post_uid}", headers=AJAX_notes, data={"content": "Before delete."}, ) s.post(f"{BASE_URL}/notes/post/{post_uid}/delete", headers=AJAX_notes) s.post( f"{BASE_URL}/notes/post/{post_uid}", headers=AJAX_notes, data={"content": "After revive."}, ) rows = list(get_table("notes").find(user_uid=_uid_notes(name), target_uid=post_uid)) assert len(rows) == 1 assert rows[0]["deleted_at"] is None assert rows[0]["content"] == "After revive." def test_note_requires_login(app_server): owner_s, owner_name = _session_notes() post_uid = _make_post_notes(_uid_notes(owner_name), "Needs login") anon = requests.Session() r = anon.post( f"{BASE_URL}/notes/post/{post_uid}", headers=AJAX_notes, data={"content": "sneaky"}, allow_redirects=False, ) assert r.status_code == 303 assert get_table("notes").count(target_uid=post_uid) == 0 def test_note_invalid_target_type_returns_400(app_server): s, name = _session_notes() post_uid = _make_post_notes(_uid_notes(name), "Bad target") r = s.post( f"{BASE_URL}/notes/widget/{post_uid}", headers=AJAX_notes, data={"content": "does not matter"}, ) assert r.status_code == 400 def test_note_is_private_per_user(app_server): alice, alice_name = _session_notes() bob, bob_name = _session_notes() post_uid = _make_post_notes(_uid_notes(alice_name), "Shared target") alice.post( f"{BASE_URL}/notes/post/{post_uid}", headers=AJAX_notes, data={"content": "Alice's private note."}, ) bob.post( f"{BASE_URL}/notes/post/{post_uid}", headers=AJAX_notes, data={"content": "Bob's private note."}, ) alice_row = get_table("notes").find_one( user_uid=_uid_notes(alice_name), target_uid=post_uid, deleted_at=None ) bob_row = get_table("notes").find_one( user_uid=_uid_notes(bob_name), target_uid=post_uid, deleted_at=None ) assert alice_row["content"] == "Alice's private note." assert bob_row["content"] == "Bob's private note." bob_view = bob.get( f"{BASE_URL}/posts/{post_uid}", headers={"Accept": "application/json"} ) assert bob_view.json()["note_content"] == "Bob's private note." def test_note_delete_only_affects_own_row(app_server): alice, alice_name = _session_notes() bob, bob_name = _session_notes() post_uid = _make_post_notes(_uid_notes(alice_name), "Delete isolation target") alice.post( f"{BASE_URL}/notes/post/{post_uid}", headers=AJAX_notes, data={"content": "Alice keeps this."}, ) bob.post(f"{BASE_URL}/notes/post/{post_uid}/delete", headers=AJAX_notes) alice_row = get_table("notes").find_one( user_uid=_uid_notes(alice_name), target_uid=post_uid, deleted_at=None ) assert alice_row is not None assert alice_row["content"] == "Alice keeps this."