Further cleanup
This commit is contained in:
@@ -14,15 +14,15 @@ router = APIRouter()
|
||||
|
||||
|
||||
@router.delete("/user/id")
|
||||
async def delete_user_by_id(user_id: UUID, user: User = Depends(get_admin_user)):
|
||||
async def delete_user_by_id(user_id: UUID, _: User = Depends(get_admin_user)):
|
||||
return {"deleted": await User.objects.delete(id=user_id)}
|
||||
|
||||
|
||||
@router.delete("/user/username")
|
||||
async def delete_user_by_username(username: str, user: User = Depends(get_admin_user)):
|
||||
async def delete_user_by_username(username: str, _: User = Depends(get_admin_user)):
|
||||
return {"deleted": await User.objects.delete(username=username)}
|
||||
|
||||
|
||||
@router.delete("/user/email")
|
||||
async def delete_user_by_email(email: str, user: User = Depends(get_admin_user)):
|
||||
async def delete_user_by_email(email: str, _: User = Depends(get_admin_user)):
|
||||
return {"deleted": await User.objects.delete(email=email)}
|
||||
|
||||
@@ -83,19 +83,6 @@ async def get_customized_avatar(
|
||||
clothe_graphic_type=clothe_graphic_type,
|
||||
).render_svg()
|
||||
# skipcq: PY-W0069
|
||||
# print(f"skin_color: {len(AvatarItemsAsList.skin_color)},")
|
||||
# print(f"hair_color: {len(AvatarItemsAsList.hair_color)},")
|
||||
# print(f"facial_hair_type: {len(AvatarItemsAsList.facial_hair_type)},")
|
||||
# print(f"facial_hair_color: {len(AvatarItemsAsList.facial_hair_color)},")
|
||||
# print(f"top_type: {len(AvatarItemsAsList.top_type)},")
|
||||
# print(f"hat_color: {len(AvatarItemsAsList.hat_color)},")
|
||||
# print(f"mouth_type: {len(AvatarItemsAsList.mouth_type)},")
|
||||
# print(f"eyebrow_type: {len(AvatarItemsAsList.eyebrow_type)},")
|
||||
# print(f"nose_type: {len(AvatarItemsAsList.nose_type)},")
|
||||
# print(f"accessories_type: {len(AvatarItemsAsList.accessories_type)},")
|
||||
# print(f"clothe_type: {len(AvatarItemsAsList.clothe_type)},")
|
||||
# print(f"clothe_color: {len(AvatarItemsAsList.clothe_color)},")
|
||||
# print(f"clothe_graphic_type: {len(AvatarItemsAsList.clothe_graphic_type)},")
|
||||
return avatar
|
||||
|
||||
|
||||
|
||||
@@ -17,18 +17,24 @@ router = APIRouter()
|
||||
|
||||
|
||||
#
|
||||
@router.get("/user/{user_id}", response_model_include={"username", "created_at", "id"}, response_model=User)
|
||||
@router.get(
|
||||
"/user/{user_id}",
|
||||
response_model_include={"username", "created_at", "id"},
|
||||
response_model=User,
|
||||
)
|
||||
async def get_user_by_user_id(user_id: UUID):
|
||||
user = await User.objects.get_or_none(id=user_id)
|
||||
# .select_related("quizs")
|
||||
# print(user)
|
||||
if user is None:
|
||||
raise HTTPException(status_code=404, detail="user not found")
|
||||
else:
|
||||
return user
|
||||
|
||||
|
||||
@router.get("/quizzes/{user_id}", response_model_exclude={"questions", "user_id"}, response_model=list[Quiz])
|
||||
@router.get(
|
||||
"/quizzes/{user_id}",
|
||||
response_model_exclude={"questions", "user_id"},
|
||||
response_model=list[Quiz],
|
||||
)
|
||||
async def get_quizzes_from_user(user_id: UUID, imported: bool | None = None):
|
||||
if imported is None:
|
||||
quizzes = await Quiz.objects.all(user_id=user_id, public=True)
|
||||
@@ -68,7 +74,13 @@ async def rate_quiz(data: RateQuizInput, quiz_id: uuid.UUID, user: User = Depend
|
||||
quiz.likes -= 1
|
||||
else:
|
||||
quiz.dislikes -= 1
|
||||
rating = Rating(id=uuid.uuid4(), user=user, positive=positive, quiz=quiz, created_at=datetime.now())
|
||||
rating = Rating(
|
||||
id=uuid.uuid4(),
|
||||
user=user,
|
||||
positive=positive,
|
||||
quiz=quiz,
|
||||
created_at=datetime.now(),
|
||||
)
|
||||
await rating.save()
|
||||
if positive:
|
||||
quiz.likes += 1
|
||||
|
||||
@@ -37,7 +37,7 @@ class UUIDEncoder(json.JSONEncoder):
|
||||
|
||||
|
||||
@router.get("/{quiz_id}")
|
||||
async def export_quiz(quiz_id: uuid.UUID, user: User = Depends(get_current_user)):
|
||||
async def export_quiz(quiz_id: uuid.UUID, _: User = Depends(get_current_user)):
|
||||
try:
|
||||
quiz: Quiz = await Quiz.objects.filter(Quiz.id == quiz_id).first()
|
||||
except ormar.exceptions.NoMatch:
|
||||
@@ -138,7 +138,7 @@ async def import_quiz(file: UploadFile = File(), user: User = Depends(get_curren
|
||||
|
||||
|
||||
@router.get("/excel/{quiz_id}")
|
||||
async def export_quiz_as_excel(quiz_id: uuid.UUID, user: User = Depends(get_current_user)):
|
||||
async def export_quiz_as_excel(quiz_id: uuid.UUID, _: User = Depends(get_current_user)):
|
||||
try:
|
||||
quiz: Quiz = await Quiz.objects.filter(Quiz.id == quiz_id).first()
|
||||
except ormar.exceptions.NoMatch:
|
||||
|
||||
@@ -10,22 +10,18 @@ from datetime import datetime
|
||||
import ormar
|
||||
import pydantic
|
||||
from email_validator import validate_email, EmailNotValidError
|
||||
from fastapi import APIRouter, Response, HTTPException, Request, Depends, status
|
||||
from fastapi import APIRouter, Response, HTTPException, Request, Depends
|
||||
from fastapi.background import BackgroundTasks
|
||||
from fastapi.responses import JSONResponse, RedirectResponse, PlainTextResponse
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
|
||||
from jose import jwt, JWTError
|
||||
|
||||
from classquiz import oauth
|
||||
from classquiz.helpers.avatar import gzipped_user_avatar
|
||||
import base64
|
||||
from classquiz.oauth.authenticate_user import rememberme_check, log_user_in
|
||||
|
||||
from classquiz.auth import (
|
||||
get_password_hash,
|
||||
verify_password,
|
||||
authenticate_user,
|
||||
get_current_user,
|
||||
)
|
||||
from classquiz.cache import clear_cache_for_account
|
||||
@@ -33,7 +29,7 @@ from classquiz.config import redis, settings, meilisearch
|
||||
import uuid
|
||||
import bleach
|
||||
from pydantic import BaseModel
|
||||
from classquiz.db.models import User, UserSession, UpdatePassword, Token, Quiz, ApiKey
|
||||
from classquiz.db.models import User, UserSession, UpdatePassword, Quiz, ApiKey
|
||||
from classquiz.emails import send_register_email, send_forgotten_password_email
|
||||
from classquiz.routers.users import webauthn, twofa
|
||||
|
||||
@@ -66,7 +62,12 @@ router.include_router(oauth.router, tags=["users", "oauth"], prefix="/oauth")
|
||||
async def create_user(user: RouteUser, background_task: BackgroundTasks) -> User | JSONResponse:
|
||||
if settings.registration_disabled:
|
||||
raise HTTPException(status_code=423)
|
||||
user = User(**user.model_dump(), id=uuid.uuid4(), avatar=gzipped_user_avatar(), created_at=datetime.now())
|
||||
user: User = User(
|
||||
**user.model_dump(),
|
||||
id=uuid.uuid4(),
|
||||
avatar=gzipped_user_avatar(),
|
||||
created_at=datetime.now(),
|
||||
)
|
||||
try:
|
||||
validate_email(user.email)
|
||||
except EmailNotValidError as e:
|
||||
@@ -91,31 +92,6 @@ async def create_user(user: RouteUser, background_task: BackgroundTasks) -> User
|
||||
return user
|
||||
|
||||
|
||||
@router.post("/token/cookie", response_model=Token, deprecated=True)
|
||||
async def login_for_cookie_access_token(
|
||||
request: Request,
|
||||
response: Response,
|
||||
form_data: OAuth2PasswordRequestForm = Depends(),
|
||||
):
|
||||
user = await authenticate_user(form_data.username, form_data.password)
|
||||
user = await User.objects.select_related("fidocredentialss").get(id=user.id)
|
||||
if not user or user.totp_secret is not None or user or len(user.fidocredentialss) != 0:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Incorrect username or password",
|
||||
)
|
||||
|
||||
return await log_user_in(response=response, request=request, user=user)
|
||||
|
||||
|
||||
@router.get("/token/rememberme")
|
||||
async def rememberme_token(request: Request, response: Response):
|
||||
rememberme_token_lol = request.cookies.get("rememberme_token")
|
||||
if rememberme_token_lol is None:
|
||||
raise HTTPException(status_code=400, detail="No rememberme cookie")
|
||||
return await rememberme_check(rememberme_token=rememberme_token_lol, response=response)
|
||||
|
||||
|
||||
@router.get("/logout")
|
||||
async def logout(request: Request, response: Response):
|
||||
remember_token = request.cookies.get("rememberme_token")
|
||||
@@ -229,24 +205,26 @@ async def reset_password_with_token(reset_password: ResetPassword, response: Res
|
||||
return {"message": "Password updated successfully"}
|
||||
|
||||
|
||||
@router.get("/sessions/list", response_model=list[UserSession], response_model_exclude={"user", "session_key", "quizs"})
|
||||
@router.get(
|
||||
"/sessions/list",
|
||||
response_model=list[UserSession],
|
||||
response_model_exclude={"user", "session_key", "quizs"},
|
||||
)
|
||||
async def list_sessions(user: User = Depends(get_current_user)):
|
||||
sessions = await UserSession.objects.filter(user=user).all()
|
||||
return [session.model_dump() for session in sessions]
|
||||
|
||||
|
||||
@router.delete("/sessions/{session_id}")
|
||||
async def delete_session(session_id: str, user: User = Depends(get_current_user)):
|
||||
try:
|
||||
session_id = uuid.UUID(session_id)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400, detail="Invalid session id")
|
||||
async def delete_session(session_id: uuid.UUID, user: User = Depends(get_current_user)):
|
||||
await UserSession.objects.filter(user=user, id=session_id).delete()
|
||||
return {"message": "Session deleted"}
|
||||
|
||||
|
||||
@router.get(
|
||||
"/session", response_model=UserSession, response_model_exclude={"user": ..., "session_key": ..., "quizs": ...}
|
||||
"/session",
|
||||
response_model=UserSession,
|
||||
response_model_exclude={"user": ..., "session_key": ..., "quizs": ...},
|
||||
)
|
||||
async def get_session(request: Request, user: User = Depends(get_current_user)):
|
||||
try:
|
||||
@@ -300,43 +278,10 @@ class InternalAuthData(BaseModel):
|
||||
jwt: str | None = None
|
||||
|
||||
|
||||
@router.post("/auth/internal")
|
||||
async def internal_auth(data: InternalAuthData, resp: Response):
|
||||
try:
|
||||
data.jwt = data.jwt.replace("Bearer ", "")
|
||||
except AttributeError:
|
||||
pass
|
||||
if data.jwt is not None:
|
||||
try:
|
||||
payload = jwt.decode(data.jwt, settings.secret_key, algorithms=["HS256"])
|
||||
email: str = payload.get("sub")
|
||||
if email is None:
|
||||
resp.status_code = 401
|
||||
return resp
|
||||
except JWTError:
|
||||
resp.status_code = 401
|
||||
return resp
|
||||
else:
|
||||
return await rememberme_check(data.rememberme, resp)
|
||||
|
||||
|
||||
class GetEmailFromJWT(BaseModel):
|
||||
jwt: str
|
||||
|
||||
|
||||
@router.post("/auth/internal/email")
|
||||
async def get_email_from_jwt(data: GetEmailFromJWT):
|
||||
try:
|
||||
data.jwt = data.jwt.replace("Bearer ", "")
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
payload = jwt.decode(data.jwt, settings.secret_key, algorithms=["HS256"])
|
||||
return payload.get("sub")
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401)
|
||||
|
||||
|
||||
@router.post("/api_keys", response_model=ApiKey, response_model_include={"key"})
|
||||
async def generate_api_key(user: User = Depends(get_current_user)):
|
||||
key = ApiKey(key=os.urandom(24).hex(), user=user)
|
||||
@@ -351,7 +296,7 @@ async def list_api_keys(user: User = Depends(get_current_user)):
|
||||
|
||||
|
||||
@router.delete("/api_keys")
|
||||
async def delete_api_key(api_key: str, user: User = Depends(get_current_user)):
|
||||
async def delete_api_key(api_key: str, _: User = Depends(get_current_user)):
|
||||
key = await ApiKey.objects.get_or_none(key=api_key)
|
||||
if key is None:
|
||||
raise HTTPException(status_code=404, detail="Key not found")
|
||||
|
||||
Reference in New Issue
Block a user