diff options
| author | l3wdfut4pwr <l3wdfut4pwr@gmail.com> | 2026-04-27 13:45:09 +0300 |
|---|---|---|
| committer | l3wdfut4pwr <l3wdfut4pwr@gmail.com> | 2026-04-27 13:45:09 +0300 |
| commit | 4848a9e9394b283022085a6305d00f94b11cd703 (patch) | |
| tree | d7ba45885f110e8ded4af20bc98b9f88f75b1f4a /app/routes | |
| parent | f1842be3bfabe7850d33662da2da377676144c48 (diff) | |
add username change and logout
Diffstat (limited to 'app/routes')
| -rw-r--r-- | app/routes/__init__.py | 19 | ||||
| -rw-r--r-- | app/routes/auth/__init__.py | 0 | ||||
| -rw-r--r-- | app/routes/auth/auth.py (renamed from app/routes/auth.py) | 0 | ||||
| -rw-r--r-- | app/routes/auth/logout.py | 35 | ||||
| -rw-r--r-- | app/routes/auth/register.py (renamed from app/routes/register.py) | 0 | ||||
| -rw-r--r-- | app/routes/me.py | 51 | ||||
| -rw-r--r-- | app/routes/users/__init__.py | 0 | ||||
| -rw-r--r-- | app/routes/users/changeusername.py | 40 | ||||
| -rw-r--r-- | app/routes/users/me.py | 17 | ||||
| -rw-r--r-- | app/routes/users/security.py | 0 | ||||
| -rw-r--r-- | app/routes/users/user.py (renamed from app/routes/user.py) | 0 |
11 files changed, 104 insertions, 58 deletions
diff --git a/app/routes/__init__.py b/app/routes/__init__.py index a57869a..65d9c36 100644 --- a/app/routes/__init__.py +++ b/app/routes/__init__.py @@ -1,13 +1,18 @@ from fastapi import APIRouter -from .auth import router as auth_router -from .me import router as me_router -from .register import router as register_router -from .user import router as user_router +from app.routes.auth.auth import router as auth_router +from app.routes.auth.logout import router as logout_router +from app.routes.auth.register import router as register_router +from app.routes.users.changeusername import router as changeusername_router +from app.routes.users.me import router as me_router +from app.routes.users.user import router as user_router router = APIRouter() -router.include_router(register_router, prefix="/auth") -router.include_router(auth_router, prefix="/auth") -router.include_router(user_router) +router.include_router(changeusername_router) router.include_router(me_router) +router.include_router(user_router) + +router.include_router(auth_router, prefix="/auth") +router.include_router(register_router, prefix="/auth") +router.include_router(logout_router, prefix="/auth") diff --git a/app/routes/auth/__init__.py b/app/routes/auth/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/routes/auth/__init__.py diff --git a/app/routes/auth.py b/app/routes/auth/auth.py index 6e0d410..6e0d410 100644 --- a/app/routes/auth.py +++ b/app/routes/auth/auth.py diff --git a/app/routes/auth/logout.py b/app/routes/auth/logout.py new file mode 100644 index 0000000..a55ea9e --- /dev/null +++ b/app/routes/auth/logout.py @@ -0,0 +1,35 @@ +from fastapi import APIRouter, Depends, Response +from sqlalchemy.ext.asyncio import AsyncSession + +from app.auth.dependencies import get_current_user +from app.models.user import User +from app.utils.db import get_async_session +from app.utils.logger_cfg import logger + +router = APIRouter(tags=["auth"]) + + +COOKIE_KWARGS = { + "httponly": True, + "secure": False, + "samesite": "lax", + "path": "/", +} + + +@router.post("/logout") +async def logout( + response: Response, + session: AsyncSession = Depends(get_async_session), + user: User = Depends(get_current_user), +): + response.delete_cookie("access_token", **COOKIE_KWARGS) + response.delete_cookie("refresh_token", **COOKIE_KWARGS) + + user.token_version += 1 + session.add(user) + await session.commit() + + logger.info("User logged out everywhere | user_id={}", user.id) + + return {"message": "Logged out successfully"} diff --git a/app/routes/register.py b/app/routes/auth/register.py index f0b36ed..f0b36ed 100644 --- a/app/routes/register.py +++ b/app/routes/auth/register.py diff --git a/app/routes/me.py b/app/routes/me.py deleted file mode 100644 index 6d28a80..0000000 --- a/app/routes/me.py +++ /dev/null @@ -1,51 +0,0 @@ -from fastapi import APIRouter, Depends, Request -from sqlalchemy.ext.asyncio import AsyncSession - -from app.auth.jwt import decode_token -from app.models.user import User -from app.utils.db import get_async_session - -router = APIRouter(tags=["auth"]) - - -async def get_current_user_from_cookie( - request: Request, - session: AsyncSession = Depends(get_async_session), -) -> dict: - token = request.cookies.get("access_token") - if not token: - return {"authenticated": False, "user": None} - - try: - payload = decode_token(token) - sub = payload.get("sub") - if sub is None: - return {"authenticated": False, "user": None} - user_id = int(sub) - except ValueError, TypeError: - return {"authenticated": False, "user": None} - - user = await User.get_user_by_id(user_id, session=session) - if not user or user.token_version != payload.get("token_version"): - return {"authenticated": False, "user": None} - - return { - "authenticated": True, - "user": { - "id": user.id, - "username": user.username, - "password": user.has_password, - "google_id": user.google_id, - "email": user.email, - "premium": user.premium, - "is_banned": user.is_banned, - "is_moderator": user.is_moderator, - }, - } - - -@router.get("/me") -async def read_current_user( - user_info: dict = Depends(get_current_user_from_cookie), -): - return user_info diff --git a/app/routes/users/__init__.py b/app/routes/users/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/routes/users/__init__.py diff --git a/app/routes/users/changeusername.py b/app/routes/users/changeusername.py new file mode 100644 index 0000000..66ba8da --- /dev/null +++ b/app/routes/users/changeusername.py @@ -0,0 +1,40 @@ +from fastapi import APIRouter, Depends, HTTPException +from pydantic import BaseModel +from sqlalchemy.ext.asyncio import AsyncSession + +from app.auth.dependencies import get_current_user +from app.models.user import User +from app.utils.db import get_async_session + +router = APIRouter() + + +class ChangeUsernameRequest(BaseModel): + username: str + + +@router.patch("/users/change-username") +async def change_username( + data: ChangeUsernameRequest, + user_info: dict = Depends(get_current_user), + session: AsyncSession = Depends(get_async_session), +): + if not user_info["authenticated"]: + raise HTTPException(status_code=401, detail="Not authenticated") + + user = user_info["user"] + + if len(data.username) < 3: + raise HTTPException(status_code=400, detail="Username too short") + + db_user = await session.get(User, user["id"]) + + if not db_user: + raise HTTPException(status_code=404, detail="User not found") + + db_user.username = data.username + + await session.commit() + await session.refresh(db_user) + + return {"success": True, "username": db_user.username} diff --git a/app/routes/users/me.py b/app/routes/users/me.py new file mode 100644 index 0000000..a54fbfe --- /dev/null +++ b/app/routes/users/me.py @@ -0,0 +1,17 @@ +from fastapi import APIRouter, Depends + +from app.auth.dependencies import get_optional_user +from app.models.user import User +from app.schemas.user import MeResponse, UserRead + +router = APIRouter(tags=["auth"]) + + +@router.get("/me", response_model=MeResponse) +async def me( + user: User | None = Depends(get_optional_user), +): + return MeResponse( + authenticated=user is not None, + user=UserRead.model_validate(user) if user else None, + ) diff --git a/app/routes/users/security.py b/app/routes/users/security.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/routes/users/security.py diff --git a/app/routes/user.py b/app/routes/users/user.py index 1eb096d..1eb096d 100644 --- a/app/routes/user.py +++ b/app/routes/users/user.py |
