|
import logging
|
|
from typing import Annotated
|
|
from fastapi import APIRouter, Request, Form
|
|
from devplacepy.models import GistForm, GistEditForm
|
|
from fastapi.responses import HTMLResponse, RedirectResponse
|
|
from devplacepy.database import get_table, get_users_by_uids, get_gist_languages, paginate
|
|
from devplacepy.content import load_detail, edit_content_item, delete_content_item, enrich_items, create_content_item, detail_context
|
|
from devplacepy.templating import templates
|
|
from devplacepy.utils import get_current_user, require_user, not_found, XP_GIST
|
|
from devplacepy.seo import base_seo_context, site_url, website_schema, software_source_code_schema, list_page_seo
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter()
|
|
|
|
LANGUAGES = [
|
|
("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 get_gists_list(user_uid=None, language=None, before=None, viewer=None):
|
|
gists_table = get_table("gists")
|
|
filters = {}
|
|
if user_uid:
|
|
filters["user_uid"] = user_uid
|
|
if language:
|
|
filters["language"] = language
|
|
|
|
total = gists_table.count(**filters)
|
|
gists, next_cursor = paginate(gists_table, before=before, **filters)
|
|
|
|
if not gists:
|
|
return [], next_cursor, total
|
|
|
|
users_map = get_users_by_uids([g["user_uid"] for g in gists])
|
|
return enrich_items(gists, "gist", users_map, user=viewer), next_cursor, total
|
|
|
|
|
|
@router.get("", response_class=HTMLResponse)
|
|
async def gists_page(request: Request, language: str = None, user_uid: str = None, before: str = None):
|
|
user = get_current_user(request)
|
|
gists_data, next_cursor, total_count = get_gists_list(user_uid, language, before, viewer=user)
|
|
seo_ctx = list_page_seo(
|
|
request,
|
|
title="Gists",
|
|
description=f"Browse {total_count} code snippets on DevPlace.",
|
|
breadcrumbs=[
|
|
{"name": "Home", "url": "/feed"},
|
|
{"name": "Gists", "url": "/gists"},
|
|
],
|
|
)
|
|
return templates.TemplateResponse(request, "gists.html", {
|
|
**seo_ctx,
|
|
"request": request,
|
|
"user": user,
|
|
"gists": gists_data,
|
|
"total_count": total_count,
|
|
"next_cursor": next_cursor,
|
|
"current_language": language,
|
|
"languages": LANGUAGES,
|
|
"gist_language_codes": get_gist_languages(),
|
|
})
|
|
|
|
|
|
@router.get("/{gist_slug}", response_class=HTMLResponse)
|
|
async def gist_detail(request: Request, gist_slug: str):
|
|
user = get_current_user(request)
|
|
detail = load_detail("gists", "gist", gist_slug, user)
|
|
if not detail:
|
|
raise not_found("Gist not found")
|
|
gist = detail["item"]
|
|
|
|
base = site_url(request)
|
|
seo_ctx = base_seo_context(
|
|
request,
|
|
title=gist.get("title", "Gist"),
|
|
description=gist.get("description", "")[:160],
|
|
og_type="article",
|
|
breadcrumbs=[
|
|
{"name": "Home", "url": "/feed"},
|
|
{"name": "Gists", "url": "/gists"},
|
|
{"name": gist.get("title", "Gist"), "url": f"/gists/{gist['slug'] or gist['uid']}"},
|
|
],
|
|
schemas=[website_schema(base), software_source_code_schema(gist, base)],
|
|
)
|
|
return templates.TemplateResponse(request, "gist_detail.html", detail_context(request, user, detail, "gist", seo_ctx, {
|
|
"languages": LANGUAGES,
|
|
}))
|
|
|
|
|
|
@router.post("/create")
|
|
async def create_gist(request: Request, data: Annotated[GistForm, Form()]):
|
|
user = require_user(request)
|
|
title = data.title.strip()
|
|
description = data.description.strip()
|
|
source_code = data.source_code.strip()
|
|
language = data.language
|
|
|
|
valid_languages = {l[0] for l in LANGUAGES}
|
|
if language not in valid_languages:
|
|
language = "plaintext"
|
|
|
|
uid, gist_slug = create_content_item("gists", "gist", user, {
|
|
"title": title,
|
|
"description": description or None,
|
|
"source_code": source_code,
|
|
"language": language,
|
|
}, title, XP_GIST, "First Gist", description or "", data.attachment_uids)
|
|
return RedirectResponse(url=f"/gists/{gist_slug}", status_code=302)
|
|
|
|
|
|
@router.post("/edit/{gist_slug}")
|
|
async def edit_gist(request: Request, gist_slug: str, data: Annotated[GistEditForm, Form()]):
|
|
user = require_user(request)
|
|
language = data.language
|
|
if language not in {l[0] for l in LANGUAGES}:
|
|
language = "plaintext"
|
|
return edit_content_item("gists", user, gist_slug, {
|
|
"title": data.title.strip(),
|
|
"description": data.description.strip() or None,
|
|
"source_code": data.source_code.strip(),
|
|
"language": language,
|
|
}, "/gists")
|
|
|
|
|
|
@router.post("/delete/{gist_slug}")
|
|
async def delete_gist(request: Request, gist_slug: str):
|
|
user = require_user(request)
|
|
return delete_content_item("gists", "gist", user, gist_slug, "/gists")
|