162 lines
5.2 KiB
Python

from fastapi import FastAPI, Depends
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pathlib import Path
from app.database import create_db_and_tables, get_session
from app.config import get_settings
from app.routers import auth, departments, channels, messages, files, websocket, snippets, admin, direct_messages, kanban, last_seen
from app.auth import get_current_user
from app.models import User, DirectMessage, Department
from sqlmodel import Session, select
settings = get_settings()
app = FastAPI(
title="Team Chat API",
description="Internal chat application similar to Microsoft Teams",
version="1.0.0"
)
try:
from starlette.middleware.proxy_headers import ProxyHeadersMiddleware
# Honor proxy headers (X-Forwarded-For, X-Forwarded-Proto) when behind nginx
app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*")
except ImportError:
import logging
logging.getLogger(__name__).warning("ProxyHeadersMiddleware not available. Start uvicorn with --proxy-headers or install 'starlette' to enable forwarded header handling.")
# CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=[
"http://localhost:5173",
"http://localhost:3000",
"http://127.0.0.1:5173",
"http://127.0.0.1:3000",
"https://collabrix.apex-project.de",
"http://collabrix.apex-project.de"
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Mount uploads directory as static files
# Get the directory where this file is located
current_dir = Path(__file__).parent.parent
uploads_dir = current_dir / "uploads"
uploads_dir.mkdir(exist_ok=True)
app.mount("/uploads", StaticFiles(directory=str(uploads_dir)), name="uploads")
# Event handlers
@app.on_event("startup")
def on_startup():
"""Create database tables on startup"""
create_db_and_tables()
# Include routers
app.include_router(auth.router)
app.include_router(admin.router)
app.include_router(departments.router)
app.include_router(channels.router)
app.include_router(messages.router)
app.include_router(direct_messages.router)
app.include_router(files.router)
app.include_router(snippets.router)
app.include_router(kanban.router)
app.include_router(websocket.router)
app.include_router(last_seen.router)
# Mount uploads directory for file serving
uploads_dir = Path(__file__).parent.parent / "uploads"
uploads_dir.mkdir(parents=True, exist_ok=True)
app.mount("/files", StaticFiles(directory=uploads_dir), name="files")
@app.get("/")
def read_root():
"""Root endpoint"""
return {
"message": "Welcome to Team Chat API",
"docs": "/docs",
"version": "1.0.0"
}
@app.get("/health")
def health_check():
"""Health check endpoint"""
return {"status": "healthy"}
@app.get("/user-status")
def get_user_statuses(session: Session = Depends(get_session), current_user: User = Depends(get_current_user)):
"""Get online status for users in same department and users with existing private chats"""
from app.websocket import manager
# Get users from same department
department_users = []
if current_user.departments:
dept_ids = [dept.id for dept in current_user.departments]
dept_statement = select(User).where(User.departments.any(Department.id.in_(dept_ids)))
department_users = session.exec(dept_statement).all()
# Get users with existing private chats
# Find all direct messages where current user is sender or receiver
dm_statement = select(DirectMessage).where(
(DirectMessage.sender_id == current_user.id) | (DirectMessage.receiver_id == current_user.id)
)
direct_messages = session.exec(dm_statement).all()
# Extract unique user IDs (excluding current user)
chat_partner_ids = set()
for dm in direct_messages:
if dm.sender_id != current_user.id:
chat_partner_ids.add(dm.sender_id)
if dm.receiver_id != current_user.id:
chat_partner_ids.add(dm.receiver_id)
# Get chat partner users
if chat_partner_ids:
chat_partners_statement = select(User).where(User.id.in_(chat_partner_ids))
chat_partners = session.exec(chat_partners_statement).all()
else:
chat_partners = []
# Combine and deduplicate users by ID
all_user_ids = set()
all_users = []
# Add department users
for user in department_users:
if user.id not in all_user_ids:
all_user_ids.add(user.id)
all_users.append(user)
# Add chat partners
for user in chat_partners:
if user.id not in all_user_ids:
all_user_ids.add(user.id)
all_users.append(user)
# Remove current user from the list
all_users = [user for user in all_users if user.id != current_user.id]
# Get their statuses
statuses = manager.get_all_user_statuses()
# Build response
result = []
for user in all_users:
status = statuses.get(user.id, "offline")
result.append({
"user_id": user.id,
"username": user.username,
"full_name": user.full_name,
"status": status
})
return result