This commit is contained in:
parent
fe0ed5b7e6
commit
347e5f0f31
@ -338,6 +338,46 @@ def get_gist_languages() -> set[str]:
|
||||
return codes
|
||||
|
||||
|
||||
_STARRED_CONTENT_TABLES = ("posts", "projects", "gists")
|
||||
|
||||
_top_authors_cache = TTLCache(ttl=60)
|
||||
|
||||
|
||||
def get_top_authors(limit: int = 5) -> list:
|
||||
cached = _top_authors_cache.get("top")
|
||||
if cached is not None:
|
||||
return cached
|
||||
sources = [table for table in _STARRED_CONTENT_TABLES if table in db.tables]
|
||||
if not sources:
|
||||
_top_authors_cache.set("top", [])
|
||||
return []
|
||||
union = " UNION ALL ".join(f"SELECT user_uid, stars FROM {table}" for table in sources)
|
||||
rows = db.query(
|
||||
f"SELECT user_uid, SUM(stars) AS total FROM ({union}) "
|
||||
f"GROUP BY user_uid HAVING total > 0 ORDER BY total DESC LIMIT {int(limit)}"
|
||||
)
|
||||
ranked = [(row["user_uid"], row["total"]) for row in rows]
|
||||
users_map = get_users_by_uids([uid for uid, _ in ranked])
|
||||
authors = []
|
||||
for uid, total in ranked:
|
||||
user = users_map.get(uid)
|
||||
if user:
|
||||
author = dict(user)
|
||||
author["stars"] = total
|
||||
authors.append(author)
|
||||
_top_authors_cache.set("top", authors)
|
||||
return authors
|
||||
|
||||
|
||||
def get_user_stars(user_uid: str) -> int:
|
||||
total = 0
|
||||
for table in _STARRED_CONTENT_TABLES:
|
||||
if table in db.tables:
|
||||
for row in db.query(f"SELECT COALESCE(SUM(stars), 0) AS s FROM {table} WHERE user_uid = :u", u=user_uid):
|
||||
total += row["s"] or 0
|
||||
return total
|
||||
|
||||
|
||||
def resolve_by_slug(table, slug):
|
||||
entry = table.find_one(slug=slug)
|
||||
if not entry:
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import logging
|
||||
from fastapi import APIRouter, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
from devplacepy.database import get_table, get_daily_topic, get_users_by_uids, get_comment_counts_by_post_uids, get_site_stats
|
||||
from devplacepy.database import get_table, get_daily_topic, get_users_by_uids, get_comment_counts_by_post_uids, get_site_stats, get_top_authors
|
||||
from devplacepy.attachments import get_attachments_batch
|
||||
from devplacepy.content import enrich_items
|
||||
from devplacepy.templating import templates
|
||||
@ -60,9 +60,8 @@ def get_feed_posts(user, tab: str = "all", topic: str = None, before: str = None
|
||||
async def feed_page(request: Request, tab: str = "all", topic: str = None, before: str = None):
|
||||
user = get_current_user(request)
|
||||
posts, next_cursor = get_feed_posts(user, tab, topic, before)
|
||||
users_table = get_table("users")
|
||||
stats = get_site_stats()
|
||||
top_authors = list(users_table.find(stars={">": 0}, order_by=["-stars"], _limit=5))
|
||||
top_authors = get_top_authors(5)
|
||||
daily_topic = get_daily_topic()
|
||||
|
||||
post_uids_list = [item["post"]["uid"] for item in posts]
|
||||
|
||||
@ -3,7 +3,7 @@ from typing import Annotated
|
||||
from fastapi import APIRouter, Request, Form
|
||||
from devplacepy.models import ProfileForm
|
||||
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
|
||||
from devplacepy.database import get_table, db
|
||||
from devplacepy.database import get_table, db, get_user_stars
|
||||
from devplacepy.templating import templates
|
||||
from devplacepy.utils import get_current_user, require_user, require_user_api, time_ago, clear_user_cache
|
||||
from devplacepy.seo import base_seo_context, site_url, website_schema, profile_page_schema
|
||||
@ -35,6 +35,7 @@ async def profile_page(request: Request, username: str, tab: str = "posts"):
|
||||
profile_user = users.find_one(username=username)
|
||||
if not profile_user:
|
||||
return RedirectResponse(url="/feed", status_code=302)
|
||||
profile_user["stars"] = get_user_stars(profile_user["uid"])
|
||||
|
||||
posts = []
|
||||
if tab == "posts":
|
||||
|
||||
@ -49,6 +49,22 @@ def test_post_vote_increment(alice):
|
||||
assert count == "1", f"expected vote count 1, got {count!r}"
|
||||
|
||||
|
||||
def _profile_stars(page, username):
|
||||
page.goto(f"{BASE_URL}/profile/{username}", wait_until="domcontentloaded")
|
||||
value = page.locator(".profile-stat:has(.profile-stat-label:has-text('Stars')) .profile-stat-value").first
|
||||
return int(value.text_content().strip())
|
||||
|
||||
|
||||
def test_profile_stars_reflect_content_votes(alice):
|
||||
page, user = alice
|
||||
before = _profile_stars(page, user["username"])
|
||||
create_post(page, "devlog", "Reputation contribution post")
|
||||
page.locator(".post-action-btn.vote-up").first.click()
|
||||
page.wait_for_url(f"{BASE_URL}/posts/*", wait_until="domcontentloaded")
|
||||
after = _profile_stars(page, user["username"])
|
||||
assert after == before + 1, f"expected stars {before + 1}, got {after}"
|
||||
|
||||
|
||||
def test_post_comments_section(alice):
|
||||
page, _ = alice
|
||||
create_post(page, "rant", "Comment section test")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user