# retoor import requests from tests.conftest import BASE_URL def _seed_news_seo(): from datetime import datetime, timezone from devplacepy.database import get_table from devplacepy.utils import generate_uid, make_combined_slug uid = generate_uid() title = f"SEO Test News Article {uid.split('-')[-1]}" slug = make_combined_slug(title, uid) get_table("news").insert( { "deleted_at": None, "deleted_by": None, "uid": uid, "slug": slug, "title": title, "description": "A seeded news article for SEO tests.", "content": "Body content for the seeded article.", "url": "https://example.com/article", "source_name": "ExampleSource", "status": "published", "synced_at": datetime.now(timezone.utc).isoformat(), "show_on_landing": 0, "grade": 8, } ) return slug, uid def _seed_owner(): from datetime import datetime, timezone from uuid import uuid4 from devplacepy.database import get_table uid = str(uuid4()) get_table("users").insert( { "uid": uid, "username": f"seo_{uid[:8]}", "email": f"{uid[:8]}@seo.test", "password_hash": "x", "role": "Member", "is_active": True, "created_at": datetime.now(timezone.utc).isoformat(), } ) return uid def _seed_post_seo(image=None): from datetime import datetime, timezone from uuid import uuid4 from devplacepy.database import get_table from devplacepy.utils import make_combined_slug owner = _seed_owner() uid = str(uuid4()) slug = make_combined_slug("SEO Detail Post", uid) get_table("posts").insert( { "deleted_at": None, "deleted_by": None, "uid": uid, "user_uid": owner, "slug": slug, "title": "SEO Detail Post", "content": "Body text for the SEO detail post.", "topic": "general", "project_uid": None, "image": image, "stars": 0, "created_at": datetime.now(timezone.utc).isoformat(), } ) return slug, uid def _seed_gist(): from datetime import datetime, timezone from uuid import uuid4 from devplacepy.database import get_table from devplacepy.utils import make_combined_slug owner = _seed_owner() uid = str(uuid4()) slug = make_combined_slug("SEO Detail Gist", uid) get_table("gists").insert( { "deleted_at": None, "deleted_by": None, "uid": uid, "user_uid": owner, "slug": slug, "title": "SEO Detail Gist", "description": "Gist description for SEO tests.", "source_code": "print('seo')", "language": "python", "stars": 0, "created_at": datetime.now(timezone.utc).isoformat(), } ) return slug, uid def _seed_project(): from datetime import datetime, timezone from uuid import uuid4 from devplacepy.database import get_table from devplacepy.utils import make_combined_slug owner = _seed_owner() uid = str(uuid4()) slug = make_combined_slug("SEO Detail Project", uid) get_table("projects").insert( { "deleted_at": None, "deleted_by": None, "uid": uid, "user_uid": owner, "slug": slug, "title": "SEO Detail Project", "description": "Project description for SEO tests.", "project_type": "software", "platforms": "Linux", "status": "Released", "stars": 0, "created_at": datetime.now(timezone.utc).isoformat(), } ) return slug, uid def _seed_news_image(news_uid): from devplacepy.database import get_table get_table("news_images").insert( { "deleted_at": None, "deleted_by": None, "news_uid": news_uid, "url": "https://example.com/seo-news-image.jpg", } ) def _seed_feed_posts(count): from datetime import datetime, timezone, timedelta from uuid import uuid4 from devplacepy.database import get_table from devplacepy.utils import make_combined_slug owner = _seed_owner() topic = f"seopag{owner[:8]}" base = datetime(2026, 1, 1, tzinfo=timezone.utc) posts = get_table("posts") for i in range(count): uid = str(uuid4()) posts.insert( { "deleted_at": None, "deleted_by": None, "uid": uid, "user_uid": owner, "slug": make_combined_slug(f"seo pag {i}", uid), "title": None, "content": f"seo pag post {i}", "topic": topic, "project_uid": None, "image": None, "stars": 0, "created_at": (base - timedelta(seconds=i)).isoformat(), } ) return topic def test_missing_profile_returns_404(app_server): r = requests.get(f"{BASE_URL}/profile/no-such-user-xyz", allow_redirects=False) assert r.status_code == 404 def _seed_comment_on_post(commenter_uid): from datetime import datetime, timezone from uuid import uuid4 from devplacepy.database import get_table post_slug, post_uid = _seed_post_seo() comment_uid = str(uuid4()) get_table("comments").insert( { "deleted_at": None, "deleted_by": None, "uid": comment_uid, "target_type": "post", "target_uid": post_uid, "post_uid": post_uid, "user_uid": commenter_uid, "content": "Activity tab link comment body", "parent_uid": None, "created_at": datetime.now(timezone.utc).isoformat(), } ) return post_slug, post_uid, comment_uid def test_activity_comment_exposes_parent_post_url(app_server): from devplacepy.database import get_table, refresh_snapshot commenter = _seed_owner() username = get_table("users").find_one(uid=commenter)["username"] post_slug, _post_uid, comment_uid = _seed_comment_on_post(commenter) refresh_snapshot() r = requests.get( f"{BASE_URL}/profile/{username}?tab=activity", headers={"Accept": "application/json"}, ) assert r.status_code == 200 activities = r.json()["activities"] comment_acts = [a for a in activities if a.get("type") == "comment"] assert comment_acts, "expected a comment activity" act = comment_acts[0] assert act["url"] == f"/posts/{post_slug}#comment-{comment_uid}" assert act["target_type"] == "post" def test_activity_comment_url_matches_notification_target(app_server): from devplacepy.database import get_table, refresh_snapshot, resolve_object_url commenter = _seed_owner() username = get_table("users").find_one(uid=commenter)["username"] _post_slug, post_uid, comment_uid = _seed_comment_on_post(commenter) refresh_snapshot() expected = f"{resolve_object_url('post', post_uid)}#comment-{comment_uid}" r = requests.get( f"{BASE_URL}/profile/{username}?tab=activity", headers={"Accept": "application/json"}, ) act = [a for a in r.json()["activities"] if a.get("type") == "comment"][0] assert act["url"] == expected def test_activity_post_exposes_url(app_server): from datetime import datetime, timezone from devplacepy.database import get_table, refresh_snapshot owner = _seed_owner() username = get_table("users").find_one(uid=owner)["username"] post_slug, post_uid = _seed_post_seo() get_table("posts").update({"uid": post_uid, "user_uid": owner}, ["uid"]) refresh_snapshot() r = requests.get( f"{BASE_URL}/profile/{username}?tab=activity", headers={"Accept": "application/json"}, ) assert r.status_code == 200 post_acts = [a for a in r.json()["activities"] if a.get("type") == "post"] assert post_acts, "expected a post activity" assert post_acts[0]["url"] == f"/posts/{post_slug}" def test_activity_comment_card_renders_overlay_link(app_server): from devplacepy.database import get_table, refresh_snapshot commenter = _seed_owner() username = get_table("users").find_one(uid=commenter)["username"] post_slug, _post_uid, comment_uid = _seed_comment_on_post(commenter) refresh_snapshot() r = requests.get(f"{BASE_URL}/profile/{username}?tab=activity") assert r.status_code == 200 assert "activity-card card-link-host" in r.text assert f'class="card-link" href="/posts/{post_slug}#comment-{comment_uid}"' in r.text def test_profile_json_exposes_online_presence(app_server): import time name = f"pres{int(time.time() * 1000)}" session = requests.Session() session.post( f"{BASE_URL}/auth/signup", data={ "username": name, "email": f"{name}@t.dev", "password": "secret123", "confirm_password": "secret123", }, allow_redirects=True, ) r = session.get( f"{BASE_URL}/profile/{name}", headers={"Accept": "application/json"} ) assert r.status_code == 200 body = r.json() assert body["profile_online"] is True assert body["profile_user"]["last_seen"] def test_profile_json_offline_when_last_seen_stale(app_server): from datetime import datetime, timezone, timedelta from devplacepy.config import PRESENCE_TIMEOUT_SECONDS from devplacepy.database import get_table, refresh_snapshot owner = _seed_owner() username = get_table("users").find_one(uid=owner)["username"] stale = ( datetime.now(timezone.utc) - timedelta(seconds=PRESENCE_TIMEOUT_SECONDS + 120) ).isoformat() get_table("users").update({"uid": owner, "last_seen": stale}, ["uid"]) refresh_snapshot() r = requests.get( f"{BASE_URL}/profile/{username}", headers={"Accept": "application/json"} ) assert r.status_code == 200 body = r.json() assert body["profile_online"] is False assert body["profile_user"]["last_seen"] == stale def test_profile_hero_avatar_has_presence_dot(app_server): import time from devplacepy.database import get_table, refresh_snapshot name = f"phero{int(time.time() * 1000)}" s = requests.Session() s.post( f"{BASE_URL}/auth/signup", data={ "username": name, "email": f"{name}@t.dev", "password": "secret123", "confirm_password": "secret123", }, allow_redirects=True, ) refresh_snapshot() uid = get_table("users").find_one(username=name)["uid"] html = s.get(f"{BASE_URL}/profile/{name}").text assert "profile-avatar-wrap" in html assert "presence-dot" in html assert f'data-presence-uid="{uid}"' in html def test_followers_list_avatar_has_presence_dot(app_server): import time from devplacepy.database import get_table, refresh_snapshot stamp = int(time.time() * 1000) target = f"folt{stamp}" follower = f"folf{stamp}" st = requests.Session() sf = requests.Session() for sess, name in ((st, target), (sf, follower)): sess.post( f"{BASE_URL}/auth/signup", data={ "username": name, "email": f"{name}@t.dev", "password": "secret123", "confirm_password": "secret123", }, allow_redirects=True, ) sf.post(f"{BASE_URL}/follow/{target}", allow_redirects=True) refresh_snapshot() follower_uid = get_table("users").find_one(username=follower)["uid"] html = st.get(f"{BASE_URL}/profile/{target}?tab=followers").text assert "follow-user" in html assert f'data-presence-uid="{follower_uid}"' in html assert "data-presence-last-seen" in html def test_viewing_profile_marks_notification_read(app_server): import time from datetime import datetime, timezone from devplacepy.database import get_table, refresh_snapshot from devplacepy.utils import generate_uid name = f"nmark{int(time.time() * 1000)}" session = requests.Session() session.post( f"{BASE_URL}/auth/signup", data={ "username": name, "email": f"{name}@t.dev", "password": "secret123", "confirm_password": "secret123", }, allow_redirects=True, ) refresh_snapshot() user = get_table("users").find_one(username=name) notif_uid = generate_uid() get_table("notifications").insert( { "uid": notif_uid, "user_uid": user["uid"], "type": "follow", "message": "someone followed you", "related_uid": generate_uid(), "target_url": f"/profile/{name}", "read": False, "created_at": datetime.now(timezone.utc).isoformat(), } ) refresh_snapshot() r = session.get(f"{BASE_URL}/profile/{name}", allow_redirects=True) assert r.status_code == 200 refresh_snapshot() assert bool(get_table("notifications").find_one(uid=notif_uid)["read"]) is True