mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Working on the implementation of fastapi users.
This commit is contained in:
@@ -1,10 +1,9 @@
|
|||||||
from sqlalchemy import Column, DateTime, Integer
|
from sqlalchemy import Column, DateTime, Integer
|
||||||
|
from sqlalchemy.orm import DeclarativeBase
|
||||||
from sqlalchemy.sql import func
|
from sqlalchemy.sql import func
|
||||||
|
|
||||||
from database import BaseModel
|
|
||||||
|
|
||||||
|
class Model(DeclarativeBase):
|
||||||
class Model(BaseModel):
|
|
||||||
__abstract__ = True
|
__abstract__ = True
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
|||||||
+34
-26
@@ -1,33 +1,41 @@
|
|||||||
from sqlalchemy import asc
|
from sqlalchemy import asc, select
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from . import models, schemas, services
|
from .models import User
|
||||||
|
|
||||||
|
|
||||||
def get_user(db: Session, user_id: int):
|
#
|
||||||
return db.query(models.User).filter(models.User.id == user_id).first()
|
# def get_user(db: Session, user_id: int):
|
||||||
|
# return db.query(models.User).filter(models.User.id == user_id).first()
|
||||||
|
|
||||||
|
#
|
||||||
|
# def get_users(db: Session, skip: int = 0, limit: int = 100):
|
||||||
|
# return db.query(models.User).order_by(asc(models.User.id)).offset(skip).limit(limit).all()
|
||||||
|
|
||||||
|
|
||||||
def get_users(db: Session, skip: int = 0, limit: int = 100):
|
async def get_users(session: AsyncSession, skip: int = 0, limit: int = 100):
|
||||||
return db.query(models.User).order_by(asc(models.User.id)).offset(skip).limit(limit).all()
|
query = select(User).order_by(asc(User.id)).offset(skip).limit(limit)
|
||||||
|
result = await session.execute(query)
|
||||||
|
users = result.scalars().all()
|
||||||
|
return users
|
||||||
|
|
||||||
|
#
|
||||||
|
# def get_user_by_email(db: Session, email: str):
|
||||||
|
# return db.query(models.User).filter(models.User.email == email).first()
|
||||||
|
|
||||||
|
|
||||||
def get_user_by_email(db: Session, email: str):
|
# def create_user(db: Session, user: schemas.UserCreate):
|
||||||
return db.query(models.User).filter(models.User.email == email).first()
|
# fake_hashed_password = services.get_password_hash(user.password)
|
||||||
|
# db_user = models.User(email=user.email, hashed_password=fake_hashed_password)
|
||||||
|
# db.add(db_user)
|
||||||
|
# db.commit()
|
||||||
|
# db.refresh(db_user)
|
||||||
|
# return db_user
|
||||||
|
|
||||||
|
#
|
||||||
def create_user(db: Session, user: schemas.UserCreate):
|
# def create_admin_user(db: Session, user: schemas.AdminUserCreate):
|
||||||
fake_hashed_password = services.get_password_hash(user.password)
|
# fake_hashed_password = services.get_password_hash(user.password)
|
||||||
db_user = models.User(email=user.email, hashed_password=fake_hashed_password)
|
# db_user = models.User(email=user.email, hashed_password=fake_hashed_password, role=user.role)
|
||||||
db.add(db_user)
|
# db.add(db_user)
|
||||||
db.commit()
|
# db.commit()
|
||||||
db.refresh(db_user)
|
# db.refresh(db_user)
|
||||||
return db_user
|
# return db_user
|
||||||
|
|
||||||
|
|
||||||
def create_admin_user(db: Session, user: schemas.AdminUserCreate):
|
|
||||||
fake_hashed_password = services.get_password_hash(user.password)
|
|
||||||
db_user = models.User(email=user.email, hashed_password=fake_hashed_password, role=user.role)
|
|
||||||
db.add(db_user)
|
|
||||||
db.commit()
|
|
||||||
db.refresh(db_user)
|
|
||||||
return db_user
|
|
||||||
|
|||||||
@@ -1,15 +1,23 @@
|
|||||||
from sqlalchemy import Column, Boolean, String, Float, Enum
|
from fastapi_users_db_sqlalchemy import SQLAlchemyBaseUserTableUUID
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import DeclarativeBase
|
||||||
|
|
||||||
from apps.base.models import Model
|
from apps.base.models import Model
|
||||||
from apps.users.roles import Role
|
from apps.users.roles import Role
|
||||||
|
|
||||||
|
|
||||||
class User(Model):
|
#
|
||||||
__tablename__ = 'users'
|
# class User(Model):
|
||||||
|
# __tablename__ = 'users'
|
||||||
|
#
|
||||||
|
# email = Column(String, unique=True, index=True)
|
||||||
|
# hashed_password = Column(String)
|
||||||
|
# is_active = Column(Boolean, default=True)
|
||||||
|
# role = Column(Enum(Role), default=Role.USER) # Add a role attribute
|
||||||
|
# # role = Column(String) # Ensure role is defined
|
||||||
|
|
||||||
email = Column(String, unique=True, index=True)
|
|
||||||
hashed_password = Column(String)
|
class Base(DeclarativeBase):
|
||||||
is_active = Column(Boolean, default=True)
|
pass
|
||||||
role = Column(Enum(Role), default=Role.USER) # Add a role attribute
|
|
||||||
# role = Column(String) # Ensure role is defined
|
|
||||||
|
class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -1,36 +1,15 @@
|
|||||||
from apps.base.schemas import Schema
|
import uuid
|
||||||
from apps.users.roles import Role
|
|
||||||
|
from fastapi_users import schemas
|
||||||
|
|
||||||
|
|
||||||
class UserBase(Schema):
|
class UserRead(schemas.BaseUser[uuid.UUID]):
|
||||||
email: str
|
pass
|
||||||
|
|
||||||
|
|
||||||
class UserCreate(UserBase):
|
class UserCreate(schemas.BaseUserCreate):
|
||||||
password: str
|
pass
|
||||||
|
|
||||||
|
|
||||||
class User(UserBase):
|
class UserUpdate(schemas.BaseUserUpdate):
|
||||||
id: int
|
pass
|
||||||
is_active: bool
|
|
||||||
role: Role
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
from_attributes = True
|
|
||||||
|
|
||||||
|
|
||||||
class Token(Schema):
|
|
||||||
access_token: str
|
|
||||||
token_type: str
|
|
||||||
|
|
||||||
|
|
||||||
class TokenData(Schema):
|
|
||||||
username: str | None = None
|
|
||||||
|
|
||||||
|
|
||||||
class UserInDB(User):
|
|
||||||
hashed_password: str
|
|
||||||
|
|
||||||
|
|
||||||
class AdminUserCreate(UserCreate):
|
|
||||||
role: Role
|
|
||||||
|
|||||||
+41
-100
@@ -1,115 +1,56 @@
|
|||||||
from datetime import datetime, timedelta, timezone
|
import uuid
|
||||||
from typing import Annotated
|
from typing import Optional
|
||||||
from fastapi import Request
|
|
||||||
|
|
||||||
from fastapi import Depends, HTTPException, status, Security
|
from fastapi import Depends, Request
|
||||||
from fastapi.security import OAuth2PasswordBearer
|
from fastapi_users import BaseUserManager, FastAPIUsers, UUIDIDMixin
|
||||||
from jose import JWTError, jwt
|
from fastapi_users.authentication import (
|
||||||
from passlib.context import CryptContext
|
AuthenticationBackend,
|
||||||
from sqlalchemy.orm import Session
|
BearerTransport,
|
||||||
from functools import wraps
|
JWTStrategy,
|
||||||
|
)
|
||||||
|
from fastapi_users.db import SQLAlchemyUserDatabase
|
||||||
|
|
||||||
from apps.users.crud import get_user_by_email
|
from apps.users.models import User
|
||||||
from apps.users.roles import Permission, role_permissions
|
from database import get_user_db
|
||||||
from apps.users.schemas import TokenData, User, UserInDB
|
|
||||||
from middleware.db_connection import get_db
|
|
||||||
from settings import config
|
|
||||||
|
|
||||||
ALGORITHM = "HS256"
|
SECRET = "SECRET"
|
||||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
|
||||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
|
||||||
|
|
||||||
|
|
||||||
def verify_password(plain_password, hashed_password):
|
class UserManager(UUIDIDMixin, BaseUserManager[User, uuid.UUID]):
|
||||||
return pwd_context.verify(plain_password, hashed_password)
|
reset_password_token_secret = SECRET
|
||||||
|
verification_token_secret = SECRET
|
||||||
|
|
||||||
|
async def on_after_register(self, user: User, request: Optional[Request] = None):
|
||||||
|
print(f"User {user.id} has registered.")
|
||||||
|
|
||||||
|
async def on_after_forgot_password(
|
||||||
|
self, user: User, token: str, request: Optional[Request] = None
|
||||||
|
):
|
||||||
|
print(f"User {user.id} has forgot their password. Reset token: {token}")
|
||||||
|
|
||||||
|
async def on_after_request_verify(
|
||||||
|
self, user: User, token: str, request: Optional[Request] = None
|
||||||
|
):
|
||||||
|
print(f"Verification requested for user {user.id}. Verification token: {token}")
|
||||||
|
|
||||||
|
|
||||||
def get_password_hash(password):
|
async def get_user_manager(user_db: SQLAlchemyUserDatabase = Depends(get_user_db)):
|
||||||
return pwd_context.hash(password)
|
yield UserManager(user_db)
|
||||||
|
|
||||||
|
|
||||||
def get_user(db, username: str):
|
bearer_transport = BearerTransport(tokenUrl="auth/jwt/login")
|
||||||
if username in db:
|
|
||||||
user_dict = db[username]
|
|
||||||
return UserInDB(**user_dict)
|
|
||||||
|
|
||||||
|
|
||||||
def authenticate_user(db, username: str, password: str):
|
def get_jwt_strategy() -> JWTStrategy:
|
||||||
user = get_user_by_email(db, username)
|
return JWTStrategy(secret=SECRET, lifetime_seconds=3600)
|
||||||
if not user:
|
|
||||||
return False
|
|
||||||
if not verify_password(password, user.hashed_password):
|
|
||||||
return False
|
|
||||||
return user
|
|
||||||
|
|
||||||
|
|
||||||
def create_access_token(data: dict, expires_delta: timedelta | None = None):
|
auth_backend = AuthenticationBackend(
|
||||||
to_encode = data.copy()
|
name="jwt",
|
||||||
if expires_delta:
|
transport=bearer_transport,
|
||||||
expire = datetime.now(timezone.utc) + expires_delta
|
get_strategy=get_jwt_strategy,
|
||||||
else:
|
)
|
||||||
expire = datetime.now(timezone.utc) + timedelta(minutes=15)
|
|
||||||
to_encode.update({"exp": expire})
|
|
||||||
encoded_jwt = jwt.encode(to_encode, config.SECRET_KEY, algorithm=ALGORITHM)
|
|
||||||
return encoded_jwt
|
|
||||||
|
|
||||||
|
fastapi_users = FastAPIUsers[User, uuid.UUID](get_user_manager, [auth_backend])
|
||||||
|
|
||||||
async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)], db: Session = Depends(get_db)):
|
current_active_user = fastapi_users.current_user(active=True)
|
||||||
credentials_exception = HTTPException(
|
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
||||||
detail="Could not validate credentials",
|
|
||||||
headers={"WWW-Authenticate": "Bearer"},
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
print(token)
|
|
||||||
payload = jwt.decode(token, config.SECRET_KEY, algorithms=[ALGORITHM])
|
|
||||||
print("payload", payload)
|
|
||||||
username: str = payload.get("sub")
|
|
||||||
if username is None:
|
|
||||||
raise credentials_exception
|
|
||||||
token_data = TokenData(username=username)
|
|
||||||
except JWTError:
|
|
||||||
raise credentials_exception
|
|
||||||
print(token_data.username)
|
|
||||||
user = get_user_by_email(db, email=token_data.username)
|
|
||||||
print(user)
|
|
||||||
if user is None:
|
|
||||||
raise credentials_exception
|
|
||||||
return user
|
|
||||||
|
|
||||||
async def get_current_active_user(
|
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
|
||||||
):
|
|
||||||
if not current_user.is_active:
|
|
||||||
raise HTTPException(status_code=400, detail="Inactive user")
|
|
||||||
return current_user
|
|
||||||
|
|
||||||
|
|
||||||
def permission_required(*permissions: Permission):
|
|
||||||
def decorator(func):
|
|
||||||
@wraps(func)
|
|
||||||
async def decorated_function(*args, **kwargs):
|
|
||||||
request: Request = kwargs.get("request")
|
|
||||||
db: Session = kwargs.get("db")
|
|
||||||
if not request:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
detail="Missing request object",
|
|
||||||
)
|
|
||||||
authorization_header = request.headers.get("Authorization")
|
|
||||||
if not authorization_header:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
||||||
detail="Missing authorization header",
|
|
||||||
)
|
|
||||||
token = authorization_header.split(" ")[1]
|
|
||||||
current_user = await get_current_user(token=token, db=db)
|
|
||||||
for permission in permissions:
|
|
||||||
if permission not in role_permissions[current_user.role]:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail=f"You do not have the required permission: {permission.value}",
|
|
||||||
)
|
|
||||||
return await func(*args, **kwargs)
|
|
||||||
return decorated_function
|
|
||||||
return decorator
|
|
||||||
|
|||||||
+23
-8
@@ -1,18 +1,33 @@
|
|||||||
from sqlalchemy import create_engine
|
from typing import AsyncGenerator
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from fastapi import Depends
|
||||||
from sqlalchemy.orm import sessionmaker
|
from fastapi_users.db import SQLAlchemyUserDatabase
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine, async_session
|
||||||
|
from apps.users.models import Base, User
|
||||||
from settings import config
|
from settings import config
|
||||||
|
|
||||||
POSTGRES_SERVER = config.POSTGRES_SERVER
|
POSTGRES_SERVER = config.POSTGRES_SERVER
|
||||||
POSTGRES_USER = config.POSTGRES_USER
|
POSTGRES_USER = config.POSTGRES_USER
|
||||||
POSTGRES_PASSWORD = config.POSTGRES_PASSWORD
|
POSTGRES_PASSWORD = config.POSTGRES_PASSWORD
|
||||||
POSTGRES_DB = config.POSTGRES_DB
|
POSTGRES_DB = config.POSTGRES_DB
|
||||||
|
SQLALCHEMY_DATABASE_URL = f"postgresql+asyncpg://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_SERVER}/{POSTGRES_DB}"
|
||||||
|
engine = create_async_engine(SQLALCHEMY_DATABASE_URL)
|
||||||
|
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
|
||||||
|
|
||||||
SQLALCHEMY_DATABASE_URL = f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_SERVER}/{POSTGRES_DB}"
|
|
||||||
|
|
||||||
engine = create_engine(SQLALCHEMY_DATABASE_URL)
|
async def create_db_and_tables():
|
||||||
|
async with engine.begin() as conn:
|
||||||
|
await conn.run_sync(Base.metadata.create_all)
|
||||||
|
|
||||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
||||||
|
|
||||||
BaseModel = declarative_base()
|
async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
|
||||||
|
async with async_session_maker() as session:
|
||||||
|
yield session
|
||||||
|
|
||||||
|
|
||||||
|
async def get_user_db(session: AsyncSession = Depends(get_async_session)):
|
||||||
|
yield SQLAlchemyUserDatabase(session, User)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_db_session() -> AsyncSession:
|
||||||
|
async with async_session() as session:
|
||||||
|
yield session
|
||||||
|
|||||||
+6
-36
@@ -1,48 +1,18 @@
|
|||||||
import os
|
import asyncio
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from sqlalchemy.orm import Session
|
from database import create_db_and_tables
|
||||||
from starlette.middleware.trustedhost import TrustedHostMiddleware
|
from middleware.create_user import create_user
|
||||||
|
|
||||||
from apps.users.roles import Role
|
|
||||||
from apps.users.schemas import UserCreate, User, AdminUserCreate
|
|
||||||
from database import BaseModel, engine, SessionLocal
|
|
||||||
from middleware.db_connection import DatabaseSessionMiddleware
|
|
||||||
from routes.main import api_router
|
from routes.main import api_router
|
||||||
from settings import config
|
|
||||||
|
|
||||||
|
|
||||||
def init_default_users(db: Session):
|
|
||||||
from apps.users import crud
|
|
||||||
print("Initializing default users...")
|
|
||||||
if not crud.get_user_by_email(db, "admin@portabase.com"):
|
|
||||||
print("Creating admin user...")
|
|
||||||
user = AdminUserCreate(email="admin@portabase.com", password="password", role=Role.ADMIN)
|
|
||||||
crud.create_admin_user(db, user)
|
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI):
|
||||||
print("Initialising database...")
|
await create_db_and_tables()
|
||||||
BaseModel.metadata.create_all(bind=engine)
|
await create_user("soluce.technologies@gmail.com", "12345678", True)
|
||||||
print("Database initialised!")
|
|
||||||
# Initialize default users
|
|
||||||
db = SessionLocal()
|
|
||||||
try:
|
|
||||||
init_default_users(db)
|
|
||||||
finally:
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
yield
|
yield
|
||||||
print("App shutdown!")
|
|
||||||
|
|
||||||
|
|
||||||
middlewares = []
|
app = FastAPI(lifespan=lifespan)
|
||||||
|
|
||||||
app = FastAPI(lifespan=lifespan, middleware=middlewares)
|
|
||||||
|
|
||||||
app.add_middleware(DatabaseSessionMiddleware)
|
|
||||||
app.add_middleware(TrustedHostMiddleware, allowed_hosts=config.ALLOWED_HOSTS)
|
|
||||||
|
|
||||||
app.include_router(api_router)
|
app.include_router(api_router)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import contextlib
|
||||||
|
|
||||||
|
from fastapi_users.exceptions import UserAlreadyExists
|
||||||
|
|
||||||
|
from apps.users.schemas import UserCreate
|
||||||
|
from apps.users.services import get_user_manager
|
||||||
|
from database import get_async_session, get_user_db
|
||||||
|
|
||||||
|
get_async_session_context = contextlib.asynccontextmanager(get_async_session)
|
||||||
|
get_user_db_context = contextlib.asynccontextmanager(get_user_db)
|
||||||
|
get_user_manager_context = contextlib.asynccontextmanager(get_user_manager)
|
||||||
|
|
||||||
|
|
||||||
|
async def create_user(email: str, password: str, is_superuser: bool = False):
|
||||||
|
try:
|
||||||
|
async with get_async_session_context() as session:
|
||||||
|
async with get_user_db_context(session) as user_db:
|
||||||
|
async with get_user_manager_context(user_db) as user_manager:
|
||||||
|
user = await user_manager.create(
|
||||||
|
UserCreate(
|
||||||
|
email=email, password=password, is_superuser=is_superuser
|
||||||
|
)
|
||||||
|
)
|
||||||
|
print(f"User created {user}")
|
||||||
|
return user
|
||||||
|
except UserAlreadyExists:
|
||||||
|
print(f"User {email} already exists")
|
||||||
|
# raise
|
||||||
@@ -1,20 +1,26 @@
|
|||||||
from fastapi import Request, Response
|
from fastapi import Request, Response
|
||||||
from starlette.middleware.base import BaseHTTPMiddleware
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from database import SessionLocal
|
from database import get_async_session
|
||||||
|
|
||||||
|
|
||||||
class DatabaseSessionMiddleware(BaseHTTPMiddleware):
|
# from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
async def dispatch(self, request: Request, call_next):
|
|
||||||
response = Response("Internal server error", status_code=500)
|
# from database import SessionLocal
|
||||||
try:
|
|
||||||
request.state.db = SessionLocal()
|
#
|
||||||
response = await call_next(request)
|
# class DatabaseSessionMiddleware(BaseHTTPMiddleware):
|
||||||
finally:
|
# async def dispatch(self, request: Request, call_next):
|
||||||
request.state.db.close()
|
# response = Response("Internal server error", status_code=500)
|
||||||
return response
|
# try:
|
||||||
|
# request.state.db = SessionLocal()
|
||||||
|
# response = await call_next(request)
|
||||||
|
# finally:
|
||||||
|
# request.state.db.close()
|
||||||
|
# return response
|
||||||
|
|
||||||
|
|
||||||
def get_db(request: Request):
|
def get_db(request: Request):
|
||||||
print(request)
|
print(request)
|
||||||
return request.state.db
|
return request.state.db
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#SQLAlchemy
|
||||||
|
#psycopg2
|
||||||
|
fastapi-users[sqlalchemy]
|
||||||
|
|
||||||
|
requests
|
||||||
|
websockets
|
||||||
|
python-dotenv
|
||||||
|
|
||||||
|
# fastapi libraries
|
||||||
|
fastapi[all]
|
||||||
|
fastapi-utilities
|
||||||
|
pydantic==2.6.0
|
||||||
|
pydantic-settings
|
||||||
|
alembic
|
||||||
|
# deployment libraries
|
||||||
|
uvicorn==0.27.0
|
||||||
|
gunicorn
|
||||||
|
|
||||||
|
|
||||||
|
# cryptographic libraries
|
||||||
|
python-jose
|
||||||
|
PyJWT
|
||||||
|
passlib
|
||||||
|
paramiko
|
||||||
|
|
||||||
|
|
||||||
|
python-multipart==0.0.12
|
||||||
|
filetype
|
||||||
|
biplist
|
||||||
|
|
||||||
|
|
||||||
@@ -1,28 +1,8 @@
|
|||||||
SQLAlchemy
|
fastapi
|
||||||
psycopg2
|
fastapi-users[sqlalchemy]
|
||||||
|
uvicorn[standard]
|
||||||
requests
|
aiosqlite
|
||||||
websockets
|
|
||||||
python-dotenv
|
|
||||||
|
|
||||||
# fastapi libraries
|
|
||||||
fastapi[all]
|
|
||||||
fastapi-utilities
|
|
||||||
pydantic==2.6.0
|
|
||||||
pydantic-settings
|
|
||||||
alembic
|
|
||||||
# deployment libraries
|
|
||||||
uvicorn==0.27.0
|
|
||||||
gunicorn
|
gunicorn
|
||||||
|
pydantic-settings
|
||||||
|
asyncpg
|
||||||
# cryptographic libraries
|
psycopg2
|
||||||
python-jose
|
|
||||||
PyJWT
|
|
||||||
passlib
|
|
||||||
paramiko
|
|
||||||
|
|
||||||
|
|
||||||
python-multipart==0.0.12
|
|
||||||
filetype
|
|
||||||
biplist
|
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
from fastapi import Depends, APIRouter, Request
|
# from fastapi import Depends, APIRouter, Request
|
||||||
from sqlalchemy.orm import Session
|
# from sqlalchemy.orm import Session
|
||||||
from apps.users.roles import Permission
|
# from apps.users.roles import Permission
|
||||||
from apps.users.services import permission_required, get_current_user, get_current_active_user
|
# from apps.users.services import permission_required, get_current_user, get_current_active_user
|
||||||
from pydantic import BaseModel
|
# from pydantic import BaseModel
|
||||||
from middleware.db_connection import get_db
|
# from middleware.db_connection import get_db
|
||||||
|
#
|
||||||
|
#
|
||||||
router = APIRouter(prefix="/agents", tags=["agents"])
|
# router = APIRouter(prefix="/agents", tags=["agents"])
|
||||||
|
#
|
||||||
|
#
|
||||||
class Agent(BaseModel):
|
# class Agent(BaseModel):
|
||||||
name: str
|
# name: str
|
||||||
|
#
|
||||||
|
#
|
||||||
@router.post("/", dependencies=[Depends(get_current_active_user)])
|
# @router.post("/", dependencies=[Depends(get_current_active_user)])
|
||||||
@permission_required(Permission.CREATE, Permission.READ)
|
# @permission_required(Permission.CREATE, Permission.READ)
|
||||||
async def create_agent(agent: Agent, request: Request, db: Session = Depends(get_db)):
|
# async def create_agent(agent: Agent, request: Request, db: Session = Depends(get_db)):
|
||||||
print(agent)
|
# print(agent)
|
||||||
return True
|
# return True
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
from apps.users.schemas import UserRead, UserCreate
|
||||||
|
from apps.users.services import fastapi_users, auth_backend
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
router.include_router(
|
||||||
|
fastapi_users.get_auth_router(auth_backend), prefix="/auth/jwt", tags=["auth"]
|
||||||
|
)
|
||||||
|
router.include_router(
|
||||||
|
fastapi_users.get_register_router(UserRead, UserCreate),
|
||||||
|
prefix="/auth",
|
||||||
|
tags=["auth"],
|
||||||
|
)
|
||||||
|
router.include_router(
|
||||||
|
fastapi_users.get_reset_password_router(),
|
||||||
|
prefix="/auth",
|
||||||
|
tags=["auth"],
|
||||||
|
)
|
||||||
|
router.include_router(
|
||||||
|
fastapi_users.get_verify_router(UserRead),
|
||||||
|
prefix="/auth",
|
||||||
|
tags=["auth"],
|
||||||
|
)
|
||||||
+25
-39
@@ -1,53 +1,39 @@
|
|||||||
from datetime import timedelta
|
from typing import List
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
|
from fastapi_users import FastAPIUsers
|
||||||
|
from fastapi_users.schemas import BaseUser
|
||||||
|
from sqlalchemy import asc
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from typing import Annotated
|
|
||||||
|
|
||||||
from apps.users.roles import Permission
|
from apps.users import crud
|
||||||
from apps.users.services import authenticate_user, create_access_token, get_current_active_user
|
from apps.users.models import User
|
||||||
from fastapi.security import OAuth2PasswordRequestForm
|
from apps.users.schemas import UserRead, UserUpdate
|
||||||
|
from apps.users.services import fastapi_users, current_active_user
|
||||||
from apps.users import crud, models, schemas
|
from database import get_user_db, get_async_session
|
||||||
from middleware.db_connection import get_db
|
from middleware.db_connection import get_db
|
||||||
|
from sqlalchemy.future import select
|
||||||
|
|
||||||
from apps.users.schemas import User, UserCreate, Token
|
# router = APIRouter()
|
||||||
from settings import config
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/users", tags=["users"])
|
router = APIRouter(prefix="/users", tags=["users"])
|
||||||
|
|
||||||
|
current_superuser = fastapi_users.current_user(active=True, superuser=True)
|
||||||
@router.post("/token", response_model=Token)
|
|
||||||
async def login_for_access_token(form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
|
|
||||||
db: Session = Depends(get_db)):
|
|
||||||
user = authenticate_user(db, form_data.username, form_data.password)
|
|
||||||
if not user:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
||||||
detail="Incorrect username or password",
|
|
||||||
headers={"WWW-Authenticate": "Bearer"},
|
|
||||||
)
|
|
||||||
access_token_expires = timedelta(minutes=config.ACCESS_TOKEN_EXPIRE_MINUTES)
|
|
||||||
access_token = create_access_token(data={"sub": user.email}, expires_delta=access_token_expires)
|
|
||||||
return Token(access_token=access_token, token_type="bearer")
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/list", response_model=list[User])
|
# @router.get("/list", response_model=list[BaseUser])
|
||||||
async def list_users(db: Session = Depends(get_db)):
|
# async def list_users(db: Session = Depends(get_db), user: User = Depends(current_superuser)):
|
||||||
db_users = crud.get_users(db)
|
# db_users = crud.get_users(db)
|
||||||
return db_users
|
# return db_users
|
||||||
|
|
||||||
|
|
||||||
@router.get("/me", response_model=User)
|
@router.get("/list", response_model=List[BaseUser])
|
||||||
async def read_users_me(current_user: Annotated[User, Depends(get_current_active_user)]):
|
async def get_users(skip: int = 0, limit: int = 10, session: AsyncSession = Depends(get_async_session)):
|
||||||
return current_user
|
users = await crud.get_users(session=session, skip=skip, limit=limit)
|
||||||
|
|
||||||
|
return users
|
||||||
@router.post("/", response_model=User)
|
|
||||||
def create_user(user: UserCreate, db: Session = Depends(get_db)):
|
|
||||||
db_user = crud.get_user_by_email(db, email=user.email)
|
|
||||||
if db_user:
|
|
||||||
raise HTTPException(status_code=400, detail="Email already registered")
|
|
||||||
return crud.create_user(db=db, user=user)
|
|
||||||
|
|
||||||
|
|
||||||
|
router.include_router(
|
||||||
|
fastapi_users.get_users_router(UserRead, UserUpdate)
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from routes.http import welcome, user, agent
|
from routes.http import welcome, user, agent, auth
|
||||||
|
|
||||||
api_router = APIRouter(prefix="/api", tags=["api"])
|
api_router = APIRouter(prefix="/api", tags=["api"])
|
||||||
api_router.include_router(welcome.router)
|
api_router.include_router(welcome.router)
|
||||||
api_router.include_router(user.router)
|
api_router.include_router(user.router)
|
||||||
api_router.include_router(agent.router)
|
api_router.include_router(auth.router)
|
||||||
|
# api_router.include_router(agent.router)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user