2026-05-10 09:08:12 +02:00
|
|
|
import logging
|
feat: replace raw form parsing with pydantic models for auth, admin, bugs, comments, and gists
Migrate all route handlers from manual `request.form()` parsing to typed `Annotated[Model, Form()]` dependencies using new pydantic models (SignupForm, LoginForm, ForgotPasswordForm, AdminRoleForm, AdminPasswordForm, BugForm, CommentForm, GistForm). Remove inline validation logic from signup, login, password reset, admin role/password change, bug creation, comment creation, and gist creation endpoints, delegating validation to model validators and field constraints. Add `RequestValidationError` exception handler with friendly error messages for auth form pages. Update model definitions to use `field_validator` and `model_validator` for cross-field checks like password matching.
2026-05-23 05:44:04 +02:00
|
|
|
from typing import Annotated
|
|
|
|
|
from fastapi import APIRouter, Request, Form
|
|
|
|
|
from devplacepy.models import ProfileForm
|
2026-05-12 13:08:38 +02:00
|
|
|
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
from devplacepy.database import get_table, db, get_user_stars, get_user_rank, get_comment_counts_by_post_uids, get_reactions_by_targets, get_user_bookmarks, get_polls_by_post_uids, get_activity_heatmap, get_activity_months, get_streaks, get_follow_counts, get_follow_list, get_following_among
|
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.content import enrich_items
|
2026-05-10 09:08:12 +02:00
|
|
|
from devplacepy.templating import templates
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
from devplacepy.utils import get_current_user, require_user, require_user_api, time_ago, clear_user_cache, not_found, generate_uid
|
|
|
|
|
from devplacepy.responses import respond, action_result
|
|
|
|
|
from devplacepy.schemas import ProfileOut
|
feat: add canonical redirect, og_image, next_page_url, and sitemap caching across content routers
Implement canonical_redirect helper in content.py to enforce slug-based 301 redirects for gist, news, post, and project detail pages. Add first_image_url helper to extract primary image from item or attachments for Open Graph meta tags. Inject next_page_url into feed, gists, news, and projects list page SEO contexts for pagination link rel. Extend seo.py with SITEMAP_URL_LIMIT, SITEMAP_TTL constants and _sitemap cache variable for future sitemap generation optimization. Update profile page to raise 404 via not_found instead of 302 redirect, and include og_image from avatar_url.
2026-06-05 20:05:07 +02:00
|
|
|
from devplacepy.avatar import avatar_url
|
2026-05-23 08:34:13 +02:00
|
|
|
from devplacepy.seo import base_seo_context, site_url, website_schema, profile_page_schema
|
feat: add project file system with CRUD, upload, inline editing, and video attachment support
- Add new `/projects/{slug}/files` endpoint group for per-project filesystem operations including directory and file CRUD, upload, and inline editing with public read and owner write access
- Extend attachment system to support video formats (webm, ogv, mov, m4v) with proper file icons and MIME types
- Implement configurable allowed file types via `allowed_file_types` site setting, replacing hardcoded `ALLOWED_UPLOAD_TYPES` with dynamic `allowed_extensions()` and `is_extension_allowed()` functions
- Add `delete_all_project_files()` call in `delete_content_item()` to clean up project files when a project is deleted
- Create database indexes on `project_files` table for `(project_uid, path)` and `(project_uid, parent_path)` to optimize file lookups
- Introduce `docs_prose.py` module with `render_prose()` function that renders Markdown content inside `data-render` divs using mistune, enabling dynamic prose rendering in documentation pages
- Enhance docs search with Markdown-aware text stripping (`_demarkdown()`) and improved HTML/script/style sanitization for better search indexing
- Update documentation API samples to reflect new attachment response fields (`is_image`, `is_video`, `mime_type`) and note video format support
- Update README to document the new project files endpoint and clarify AI gateway attribution for guest Devii sessions
2026-06-08 22:51:09 +02:00
|
|
|
from devplacepy.services.manager import service_manager
|
2026-05-10 09:08:12 +02:00
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
|
|
|
|
|
2026-06-09 00:30:25 +02:00
|
|
|
def _ai_quota(user_uid: str, include_cost: bool = False, is_admin: bool = False) -> dict | None:
|
feat: add project file system with CRUD, upload, inline editing, and video attachment support
- Add new `/projects/{slug}/files` endpoint group for per-project filesystem operations including directory and file CRUD, upload, and inline editing with public read and owner write access
- Extend attachment system to support video formats (webm, ogv, mov, m4v) with proper file icons and MIME types
- Implement configurable allowed file types via `allowed_file_types` site setting, replacing hardcoded `ALLOWED_UPLOAD_TYPES` with dynamic `allowed_extensions()` and `is_extension_allowed()` functions
- Add `delete_all_project_files()` call in `delete_content_item()` to clean up project files when a project is deleted
- Create database indexes on `project_files` table for `(project_uid, path)` and `(project_uid, parent_path)` to optimize file lookups
- Introduce `docs_prose.py` module with `render_prose()` function that renders Markdown content inside `data-render` divs using mistune, enabling dynamic prose rendering in documentation pages
- Enhance docs search with Markdown-aware text stripping (`_demarkdown()`) and improved HTML/script/style sanitization for better search indexing
- Update documentation API samples to reflect new attachment response fields (`is_image`, `is_video`, `mime_type`) and note video format support
- Update README to document the new project files endpoint and clarify AI gateway attribution for guest Devii sessions
2026-06-08 22:51:09 +02:00
|
|
|
devii = service_manager.get_service("devii")
|
|
|
|
|
if devii is None:
|
|
|
|
|
return None
|
|
|
|
|
try:
|
2026-06-09 00:30:25 +02:00
|
|
|
limit = devii.daily_limit_for("user", is_admin)
|
feat: add project file system with CRUD, upload, inline editing, and video attachment support
- Add new `/projects/{slug}/files` endpoint group for per-project filesystem operations including directory and file CRUD, upload, and inline editing with public read and owner write access
- Extend attachment system to support video formats (webm, ogv, mov, m4v) with proper file icons and MIME types
- Implement configurable allowed file types via `allowed_file_types` site setting, replacing hardcoded `ALLOWED_UPLOAD_TYPES` with dynamic `allowed_extensions()` and `is_extension_allowed()` functions
- Add `delete_all_project_files()` call in `delete_content_item()` to clean up project files when a project is deleted
- Create database indexes on `project_files` table for `(project_uid, path)` and `(project_uid, parent_path)` to optimize file lookups
- Introduce `docs_prose.py` module with `render_prose()` function that renders Markdown content inside `data-render` divs using mistune, enabling dynamic prose rendering in documentation pages
- Enhance docs search with Markdown-aware text stripping (`_demarkdown()`) and improved HTML/script/style sanitization for better search indexing
- Update documentation API samples to reflect new attachment response fields (`is_image`, `is_video`, `mime_type`) and note video format support
- Update README to document the new project files endpoint and clarify AI gateway attribution for guest Devii sessions
2026-06-08 22:51:09 +02:00
|
|
|
spent = devii.spent_24h("user", user_uid)
|
|
|
|
|
turns = devii.hub().ledger.turns_24h("user", user_uid)
|
|
|
|
|
except Exception:
|
|
|
|
|
logger.exception("Failed to compute AI quota for %s", user_uid)
|
|
|
|
|
return None
|
|
|
|
|
used_pct = round(min(100.0, spent / limit * 100), 1) if limit > 0 else 0.0
|
|
|
|
|
quota = {"used_pct": used_pct, "turns": turns}
|
|
|
|
|
if include_cost:
|
|
|
|
|
quota["spent_usd"] = round(spent, 4)
|
|
|
|
|
quota["limit_usd"] = round(limit, 2)
|
|
|
|
|
return quota
|
|
|
|
|
|
|
|
|
|
|
feat: replace raw form parsing with pydantic models for auth, admin, bugs, comments, and gists
Migrate all route handlers from manual `request.form()` parsing to typed `Annotated[Model, Form()]` dependencies using new pydantic models (SignupForm, LoginForm, ForgotPasswordForm, AdminRoleForm, AdminPasswordForm, BugForm, CommentForm, GistForm). Remove inline validation logic from signup, login, password reset, admin role/password change, bug creation, comment creation, and gist creation endpoints, delegating validation to model validators and field constraints. Add `RequestValidationError` exception handler with friendly error messages for auth form pages. Update model definitions to use `field_validator` and `model_validator` for cross-field checks like password matching.
2026-05-23 05:44:04 +02:00
|
|
|
@router.get("/search")
|
|
|
|
|
async def search_users(request: Request, q: str = ""):
|
2026-05-23 08:34:13 +02:00
|
|
|
require_user_api(request)
|
feat: replace raw form parsing with pydantic models for auth, admin, bugs, comments, and gists
Migrate all route handlers from manual `request.form()` parsing to typed `Annotated[Model, Form()]` dependencies using new pydantic models (SignupForm, LoginForm, ForgotPasswordForm, AdminRoleForm, AdminPasswordForm, BugForm, CommentForm, GistForm). Remove inline validation logic from signup, login, password reset, admin role/password change, bug creation, comment creation, and gist creation endpoints, delegating validation to model validators and field constraints. Add `RequestValidationError` exception handler with friendly error messages for auth form pages. Update model definitions to use `field_validator` and `model_validator` for cross-field checks like password matching.
2026-05-23 05:44:04 +02:00
|
|
|
if not q or len(q) < 1:
|
|
|
|
|
return JSONResponse({"results": []})
|
|
|
|
|
if "users" in db.tables:
|
|
|
|
|
rows = db.query(
|
|
|
|
|
"SELECT uid, username FROM users WHERE username LIKE :q LIMIT 10",
|
|
|
|
|
q=f"%{q}%",
|
|
|
|
|
)
|
|
|
|
|
results = [{"uid": r["uid"], "username": r["username"]} for r in rows]
|
|
|
|
|
else:
|
|
|
|
|
results = []
|
|
|
|
|
return JSONResponse({"results": results})
|
|
|
|
|
|
|
|
|
|
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
def _follow_people(profile_uid: str, mode: str, current_user, page: int):
|
|
|
|
|
people, pagination = get_follow_list(profile_uid, mode, page)
|
|
|
|
|
mine = get_following_among(current_user["uid"], [p["uid"] for p in people]) if current_user else set()
|
|
|
|
|
for person in people:
|
|
|
|
|
person["is_following"] = person["uid"] in mine
|
|
|
|
|
person["is_self"] = bool(current_user and current_user["uid"] == person["uid"])
|
|
|
|
|
return people, pagination
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/{username}/followers")
|
|
|
|
|
async def profile_followers(request: Request, username: str, page: int = 1):
|
|
|
|
|
return _follow_list_json(request, username, "followers", page)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/{username}/following")
|
|
|
|
|
async def profile_following(request: Request, username: str, page: int = 1):
|
|
|
|
|
return _follow_list_json(request, username, "following", page)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _follow_list_json(request: Request, username: str, mode: str, page: int):
|
|
|
|
|
profile_user = get_table("users").find_one(username=username)
|
|
|
|
|
if not profile_user:
|
|
|
|
|
raise not_found("Profile not found")
|
|
|
|
|
current_user = get_current_user(request)
|
|
|
|
|
people, pagination = _follow_people(profile_user["uid"], mode, current_user, page)
|
|
|
|
|
return JSONResponse({
|
|
|
|
|
"username": profile_user["username"],
|
|
|
|
|
"mode": mode,
|
|
|
|
|
"count": pagination["total"],
|
|
|
|
|
"page": pagination["page"],
|
|
|
|
|
"total_pages": pagination["total_pages"],
|
|
|
|
|
mode: [{"uid": p["uid"], "username": p["username"], "bio": p["bio"], "is_following": p["is_following"]} for p in people],
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
2026-05-10 09:08:12 +02:00
|
|
|
@router.get("/{username}", response_class=HTMLResponse)
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
async def profile_page(request: Request, username: str, tab: str = "posts", page: int = 1):
|
2026-05-10 09:08:12 +02:00
|
|
|
current_user = get_current_user(request)
|
|
|
|
|
users = get_table("users")
|
|
|
|
|
profile_user = users.find_one(username=username)
|
|
|
|
|
if not profile_user:
|
feat: add canonical redirect, og_image, next_page_url, and sitemap caching across content routers
Implement canonical_redirect helper in content.py to enforce slug-based 301 redirects for gist, news, post, and project detail pages. Add first_image_url helper to extract primary image from item or attachments for Open Graph meta tags. Inject next_page_url into feed, gists, news, and projects list page SEO contexts for pagination link rel. Extend seo.py with SITEMAP_URL_LIMIT, SITEMAP_TTL constants and _sitemap cache variable for future sitemap generation optimization. Update profile page to raise 404 via not_found instead of 302 redirect, and include og_image from avatar_url.
2026-06-05 20:05:07 +02:00
|
|
|
raise not_found("Profile not found")
|
2026-05-23 10:54:45 +02:00
|
|
|
profile_user["stars"] = get_user_stars(profile_user["uid"])
|
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
|
|
|
rank = get_user_rank(profile_user["uid"])
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
follow_counts = get_follow_counts(profile_user["uid"])
|
|
|
|
|
|
|
|
|
|
people = []
|
|
|
|
|
follow_pagination = None
|
|
|
|
|
if tab in ("followers", "following"):
|
|
|
|
|
people, follow_pagination = _follow_people(profile_user["uid"], tab, current_user, page)
|
2026-05-10 09:08:12 +02:00
|
|
|
|
|
|
|
|
posts = []
|
|
|
|
|
if tab == "posts":
|
|
|
|
|
posts_table = get_table("posts")
|
2026-05-11 03:14:43 +02:00
|
|
|
raw_posts = list(posts_table.find(user_uid=profile_user["uid"], order_by=["-created_at"]))
|
2026-06-06 16:31:42 +02:00
|
|
|
post_uids = [p["uid"] for p in raw_posts]
|
|
|
|
|
counts = get_comment_counts_by_post_uids(post_uids) if raw_posts else {}
|
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
|
|
|
authors = {profile_user["uid"]: profile_user}
|
|
|
|
|
posts = enrich_items(raw_posts, "post", authors, {"comment_count": counts}, user=current_user)
|
2026-06-06 16:31:42 +02:00
|
|
|
reactions_map = get_reactions_by_targets("post", post_uids, current_user)
|
|
|
|
|
bookmark_set = get_user_bookmarks(current_user["uid"], "post", post_uids) if current_user else set()
|
|
|
|
|
polls_map = get_polls_by_post_uids(post_uids, current_user)
|
|
|
|
|
for item in posts:
|
|
|
|
|
uid = item["post"]["uid"]
|
|
|
|
|
item["reactions"] = reactions_map.get(uid, {"counts": {}, "mine": []})
|
|
|
|
|
item["bookmarked"] = uid in bookmark_set
|
|
|
|
|
item["poll"] = polls_map.get(uid)
|
2026-05-10 09:08:12 +02:00
|
|
|
|
|
|
|
|
badges = list(get_table("badges").find(user_uid=profile_user["uid"]))
|
2026-06-09 06:41:27 +02:00
|
|
|
can_see_private = bool(current_user and (current_user["uid"] == profile_user["uid"] or current_user.get("role") == "Admin"))
|
2026-05-10 09:08:12 +02:00
|
|
|
projects = list(get_table("projects").find(user_uid=profile_user["uid"]))
|
2026-06-09 06:41:27 +02:00
|
|
|
if not can_see_private:
|
|
|
|
|
projects = [p for p in projects if not p.get("is_private")]
|
2026-05-13 21:17:57 +02:00
|
|
|
gists_raw = list(get_table("gists").find(user_uid=profile_user["uid"]))
|
|
|
|
|
gists = []
|
|
|
|
|
for g in gists_raw:
|
|
|
|
|
gists.append({"gist": g, "time_ago": time_ago(g["created_at"])})
|
2026-05-23 06:20:27 +02:00
|
|
|
posts_count = len(posts) or get_table("posts").count(user_uid=profile_user["uid"])
|
2026-05-11 00:41:41 +02:00
|
|
|
|
|
|
|
|
activities = []
|
|
|
|
|
if tab == "activity":
|
|
|
|
|
posts_table = get_table("posts")
|
|
|
|
|
for p in posts_table.find(user_uid=profile_user["uid"], order_by=["-created_at"], _limit=10):
|
2026-05-11 03:14:43 +02:00
|
|
|
activities.append({"type": "post", "content": p.get("title") or p["content"][:80], "time_ago": time_ago(p["created_at"]), "created_at": p["created_at"], "uid": p["uid"]})
|
2026-05-11 00:41:41 +02:00
|
|
|
comments_table = get_table("comments")
|
|
|
|
|
for c in comments_table.find(user_uid=profile_user["uid"], order_by=["-created_at"], _limit=10):
|
2026-05-13 21:17:57 +02:00
|
|
|
target_uid = c.get("target_uid", c.get("post_uid", ""))
|
|
|
|
|
target_type = c.get("target_type", "post")
|
|
|
|
|
activities.append({"type": "comment", "content": c["content"][:80], "time_ago": time_ago(c["created_at"]), "created_at": c["created_at"], "uid": target_uid, "target_type": target_type})
|
2026-05-11 03:14:43 +02:00
|
|
|
activities.sort(key=lambda a: a["created_at"], reverse=True)
|
2026-05-11 00:41:41 +02:00
|
|
|
|
2026-06-06 16:31:42 +02:00
|
|
|
heatmap = get_activity_heatmap(profile_user["uid"])
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
heatmap_months = get_activity_months(heatmap)
|
2026-06-06 16:31:42 +02:00
|
|
|
streak = get_streaks(profile_user["uid"])
|
|
|
|
|
|
2026-05-11 00:41:41 +02:00
|
|
|
is_following = False
|
|
|
|
|
if current_user:
|
|
|
|
|
follows = get_table("follows")
|
|
|
|
|
is_following = bool(follows.find_one(follower_uid=current_user["uid"], following_uid=profile_user["uid"]))
|
2026-05-10 09:08:12 +02:00
|
|
|
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
is_owner = bool(current_user and current_user["uid"] == profile_user["uid"])
|
feat: add project file system with CRUD, upload, inline editing, and video attachment support
- Add new `/projects/{slug}/files` endpoint group for per-project filesystem operations including directory and file CRUD, upload, and inline editing with public read and owner write access
- Extend attachment system to support video formats (webm, ogv, mov, m4v) with proper file icons and MIME types
- Implement configurable allowed file types via `allowed_file_types` site setting, replacing hardcoded `ALLOWED_UPLOAD_TYPES` with dynamic `allowed_extensions()` and `is_extension_allowed()` functions
- Add `delete_all_project_files()` call in `delete_content_item()` to clean up project files when a project is deleted
- Create database indexes on `project_files` table for `(project_uid, path)` and `(project_uid, parent_path)` to optimize file lookups
- Introduce `docs_prose.py` module with `render_prose()` function that renders Markdown content inside `data-render` divs using mistune, enabling dynamic prose rendering in documentation pages
- Enhance docs search with Markdown-aware text stripping (`_demarkdown()`) and improved HTML/script/style sanitization for better search indexing
- Update documentation API samples to reflect new attachment response fields (`is_image`, `is_video`, `mime_type`) and note video format support
- Update README to document the new project files endpoint and clarify AI gateway attribution for guest Devii sessions
2026-06-08 22:51:09 +02:00
|
|
|
viewer_is_admin = bool(current_user and current_user.get("role") == "Admin")
|
|
|
|
|
can_view_api_key = bool(current_user and (is_owner or viewer_is_admin))
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
api_key = profile_user.get("api_key", "") if can_view_api_key else ""
|
2026-06-09 00:30:25 +02:00
|
|
|
profile_is_admin = profile_user.get("role") == "Admin"
|
|
|
|
|
ai_quota = _ai_quota(profile_user["uid"], include_cost=viewer_is_admin, is_admin=profile_is_admin) if (is_owner or viewer_is_admin) else None
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
|
2026-05-11 05:30:51 +02:00
|
|
|
base = site_url(request)
|
|
|
|
|
robots = "noindex,follow" if posts_count < 2 else "index,follow"
|
|
|
|
|
bio = profile_user.get("bio", "")
|
|
|
|
|
desc = bio or f"View {profile_user['username']}'s profile on DevPlace. {posts_count} posts."
|
|
|
|
|
seo_ctx = base_seo_context(
|
|
|
|
|
request,
|
|
|
|
|
title=f"{profile_user['username']} (@{profile_user['username']})",
|
|
|
|
|
description=desc,
|
|
|
|
|
robots=robots,
|
2026-05-23 03:21:55 +02:00
|
|
|
og_type="profile",
|
feat: add canonical redirect, og_image, next_page_url, and sitemap caching across content routers
Implement canonical_redirect helper in content.py to enforce slug-based 301 redirects for gist, news, post, and project detail pages. Add first_image_url helper to extract primary image from item or attachments for Open Graph meta tags. Inject next_page_url into feed, gists, news, and projects list page SEO contexts for pagination link rel. Extend seo.py with SITEMAP_URL_LIMIT, SITEMAP_TTL constants and _sitemap cache variable for future sitemap generation optimization. Update profile page to raise 404 via not_found instead of 302 redirect, and include og_image from avatar_url.
2026-06-05 20:05:07 +02:00
|
|
|
og_image=avatar_url("multiavatar", profile_user["username"], 256),
|
2026-05-11 05:30:51 +02:00
|
|
|
breadcrumbs=[
|
|
|
|
|
{"name": "Home", "url": "/feed"},
|
|
|
|
|
{"name": profile_user['username'], "url": f"/profile/{profile_user['username']}"},
|
|
|
|
|
],
|
|
|
|
|
schemas=[
|
|
|
|
|
website_schema(base),
|
|
|
|
|
profile_page_schema(profile_user, posts_count, base),
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
return respond(request, "profile.html", {
|
2026-05-11 05:30:51 +02:00
|
|
|
**seo_ctx,
|
2026-05-10 09:08:12 +02:00
|
|
|
"request": request,
|
|
|
|
|
"user": current_user,
|
|
|
|
|
"profile_user": profile_user,
|
|
|
|
|
"posts": posts,
|
|
|
|
|
"badges": badges,
|
|
|
|
|
"projects": projects,
|
2026-05-12 15:07:34 +02:00
|
|
|
"gists": gists,
|
2026-05-10 09:08:12 +02:00
|
|
|
"current_tab": tab,
|
2026-05-11 00:41:41 +02:00
|
|
|
"posts_count": posts_count,
|
|
|
|
|
"is_following": is_following,
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
"is_owner": is_owner,
|
|
|
|
|
"can_view_api_key": can_view_api_key,
|
|
|
|
|
"api_key": api_key,
|
feat: add project file system with CRUD, upload, inline editing, and video attachment support
- Add new `/projects/{slug}/files` endpoint group for per-project filesystem operations including directory and file CRUD, upload, and inline editing with public read and owner write access
- Extend attachment system to support video formats (webm, ogv, mov, m4v) with proper file icons and MIME types
- Implement configurable allowed file types via `allowed_file_types` site setting, replacing hardcoded `ALLOWED_UPLOAD_TYPES` with dynamic `allowed_extensions()` and `is_extension_allowed()` functions
- Add `delete_all_project_files()` call in `delete_content_item()` to clean up project files when a project is deleted
- Create database indexes on `project_files` table for `(project_uid, path)` and `(project_uid, parent_path)` to optimize file lookups
- Introduce `docs_prose.py` module with `render_prose()` function that renders Markdown content inside `data-render` divs using mistune, enabling dynamic prose rendering in documentation pages
- Enhance docs search with Markdown-aware text stripping (`_demarkdown()`) and improved HTML/script/style sanitization for better search indexing
- Update documentation API samples to reflect new attachment response fields (`is_image`, `is_video`, `mime_type`) and note video format support
- Update README to document the new project files endpoint and clarify AI gateway attribution for guest Devii sessions
2026-06-08 22:51:09 +02:00
|
|
|
"ai_quota": ai_quota,
|
2026-05-11 00:41:41 +02:00
|
|
|
"activities": activities,
|
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
|
|
|
"rank": rank,
|
2026-06-06 16:31:42 +02:00
|
|
|
"heatmap": heatmap,
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
"heatmap_months": heatmap_months,
|
2026-06-06 16:31:42 +02:00
|
|
|
"streak": streak,
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
"people": people,
|
|
|
|
|
"follow_pagination": follow_pagination,
|
|
|
|
|
"followers_count": follow_counts["followers"],
|
|
|
|
|
"following_count": follow_counts["following"],
|
|
|
|
|
}, model=ProfileOut)
|
2026-05-10 09:08:12 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/update")
|
feat: replace raw form parsing with pydantic models for auth, admin, bugs, comments, and gists
Migrate all route handlers from manual `request.form()` parsing to typed `Annotated[Model, Form()]` dependencies using new pydantic models (SignupForm, LoginForm, ForgotPasswordForm, AdminRoleForm, AdminPasswordForm, BugForm, CommentForm, GistForm). Remove inline validation logic from signup, login, password reset, admin role/password change, bug creation, comment creation, and gist creation endpoints, delegating validation to model validators and field constraints. Add `RequestValidationError` exception handler with friendly error messages for auth form pages. Update model definitions to use `field_validator` and `model_validator` for cross-field checks like password matching.
2026-05-23 05:44:04 +02:00
|
|
|
async def update_profile(request: Request, data: Annotated[ProfileForm, Form()]):
|
2026-05-10 09:08:12 +02:00
|
|
|
user = require_user(request)
|
|
|
|
|
users = get_table("users")
|
2026-05-11 03:14:43 +02:00
|
|
|
users.update({
|
2026-05-10 09:08:12 +02:00
|
|
|
"uid": user["uid"],
|
feat: replace raw form parsing with pydantic models for auth, admin, bugs, comments, and gists
Migrate all route handlers from manual `request.form()` parsing to typed `Annotated[Model, Form()]` dependencies using new pydantic models (SignupForm, LoginForm, ForgotPasswordForm, AdminRoleForm, AdminPasswordForm, BugForm, CommentForm, GistForm). Remove inline validation logic from signup, login, password reset, admin role/password change, bug creation, comment creation, and gist creation endpoints, delegating validation to model validators and field constraints. Add `RequestValidationError` exception handler with friendly error messages for auth form pages. Update model definitions to use `field_validator` and `model_validator` for cross-field checks like password matching.
2026-05-23 05:44:04 +02:00
|
|
|
"bio": data.bio.strip(),
|
|
|
|
|
"location": data.location.strip(),
|
|
|
|
|
"git_link": data.git_link.strip(),
|
|
|
|
|
"website": data.website.strip(),
|
2026-05-11 03:14:43 +02:00
|
|
|
}, ["uid"])
|
2026-05-23 06:20:27 +02:00
|
|
|
clear_user_cache(user["uid"])
|
2026-05-10 09:08:12 +02:00
|
|
|
|
|
|
|
|
logger.info(f"Profile updated for {user['username']}")
|
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
|
|
|
return action_result(request, f"/profile/{user['username']}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/regenerate-api-key")
|
|
|
|
|
async def regenerate_api_key(request: Request):
|
|
|
|
|
user = require_user(request)
|
|
|
|
|
new_key = generate_uid()
|
|
|
|
|
get_table("users").update({"uid": user["uid"], "api_key": new_key}, ["uid"])
|
|
|
|
|
clear_user_cache(user["uid"])
|
|
|
|
|
logger.info(f"API key regenerated for {user['username']}")
|
|
|
|
|
return JSONResponse({"api_key": new_key})
|