2026-05-10 09:08:12 +02:00
|
|
|
from fastapi.templating import Jinja2Templates
|
2026-05-23 06:20:27 +02:00
|
|
|
from devplacepy.cache import TTLCache
|
2026-05-10 09:08:12 +02:00
|
|
|
from devplacepy.config import TEMPLATES_DIR
|
2026-05-13 21:17:57 +02:00
|
|
|
from devplacepy.constants import TOPICS
|
2026-05-10 09:08:12 +02:00
|
|
|
from devplacepy.database import get_table
|
2026-05-11 03:14:43 +02:00
|
|
|
from devplacepy.avatar import avatar_url
|
2026-05-12 12:45:52 +02:00
|
|
|
from devplacepy.utils import format_date as _format_date
|
feat: add leaderboard router, gamification backfill, and shared content creation helpers
Introduce a new `/leaderboard` endpoint ranking top 50 members by total stars, wire it into the app router and documentation. Implement `_backfill_gamification()` in `database.py` to compute XP/levels for existing accounts from prior posts, comments, votes, and follows. Extract `is_owner()`, `create_content_item()`, and `detail_context()` into `content.py` to centralize content creation, reward awarding, mention notifications, and attachment linking. Update comment creation/deletion in `comments.py` to use `award_rewards()` with `XP_COMMENT` and the new `is_owner()` helper. Add shared template partials documentation for vote bars, star buttons, post headers, and topic selectors to `AGENTS.md`.
2026-05-30 20:16:39 +02:00
|
|
|
from devplacepy.utils import badge_info
|
2026-05-10 09:08:12 +02:00
|
|
|
templates = Jinja2Templates(directory=str(TEMPLATES_DIR))
|
|
|
|
|
|
2026-05-23 06:20:27 +02:00
|
|
|
_unread_cache = TTLCache(ttl=60)
|
2026-05-11 03:14:43 +02:00
|
|
|
|
2026-05-16 02:49:53 +02:00
|
|
|
def clear_unread_cache(user_uid: str) -> None:
|
2026-05-23 06:20:27 +02:00
|
|
|
_unread_cache.pop(user_uid)
|
2026-05-16 02:49:53 +02:00
|
|
|
|
|
|
|
|
|
2026-05-10 09:08:12 +02:00
|
|
|
def jinja_unread_count(user_uid: str) -> int:
|
2026-05-12 12:45:52 +02:00
|
|
|
cached = _unread_cache.get(user_uid)
|
2026-05-23 06:20:27 +02:00
|
|
|
if cached is not None:
|
|
|
|
|
return cached
|
2026-05-10 09:08:12 +02:00
|
|
|
notifs = get_table("notifications")
|
2026-05-23 06:20:27 +02:00
|
|
|
count = notifs.count(user_uid=user_uid, read=False)
|
|
|
|
|
_unread_cache.set(user_uid, count)
|
2026-05-11 03:14:43 +02:00
|
|
|
return count
|
2026-05-10 09:08:12 +02:00
|
|
|
|
|
|
|
|
def jinja_user_projects(user_uid: str) -> list:
|
|
|
|
|
projects = get_table("projects")
|
|
|
|
|
return list(projects.find(user_uid=user_uid))
|
|
|
|
|
|
|
|
|
|
templates.env.globals["get_unread_count"] = jinja_unread_count
|
|
|
|
|
templates.env.globals["get_user_projects"] = jinja_user_projects
|
2026-05-10 21:33:53 +02:00
|
|
|
templates.env.globals["avatar_url"] = avatar_url
|
2026-05-12 12:45:52 +02:00
|
|
|
templates.env.globals["format_date"] = _format_date
|
feat: add leaderboard router, gamification backfill, and shared content creation helpers
Introduce a new `/leaderboard` endpoint ranking top 50 members by total stars, wire it into the app router and documentation. Implement `_backfill_gamification()` in `database.py` to compute XP/levels for existing accounts from prior posts, comments, votes, and follows. Extract `is_owner()`, `create_content_item()`, and `detail_context()` into `content.py` to centralize content creation, reward awarding, mention notifications, and attachment linking. Update comment creation/deletion in `comments.py` to use `award_rewards()` with `XP_COMMENT` and the new `is_owner()` helper. Add shared template partials documentation for vote bars, star buttons, post headers, and topic selectors to `AGENTS.md`.
2026-05-30 20:16:39 +02:00
|
|
|
templates.env.globals["badge_info"] = badge_info
|
2026-05-13 21:17:57 +02:00
|
|
|
templates.env.globals["TOPICS"] = TOPICS
|
2026-05-12 15:07:34 +02:00
|
|
|
def jinja_max_upload_size_mb():
|
2026-05-23 06:55:11 +02:00
|
|
|
from devplacepy.database import get_int_setting
|
|
|
|
|
return get_int_setting("max_upload_size_mb", 10)
|
2026-05-12 15:07:34 +02:00
|
|
|
|
|
|
|
|
def jinja_max_attachments():
|
2026-05-23 06:55:11 +02:00
|
|
|
from devplacepy.database import get_int_setting
|
|
|
|
|
return get_int_setting("max_attachments_per_resource", 10)
|
2026-05-12 15:07:34 +02:00
|
|
|
|
|
|
|
|
def jinja_allowed_file_types():
|
|
|
|
|
from devplacepy.database import get_setting
|
|
|
|
|
return get_setting("allowed_file_types", "")
|
|
|
|
|
|
|
|
|
|
templates.env.globals["max_upload_size_mb"] = jinja_max_upload_size_mb
|
|
|
|
|
templates.env.globals["max_attachments_per_resource"] = jinja_max_attachments
|
|
|
|
|
templates.env.globals["allowed_file_types"] = jinja_allowed_file_types
|
2026-05-13 21:17:57 +02:00
|
|
|
|
|
|
|
|
_LANGUAGE_NAMES = {
|
|
|
|
|
"python": "Python", "javascript": "JavaScript", "typescript": "TypeScript",
|
|
|
|
|
"html": "HTML", "css": "CSS", "c": "C", "cpp": "C++", "java": "Java",
|
|
|
|
|
"go": "Go", "rust": "Rust", "sql": "SQL", "bash": "Bash",
|
|
|
|
|
"yaml": "YAML", "json": "JSON", "markdown": "Markdown",
|
|
|
|
|
"swift": "Swift", "php": "PHP", "ruby": "Ruby", "kotlin": "Kotlin",
|
|
|
|
|
"lua": "Lua", "perl": "Perl", "haskell": "Haskell", "elixir": "Elixir",
|
|
|
|
|
"r": "R", "dart": "Dart", "scala": "Scala", "plaintext": "Plain Text",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def jinja_language_name(code: str) -> str:
|
|
|
|
|
return _LANGUAGE_NAMES.get(code, code)
|
|
|
|
|
|
|
|
|
|
templates.env.globals["language_name"] = jinja_language_name
|
|
|
|
|
|
|
|
|
|
from devplacepy.attachments import format_file_size, file_icon_emoji
|
|
|
|
|
templates.env.globals["format_file_size"] = format_file_size
|
|
|
|
|
templates.env.globals["file_icon_emoji"] = file_icon_emoji
|