srivatsavdamaraju's picture
Upload 39 files
fd21f0c verified
import os
from fastapi import FastAPI, Depends, HTTPException , Depends , status
from sqlalchemy.orm import Session
import os
import sys
from pathlib import Path
import json
# ensure project root (agent/) is on sys.path so sibling packages like "s3" can be imported
project_root = Path(__file__).resolve().parents[2] # -> ...\openai_agents\agent
if str(project_root) not in sys.path:
sys.path.insert(0, str(project_root))
from passlib.context import CryptContext
from dotenv import load_dotenv
from sqlalchemy import text
# from . import database, models, crud
# import database , models , crud
from .schemas import (
UserCreate,
UserResponse,
ConversationCreate,
ConversationResponse,
OrganizationCreate,
OrganizationResponse,
PlanCreate,
PlanResponse,
LoginRequest,
DatasetBase,
DatasetCreate,
DatasetUpdate,
DatasetResponse,
UserDatasetsMetadataBase,
UserDatasetsMetadataCreate,
UserDatasetsMetadataResponse,
OrganizationBase,
OrganizationCreate,
OrganizationUpdate,
OrganizationResponse
)
from .database import create_tables, get_db, engine
from . import crud, models
from uuid import UUID
from fastapi.security import OAuth2PasswordRequestForm
from datetime import timedelta, datetime, timezone
from . import auth
from .decorators import require_auth
from fastapi import APIRouter
load_dotenv()
# login_apis_router = FastAPI(title="MyApp", version="1.0.0")
login_apis_router = APIRouter(prefix="/auth", tags=["Authentication"])
# Qdrant_router = APIRouter(prefix="/qdrant", tags=["Qdrant_Collections"])
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# @login_apis_router.on_event("startup")
# def on_startup():
# create_tables()
# print("Database tables created/checked")
@login_apis_router.get("/")
def health():
return {"message": "OK"}
@login_apis_router.post("/users/create")
def create_user_endpoint(user: UserCreate, db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
if crud.get_user_by_username(db, user.username) or crud.get_user_by_email(db, user.email):
raise HTTPException(status_code=400, detail="username or email already exists")
hashed = pwd_context.hash(user.password)
created = crud.create_user(db, user, hashed)
return created
@login_apis_router.get("/users")
def list_users(db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
print("Listing all users")
users = db.query(models.User).all()
# print("all users retrieved",users)
return {"users": users, "count": len(users)}
@login_apis_router.get("/users/{username}")
def get_user_by_username(username: str, db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
user = crud.get_user_by_username(db, username)
print("get user by username api hitted")
if not user:
raise HTTPException(status_code=404, detail=f"User '{username}' not found")
return {"user": user}
# 🔹 Get user by ID (UUID)
@login_apis_router.get("/users/id/{user_id}")
def get_user_by_id(user_id: UUID, db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
user = db.query(models.User).filter(models.User.id == user_id).first()
if not user:
raise HTTPException(status_code=404, detail=f"User with id '{user_id}' not found")
return {"user": user}
# Login - returns JWT token
@login_apis_router.post("/login")
def login(login_data: LoginRequest, db: Session = Depends(get_db)):
# Find user by email
user = db.query(models.User).filter(models.User.email == login_data.email).first()
if not user or not auth.verify_password(login_data.password, user.password):
raise HTTPException(status_code=401, detail="Invalid email or password")
# Update last login time
user.last_login = datetime.now(timezone.utc)
db.commit()
db.refresh(user)
# Create JWT token
access_token_expires = timedelta(minutes=auth.ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = auth.create_access_token(
data={"sub": user.email}, expires_delta=access_token_expires
)
# Return token and complete user data
return {
"message": "User Logged in Successfully",
"access_token": access_token,
"token_type": "bearer",
"user": {
"id": str(user.id),
"fullname": user.fullname,
"username": user.username,
"email": user.email,
"role": user.role,
"is_active": user.is_active,
"last_login": user.last_login.isoformat() if user.last_login else None,
"organization_id": str(user.organization_id) if user.organization_id else None,
"provider_id": str(user.provider_id) if user.provider_id else None,
"created_at": user.created_at.isoformat() if user.created_at else None,
"updated_at": user.updated_at.isoformat() if user.updated_at else None,
}
}
# 🚪 Logout - JWT is stateless, so simulate logout
@login_apis_router.post("/logout")
def logout():
return {"message": "User logged out successfully"}
# @login_apis_router.post("/conversations", status_code=201)
# async def create_conversation(payload: dict, db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
# """
# Create a new conversation entry using raw SQL
# """
# try:
# user_id = payload.get("user_id")
# convo_id = payload.get("convo_id")
# data = payload.get("data", {})
# is_saved = payload.get("is_saved", False)
# # Convert data fields to JSON
# user_query = json.dumps(data.get("user_query", {}))
# response = json.dumps(data.get("response", {}))
# # Extract file_metadata (if present inside response.artifacts)
# artifacts = data.get("response", {}).get("artifacts", [])
# file_metadata = json.dumps(artifacts) if artifacts else json.dumps([])
# created_at = datetime.now(timezone.utc)
# updated_at = created_at
# insert_query = text("""
# INSERT INTO conversation_data (user_id, convo_id, user_query, response, file_metadata, is_saved,created_at, updated_at)
# VALUES (:user_id, :convo_id, :user_query, :response, :file_metadata, :is_saved, :created_at, :updated_at)
# RETURNING id, created_at, updat
# """)
# result = db.execute(insert_query, {
# "user_id": user_id,
# "convo_id": convo_id,
# "user_query": user_query,
# "response": response,
# "file_metadata": file_metadata,
# "is_saved": is_saved,
# "created_at": created_at,
# "updated_at": updated_at
# })
# db.commit()
# inserted = result.fetchone()
# return {
# "message": "Conversation created successfully",
# "id": str(inserted[0]),
# "convo_id": convo_id,
# "created_at": str(inserted[1]),
# "is_saved": is_saved
# }
# except Exception as e:
# db.rollback()
# raise HTTPException(status_code=500, detail=f"Error creating conversation: {str(e)}")
# @login_apis_router.post("/conversations", status_code=201)
# async def create_conversation(payload: dict, db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
# """
# Create a new conversation entry using raw SQL
# """
# try:
# user_id = payload.get("user_id")
# convo_id = payload.get("convo_id")
# data = payload.get("data", {})
# is_saved = payload.get("is_saved", False)
# # Convert data fields to JSON
# user_query = json.dumps(data.get("user_query", {}))
# response = json.dumps(data.get("response", {}))
# # Extract file_metadata (if present inside response.artifacts)
# artifacts = data.get("response", {}).get("artifacts", [])
# file_metadata = json.dumps(artifacts) if artifacts else json.dumps([])
# created_at = datetime.now(timezone.utc)
# updated_at = created_at
# insert_query = text("""
# INSERT INTO conversation_data (
# user_id, convo_id, user_query, response, file_metadata, is_saved, created_at, updated_at
# )
# VALUES (
# :user_id, :convo_id, :user_query, :response, :file_metadata, :is_saved, :created_at, :updated_at
# )
# RETURNING id, created_at
# """)
# result = db.execute(insert_query, {
# "user_id": user_id,
# "convo_id": convo_id,
# "user_query": user_query,
# "response": response,
# "file_metadata": file_metadata,
# "is_saved": is_saved,
# "created_at": created_at,
# "updated_at": updated_at
# })
# db.commit()
# inserted = result.fetchone()
# return {
# "message": "Conversation created successfully",
# "id": str(inserted[0]),
# "convo_id": convo_id,
# "created_at": str(inserted[1]),
# "is_saved": is_saved
# }
# except Exception as e:
# db.rollback()
# raise HTTPException(status_code=500, detail=f"Error creating conversation: {str(e)}")
@login_apis_router.delete("/reset-db")
def reset_database():
with engine.connect() as conn:
conn.execute(text("DROP SCHEMA public CASCADE;"))
conn.execute(text("CREATE SCHEMA public;"))
conn.commit()
return {"message": " All tables dropped and schema reset successfully"}
# -----------------------------
# ORGANIZATION ROUTES
# -----------------------------
@login_apis_router.post("/Createorganizations", status_code=201)
def create_organization(payload: OrganizationCreate, db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
org = models.Organization(
name=payload.name,
domain=payload.domain,
plan_id=payload.plan_id,
location=payload.location,
city=payload.city,
state=payload.state,
country=payload.country,
is_active=payload.is_active if payload.is_active is not None else True,
)
db.add(org)
db.commit()
db.refresh(org)
return {"organization": org}
@login_apis_router.get("/organizations")
def list_organizations(db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
print("organization api hitted")
organizations=db.query(models.Organization).all()
# print("organization data",query)
return {"organizations": organizations, "count": len(organizations)}
@login_apis_router.get("/organizations/{organization_id}")
def get_organization(organization_id: UUID, db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
org = db.query(models.Organization).filter(models.Organization.id == organization_id).first()
if not org:
raise HTTPException(status_code=404, detail=f"Organization with id '{organization_id}' not found")
return {"organization": org}
# -----------------------------
# DATASET ROUTES
# -----------------------------
@login_apis_router.get("/getuserdatasets/{user_id}")
def get_datasets_by_user(user_id: UUID, db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
datasets = db.query(models.Dataset).filter(models.Dataset.created_by == user_id).all()
if not datasets:
raise HTTPException(status_code=404, detail=f"No datasets found for user ID {user_id}")
return {"datasets": datasets, "count": len(datasets)}
# -----------------------------
# PLAN ROUTES
# -----------------------------
@login_apis_router.post("/Createplans", response_model=PlanResponse, status_code=201)
def create_plan(payload: PlanCreate, db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
plan = models.Plan(
plan_type=payload.plan_type,
price=payload.price,
features=payload.features,
)
db.add(plan)
db.commit()
db.refresh(plan)
return plan
@login_apis_router.get("/plans", response_model=list[PlanResponse])
def list_plans(db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
return db.query(models.Plan).all()
@login_apis_router.get("/plans/{plan_id}", response_model=PlanResponse)
def get_plan(plan_id: UUID, db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
plan = db.query(models.Plan).filter(models.Plan.id == plan_id).first()
if not plan:
raise HTTPException(status_code=404, detail=f"Plan with id '{plan_id}' not found")
return plan
# -----------------------------
# USERMETADATA ROUTES
# -----------------------------
@login_apis_router.post("/UserMetadataCreate", response_model=UserDatasetsMetadataResponse)
def create_metadata(metadata_in: UserDatasetsMetadataCreate, db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
return crud.create_user_dataset_metadata(db=db, metadata_in=metadata_in)
@login_apis_router.get("/UserMetadata/{user_id}", response_model=list[UserDatasetsMetadataResponse])
def get_metadata(user_id: str, db: Session = Depends(get_db), auth_data: dict = Depends(require_auth)):
result = crud.get_user_dataset_metadata(db=db, user_id=user_id)
if not result:
raise HTTPException(status_code=404, detail="No metadata found for this user.")
return result
# -----------------------------
# ORGANIZATIONS ROUTES
# -----------------------------
@login_apis_router.post("/createorganization")
def create_organization(payload: OrganizationCreate, db: Session = Depends(get_db)):
"""
API to create an organization.
Only users with role='superadmin' can create an organization.
"""
# Step 1: Fetch user from User table using user_id from payload
user = db.query(models.User).filter(models.User.id == payload.created_by).first()
if not user:
raise HTTPException(status_code=404, detail="User not found")
# Step 2: Validate user role
if user.role.lower() != "superadmin":
raise HTTPException(status_code=403, detail="Only Superadmin can create an organization")
# Step 3: Create new organization entry
new_org = models.Organization(
name=payload.name,
domain=payload.domain,
plan_id=payload.plan_id,
location=payload.location,
city=payload.city,
state=payload.state,
country=payload.country,
is_active=payload.is_active,
created_by=payload.created_by,
created_at=datetime.utcnow(),
updated_at=datetime.utcnow(),
)
db.add(new_org)
db.commit()
db.refresh(new_org)
return {"message": "Organization created successfully", "organization": new_org}
@login_apis_router.get("/getorganizations", response_model=list[OrganizationResponse])
def get_all_organizations(
db: Session = Depends(get_db),
auth_data: dict = Depends(require_auth)
):
"""Fetch all active organizations."""
orgs = db.query(models.Organization).filter(models.Organization.deleted_at.is_(None)).all()
return orgs
@login_apis_router.get("/getorganization/{org_id}", response_model=OrganizationResponse)
def get_organization_by_id(
org_id: UUID,
db: Session = Depends(get_db),
auth_data: dict = Depends(require_auth)
):
"""Fetch a specific organization by ID."""
org = db.query(models.Organization).filter(
models.Organization.id == org_id,
models.Organization.deleted_at.is_(None)
).first()
if not org:
raise HTTPException(status_code=404, detail="Organization not found")
return org
@login_apis_router.put("/updateorganization/{org_id}", response_model=OrganizationResponse)
def update_organization(
org_id: UUID,
org_data: OrganizationCreate, # still using this schema to receive update data
db: Session = Depends(get_db),
auth_data: dict = Depends(require_auth)
):
"""
Update organization details.
Only Superadmin users can update organization details.
"""
# Step 1: Verify user exists
user = db.query(models.User).filter(models.User.id == org_data.created_by).first()
if not user:
raise HTTPException(status_code=404, detail="User not found")
# Step 2: Verify role = superadmin
if user.role.lower() != "superadmin":
raise HTTPException(status_code=403, detail="Only Superadmin can update organization details")
# Step 3: Check organization exists
org = db.query(models.Organization).filter(
models.Organization.id == org_id,
models.Organization.deleted_at.is_(None)
).first()
if not org:
raise HTTPException(status_code=404, detail="Organization not found")
# Step 4: Update organization fields
update_data = org_data.dict(exclude_unset=True)
for key, value in update_data.items():
setattr(org, key, value)
org.updated_at = datetime.now(timezone.utc)
db.commit()
db.refresh(org)
return org
@login_apis_router.delete("/deleteorganization/{org_id}")
def delete_organization(
org_id: UUID,
db: Session = Depends(get_db),
auth_data: dict = Depends(require_auth)
):
"""
Soft delete an organization.
Only Superadmin users can perform this action.
"""
# Step 1: Extract user_id from token
user_id = auth_data.get("user_id")
if not user_id:
raise HTTPException(status_code=401, detail="User not authenticated")
# Step 2: Fetch user from DB
user = db.query(models.User).filter(models.User.id == user_id).first()
if not user:
raise HTTPException(status_code=404, detail="User not found")
# Step 3: Check if user is Superadmin
if user.role.lower() != "superadmin":
raise HTTPException(status_code=403, detail="Only Superadmin can delete organizations")
# Step 4: Find organization
org = db.query(models.Organization).filter(
models.Organization.id == org_id,
models.Organization.deleted_at.is_(None)
).first()
if not org:
raise HTTPException(status_code=404, detail="Organization not found")
# Step 5: Soft delete (mark deleted_at timestamp)
org.deleted_at = datetime.now(timezone.utc)
db.commit()
return {"message": f"Organization '{org.name}' deleted successfully"}