|
|
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 |
|
|
|
|
|
|
|
|
|
|
|
project_root = Path(__file__).resolve().parents[2] |
|
|
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 .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 = APIRouter(prefix="/auth", tags=["Authentication"]) |
|
|
|
|
|
|
|
|
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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() |
|
|
|
|
|
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} |
|
|
|
|
|
|
|
|
@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_apis_router.post("/login") |
|
|
def login(login_data: LoginRequest, db: Session = Depends(get_db)): |
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
user.last_login = datetime.now(timezone.utc) |
|
|
db.commit() |
|
|
db.refresh(user) |
|
|
|
|
|
|
|
|
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 { |
|
|
"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, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@login_apis_router.post("/logout") |
|
|
def logout(): |
|
|
return {"message": "User logged out successfully"} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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"} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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() |
|
|
|
|
|
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} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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)} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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. |
|
|
""" |
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
if user.role.lower() != "superadmin": |
|
|
raise HTTPException(status_code=403, detail="Only Superadmin can create an organization") |
|
|
|
|
|
|
|
|
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, |
|
|
db: Session = Depends(get_db), |
|
|
auth_data: dict = Depends(require_auth) |
|
|
): |
|
|
""" |
|
|
Update organization details. |
|
|
Only Superadmin users can update organization details. |
|
|
""" |
|
|
|
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
if user.role.lower() != "superadmin": |
|
|
raise HTTPException(status_code=403, detail="Only Superadmin can update organization details") |
|
|
|
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
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. |
|
|
""" |
|
|
|
|
|
|
|
|
user_id = auth_data.get("user_id") |
|
|
if not user_id: |
|
|
raise HTTPException(status_code=401, detail="User not authenticated") |
|
|
|
|
|
|
|
|
user = db.query(models.User).filter(models.User.id == user_id).first() |
|
|
if not user: |
|
|
raise HTTPException(status_code=404, detail="User not found") |
|
|
|
|
|
|
|
|
if user.role.lower() != "superadmin": |
|
|
raise HTTPException(status_code=403, detail="Only Superadmin can delete organizations") |
|
|
|
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
org.deleted_at = datetime.now(timezone.utc) |
|
|
db.commit() |
|
|
|
|
|
return {"message": f"Organization '{org.name}' deleted successfully"} |
|
|
|
|
|
|
|
|
|
|
|
|