2026-06-12 01:58:46 +02:00
|
|
|
# retoor <retoor@molodetz.nl>
|
|
|
|
|
|
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
|
2026-06-17 19:10:52 +02:00
|
|
|
from fastapi import Depends, APIRouter, Request
|
2026-05-27 21:06:18 +02:00
|
|
|
from fastapi.responses import RedirectResponse, JSONResponse
|
2026-06-21 18:46:27 +02:00
|
|
|
from devplacepy.utils import require_user, redirect_back
|
2026-06-14 09:48:10 +02:00
|
|
|
from devplacepy.content import apply_vote
|
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 devplacepy.models import VoteForm
|
2026-06-17 19:10:52 +02:00
|
|
|
from devplacepy.dependencies import json_or_form
|
2026-05-10 09:08:12 +02:00
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
2026-07-26 14:57:18 +02:00
|
|
|
VOTABLE = {"post", "comment", "gist", "project", "quiz"}
|
2026-06-21 18:46:27 +02:00
|
|
|
|
|
|
|
|
|
2026-05-10 09:08:12 +02:00
|
|
|
@router.post("/{target_type}/{target_uid}")
|
2026-06-09 18:48:08 +02:00
|
|
|
async def vote(
|
|
|
|
|
request: Request,
|
|
|
|
|
target_type: str,
|
|
|
|
|
target_uid: str,
|
2026-06-17 19:10:52 +02:00
|
|
|
data: Annotated[VoteForm, Depends(json_or_form(VoteForm))],
|
2026-06-09 18:48:08 +02:00
|
|
|
):
|
2026-05-10 09:08:12 +02:00
|
|
|
user = require_user(request)
|
2026-06-21 18:46:27 +02:00
|
|
|
if target_type not in VOTABLE:
|
|
|
|
|
return JSONResponse({"error": "Invalid target"}, status_code=400)
|
2026-06-14 09:48:10 +02:00
|
|
|
result = apply_vote(request, user, target_type, target_uid, data.value)
|
2026-05-10 09:08:12 +02:00
|
|
|
|
2026-05-27 21:06:18 +02:00
|
|
|
if request.headers.get("x-requested-with") == "fetch":
|
2026-06-09 18:48:08 +02:00
|
|
|
logger.debug(
|
|
|
|
|
"ajax vote response target=%s/%s net=%s value=%s",
|
|
|
|
|
target_type,
|
|
|
|
|
target_uid,
|
2026-06-14 09:48:10 +02:00
|
|
|
result["net"],
|
|
|
|
|
result["value"],
|
2026-06-09 18:48:08 +02:00
|
|
|
)
|
2026-06-14 09:48:10 +02:00
|
|
|
return JSONResponse(result)
|
2026-05-27 21:06:18 +02:00
|
|
|
|
2026-06-21 18:46:27 +02:00
|
|
|
return RedirectResponse(url=redirect_back(request), status_code=302)
|