|
# retoor <retoor@molodetz.nl>
|
|
|
|
import logging
|
|
from typing import Annotated
|
|
from fastapi import APIRouter, Request, Form
|
|
from fastapi.responses import HTMLResponse
|
|
from devplacepy.database import get_table, get_setting, get_int_setting
|
|
from devplacepy.templating import templates
|
|
from devplacepy.utils import (
|
|
create_session,
|
|
get_current_user,
|
|
register_account_async,
|
|
)
|
|
from devplacepy.seo import base_seo_context
|
|
from devplacepy.models import SignupForm
|
|
from devplacepy.config import SECONDS_PER_DAY
|
|
from devplacepy.responses import respond, action_result, wants_json, json_error
|
|
from devplacepy.schemas import AuthPageOut
|
|
from devplacepy.services.audit import record as audit
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/signup", response_class=HTMLResponse)
|
|
async def signup_page(request: Request):
|
|
user = get_current_user(request)
|
|
if user:
|
|
return action_result(request, "/feed")
|
|
seo_ctx = base_seo_context(
|
|
request,
|
|
title="Join DevPlace",
|
|
description="Create your DevPlace account and start connecting with developers.",
|
|
robots="noindex,nofollow",
|
|
)
|
|
registration_closed = get_setting("registration_open", "1") != "1"
|
|
return respond(
|
|
request,
|
|
"signup.html",
|
|
{
|
|
**seo_ctx,
|
|
"request": request,
|
|
"page": "signup",
|
|
"registration_closed": registration_closed,
|
|
},
|
|
model=AuthPageOut,
|
|
)
|
|
|
|
|
|
@router.post("/signup")
|
|
async def signup(request: Request, data: Annotated[SignupForm, Form()]):
|
|
username = data.username
|
|
email = data.email.strip().lower()
|
|
password = data.password
|
|
|
|
if get_setting("registration_open", "1") != "1":
|
|
if wants_json(request):
|
|
return json_error(403, "Registration is closed")
|
|
seo_ctx = base_seo_context(
|
|
request, title="Join DevPlace", robots="noindex,nofollow"
|
|
)
|
|
return templates.TemplateResponse(
|
|
request,
|
|
"signup.html",
|
|
{**seo_ctx, "request": request, "registration_closed": True},
|
|
)
|
|
|
|
errors = []
|
|
users = get_table("users")
|
|
if users.find_one(username=username):
|
|
errors.append("Username already taken")
|
|
if users.find_one(email=email):
|
|
errors.append("Email already registered")
|
|
|
|
if errors:
|
|
if wants_json(request):
|
|
return json_error(400, "; ".join(errors), errors=errors)
|
|
seo_ctx = base_seo_context(
|
|
request, title="Join DevPlace", robots="noindex,nofollow"
|
|
)
|
|
return templates.TemplateResponse(
|
|
request,
|
|
"signup.html",
|
|
{
|
|
**seo_ctx,
|
|
"request": request,
|
|
"errors": errors,
|
|
"username": username,
|
|
"email": email,
|
|
},
|
|
)
|
|
|
|
uid, role, is_first = await register_account_async(username, email, password)
|
|
|
|
max_age = max(1, get_int_setting("session_max_age_days", 7)) * SECONDS_PER_DAY
|
|
token = create_session(uid, max_age)
|
|
response = action_result(request, "/feed", data={"username": username})
|
|
response.set_cookie(
|
|
key="session", value=token, max_age=max_age, httponly=True, samesite="lax"
|
|
)
|
|
logger.info(f"User {username} signed up")
|
|
audit.record(
|
|
request,
|
|
"auth.signup",
|
|
user={"uid": uid, "username": username, "role": role},
|
|
target_type="user",
|
|
target_uid=uid,
|
|
target_label=username,
|
|
new_value=role,
|
|
metadata={"first_user": is_first},
|
|
summary=f"user {username} registered account",
|
|
links=[audit.target("user", uid, username)],
|
|
)
|
|
return response
|