From 8bdd740404821cce5d40d4743d02fadfded4e08c Mon Sep 17 00:00:00 2001 From: "ahmed.mujtaba" Date: Tue, 4 Aug 2026 16:44:43 +0500 Subject: [PATCH] login corrected --- .gitignore | 2 ++ backend/users/app.py | 31 +++++++++++++++++++------------ backend/users/models.py | 2 +- backend/users/permissions.py | 11 ++++++----- backend/users/views.py | 3 +-- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 4229f9b..368e0dd 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,5 @@ env/ tmp/ temp/ .cache/ + +**.pdf diff --git a/backend/users/app.py b/backend/users/app.py index 6419691..0125926 100644 --- a/backend/users/app.py +++ b/backend/users/app.py @@ -1,12 +1,9 @@ -from typing import Annotated - from fastapi import APIRouter,Depends, Query from fastapi.responses import JSONResponse from fastapi import HTTPException -from fastapi.security import OAuth2PasswordRequestForm from db_setup import get_session from sqlalchemy.ext.asyncio import AsyncSession -from pydantic import BaseModel, EmailStr +from pydantic import BaseModel, EmailStr, model_validator from users.views import User from users.permissions import CurrentUser from users.serializers import serialize_token @@ -33,18 +30,27 @@ class UserUpdate(BaseModel): is_active: bool | None = None +class UserLogin(BaseModel): + password: str + email: EmailStr | None = None + username: str | None = None + + @model_validator(mode="after") + def require_email_or_username(self): + if not self.email and not self.username: + raise ValueError("email or username is required") + return self + + class TokenRefresh(BaseModel): refresh_token: str @router.post("/users/login") -async def login( - form_data: Annotated[OAuth2PasswordRequestForm, Depends()], - session: AsyncSession = Depends(get_session), -): +async def login(payload: UserLogin,session: AsyncSession = Depends(get_session)): try: service=User(session=session) - user=await service.authenticate_user(form_data.username,form_data.password) + user=await service.authenticate_user(payload.email or payload.username,payload.password) tokens=serialize_token(create_access_token(user),create_refresh_token(user),user) return JSONResponse(content={**tokens,"status_code":200}) except HTTPException: @@ -77,11 +83,12 @@ async def me(current_user: CurrentUser): @router.post("/users/create") -async def create_user(payload: UserCreate,current_user: CurrentUser,session: AsyncSession = Depends(get_session)): +async def create_user(payload: UserCreate,session: AsyncSession = Depends(get_session)): try: service=User(session=session) - data=await service.create_user(payload.model_dump()) - return JSONResponse(content={"data":data,"status_code":200}) + user=await service.create_user(payload.model_dump()) + tokens=serialize_token(create_access_token(user),create_refresh_token(user),user) + return JSONResponse(content={**tokens,"status_code":200}) except HTTPException: raise except Exception as e: diff --git a/backend/users/models.py b/backend/users/models.py index f33fb33..6e0baac 100644 --- a/backend/users/models.py +++ b/backend/users/models.py @@ -15,7 +15,7 @@ class Users(SQLModel, table=True): id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) name: str email: str = Field(unique=True) - role_id: int | None = Field(default=None, foreign_key="roles.id") + role_id: int | None = Field(nullable=True, foreign_key="roles.id") role: Roles | None = Relationship(back_populates="users") password: str created_at: datetime = Field(default_factory=datetime.now) diff --git a/backend/users/permissions.py b/backend/users/permissions.py index 084c2d8..ff86c97 100644 --- a/backend/users/permissions.py +++ b/backend/users/permissions.py @@ -1,4 +1,4 @@ -"""OAuth2 bearer scheme and the current-user dependency for `/users/*` routes.""" +"""HTTP Bearer scheme and the current-user dependency for `/users/*` routes.""" from __future__ import annotations @@ -6,7 +6,7 @@ from typing import Annotated import jwt from fastapi import Depends, HTTPException -from fastapi.security import OAuth2PasswordBearer +from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from sqlalchemy.ext.asyncio import AsyncSession from db_setup import get_session @@ -14,11 +14,11 @@ from users.models import Users from users.plugins import decode_token from users.serializers import serialize_user -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="users/login") +bearer_scheme = HTTPBearer() async def get_current_user( - token: Annotated[str, Depends(oauth2_scheme)], + credentials: Annotated[HTTPAuthorizationCredentials, Depends(bearer_scheme)], session: Annotated[AsyncSession, Depends(get_session)], ) -> dict: credentials_exception = HTTPException( @@ -27,7 +27,7 @@ async def get_current_user( headers={"WWW-Authenticate": "Bearer"}, ) try: - payload = decode_token(token, expected_type="access") + payload = decode_token(credentials.credentials, expected_type="access") except jwt.PyJWTError: raise credentials_exception @@ -42,3 +42,4 @@ async def get_current_user( CurrentUser = Annotated[dict, Depends(get_current_user)] + diff --git a/backend/users/views.py b/backend/users/views.py index cfee2a0..21fea8c 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -19,8 +19,7 @@ class User: fields=clean_user_payload(payload) if not fields.get("password"): raise HTTPException(status_code=400,detail="Password is required") - user=await Users.insert_user(self.session,fields) - return serialize_user(user) + return await Users.insert_user(self.session,fields) async def get_users(self,top,skip,search=None): users=await Users.get_users(self.session,top,skip,search)