local tests
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-09-26 06:01:35 +09:00
parent ddce9f5125
commit d47f8679ec
4 changed files with 575 additions and 128 deletions

View File

@@ -185,9 +185,70 @@ async def rate_limiting_middleware(request: Request, call_next):
return await call_next(request) return await call_next(request)
# Authentication routes
@app.post("/api/v1/auth/register", response_model=UserResponse, tags=["Authentication"], summary="Register a new user")
async def register_user(user_create: UserCreate, request: Request):
"""Register a new user"""
async with httpx.AsyncClient(timeout=30.0) as client:
try:
response = await client.post(
f"{SERVICES['users']}/api/v1/auth/register",
json=user_create.model_dump(),
headers={
"Content-Type": "application/json",
"Accept": "application/json"
}
)
if response.status_code == 200:
return response.json()
else:
error_detail = response.text
try:
error_json = response.json()
error_detail = error_json.get("detail", error_detail)
except:
pass
raise HTTPException(status_code=response.status_code, detail=error_detail)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=f"Registration error: {str(e)}")
@app.post("/api/v1/auth/login", response_model=Token, tags=["Authentication"], summary="Login user")
async def login_user(user_login: UserLogin, request: Request):
"""Login user"""
async with httpx.AsyncClient(timeout=30.0) as client:
try:
response = await client.post(
f"{SERVICES['users']}/api/v1/auth/login",
json=user_login.model_dump(),
headers={
"Content-Type": "application/json",
"Accept": "application/json"
}
)
if response.status_code == 200:
return response.json()
else:
error_detail = response.text
try:
error_json = response.json()
error_detail = error_json.get("detail", error_detail)
except:
pass
raise HTTPException(status_code=response.status_code, detail=error_detail)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=f"Login error: {str(e)}")
# User Service routes # User Service routes
@app.post("/api/v1/auth/register", operation_id="user_auth_register", response_model=UserResponse, tags=["Authentication"], summary="Register a new user")
@app.post("/api/v1/auth/login", operation_id="user_auth_login", response_model=Token, tags=["Authentication"], summary="Login user")
@app.post("/api/v1/users/register", operation_id="user_register", response_model=UserResponse, tags=["Users"], summary="Register a new user") @app.post("/api/v1/users/register", operation_id="user_register", response_model=UserResponse, tags=["Users"], summary="Register a new user")
@app.get("/api/v1/users/me", operation_id="user_me_get", response_model=UserResponse, tags=["Users"], summary="Get current user profile") @app.get("/api/v1/users/me", operation_id="user_me_get", response_model=UserResponse, tags=["Users"], summary="Get current user profile")
@app.patch("/api/v1/users/me", operation_id="user_me_patch", response_model=UserResponse, tags=["Users"], summary="Update user profile") @app.patch("/api/v1/users/me", operation_id="user_me_patch", response_model=UserResponse, tags=["Users"], summary="Update user profile")

View File

@@ -1,10 +1,11 @@
import asyncio import asyncio
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import List
import httpx import httpx
from fastapi import BackgroundTasks, Depends, FastAPI, HTTPException, status from fastapi import BackgroundTasks, Depends, FastAPI, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy import func, select from sqlalchemy import func, select, update
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from services.emergency_service.models import EmergencyAlert, EmergencyResponse from services.emergency_service.models import EmergencyAlert, EmergencyResponse
@@ -18,7 +19,7 @@ from services.emergency_service.schemas import (
from services.user_service.models import User from services.user_service.models import User
from shared.auth import get_current_user_from_token from shared.auth import get_current_user_from_token
from shared.config import settings from shared.config import settings
from shared.database import AsyncSessionLocal, get_db from shared.database import get_db
app = FastAPI(title="Emergency Service", version="1.0.0") app = FastAPI(title="Emergency Service", version="1.0.0")
@@ -55,7 +56,7 @@ async def health_check():
async def get_nearby_users( async def get_nearby_users(
latitude: float, longitude: float, radius_km: float = 1.0 latitude: float, longitude: float, radius_km: float = 1.0
) -> list: ) -> List[dict]:
"""Get users within radius using Location Service""" """Get users within radius using Location Service"""
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
try: try:
@@ -75,7 +76,7 @@ async def get_nearby_users(
return [] return []
async def send_emergency_notifications(alert_id: int, nearby_users: list): async def send_emergency_notifications(alert_id: int, nearby_users: List[dict]):
"""Send push notifications to nearby users""" """Send push notifications to nearby users"""
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
try: try:
@@ -98,15 +99,14 @@ async def create_emergency_alert(
current_user: User = Depends(get_current_user), current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db), db: AsyncSession = Depends(get_db),
): ):
"""Create new emergency alert and notify nearby users""" """Create new emergency alert"""
# Create alert # Create alert
db_alert = EmergencyAlert( db_alert = EmergencyAlert(
user_id=current_user.id, user_id=current_user.id,
latitude=alert_data.latitude, latitude=alert_data.latitude,
longitude=alert_data.longitude, longitude=alert_data.longitude,
address=alert_data.address, address=alert_data.address,
alert_type=alert_data.alert_type.value, alert_type=alert_data.alert_type,
message=alert_data.message, message=alert_data.message,
) )
@@ -114,34 +114,45 @@ async def create_emergency_alert(
await db.commit() await db.commit()
await db.refresh(db_alert) await db.refresh(db_alert)
# Get nearby users and send notifications in background # Process alert in background
background_tasks.add_task( background_tasks.add_task(
process_emergency_alert, db_alert.id, alert_data.latitude, alert_data.longitude process_emergency_alert_in_background,
int(db_alert.id), # Convert to int explicitly
alert_data.latitude,
alert_data.longitude
) )
return EmergencyAlertResponse.model_validate(db_alert) return EmergencyAlertResponse.model_validate(db_alert)
async def process_emergency_alert(alert_id: int, latitude: float, longitude: float): async def process_emergency_alert_in_background(alert_id: int, latitude: float, longitude: float):
"""Process emergency alert - get nearby users and send notifications""" """Process emergency alert - notify nearby users"""
# Get nearby users try:
nearby_users = await get_nearby_users( # Get nearby users
latitude, longitude, settings.MAX_EMERGENCY_RADIUS_KM nearby_users = await get_nearby_users(latitude, longitude)
)
# Update alert with notified users count if nearby_users:
async with AsyncSessionLocal() as db: # Create new database session for background task
result = await db.execute( from shared.database import AsyncSessionLocal
select(EmergencyAlert).filter(EmergencyAlert.id == alert_id) async with AsyncSessionLocal() as db:
) try:
alert = result.scalars().first() # Update alert with notification count
if alert: await db.execute(
alert.notified_users_count = len(nearby_users) update(EmergencyAlert)
await db.commit() .where(EmergencyAlert.id == alert_id)
.values(notified_users_count=len(nearby_users))
)
await db.commit()
# Send notifications # Send notifications
if nearby_users: await send_emergency_notifications(alert_id, nearby_users)
await send_emergency_notifications(alert_id, nearby_users)
except Exception as e:
print(f"Error processing emergency alert: {e}")
await db.rollback()
except Exception as e:
print(f"Error in process_emergency_alert_in_background: {e}")
@app.post("/api/v1/alert/{alert_id}/respond", response_model=EmergencyResponseResponse) @app.post("/api/v1/alert/{alert_id}/respond", response_model=EmergencyResponseResponse)
@@ -152,44 +163,46 @@ async def respond_to_alert(
db: AsyncSession = Depends(get_db), db: AsyncSession = Depends(get_db),
): ):
"""Respond to emergency alert""" """Respond to emergency alert"""
# Check if alert exists # Check if alert exists
result = await db.execute( result = await db.execute(select(EmergencyAlert).filter(EmergencyAlert.id == alert_id))
select(EmergencyAlert).filter(EmergencyAlert.id == alert_id)
)
alert = result.scalars().first() alert = result.scalars().first()
if not alert: if not alert:
raise HTTPException(status_code=404, detail="Alert not found") raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Alert not found"
)
if alert.is_resolved: # Check if already responded
raise HTTPException(status_code=400, detail="Alert already resolved")
# Check if user already responded
existing_response = await db.execute( existing_response = await db.execute(
select(EmergencyResponse).filter( select(EmergencyResponse).filter(
EmergencyResponse.alert_id == alert_id, EmergencyResponse.alert_id == alert_id,
EmergencyResponse.responder_id == current_user.id, EmergencyResponse.user_id == current_user.id
) )
) )
if existing_response.scalars().first(): if existing_response.scalars().first():
raise HTTPException( raise HTTPException(
status_code=400, detail="You already responded to this alert" status_code=status.HTTP_400_BAD_REQUEST,
detail="You have already responded to this alert"
) )
# Create response # Create response
db_response = EmergencyResponse( db_response = EmergencyResponse(
alert_id=alert_id, alert_id=alert_id,
responder_id=current_user.id, user_id=current_user.id,
response_type=response_data.response_type.value, response_type=response_data.response_type,
message=response_data.message, message=response_data.message,
eta_minutes=response_data.eta_minutes, eta_minutes=response_data.eta_minutes,
) )
db.add(db_response) db.add(db_response)
# Update responded users count # Update responded users count
alert.responded_users_count += 1 await db.execute(
update(EmergencyAlert)
.where(EmergencyAlert.id == alert_id)
.values(responded_users_count=EmergencyAlert.responded_users_count + 1)
)
await db.commit() await db.commit()
await db.refresh(db_response) await db.refresh(db_response)
@@ -202,116 +215,110 @@ async def resolve_alert(
current_user: User = Depends(get_current_user), current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db), db: AsyncSession = Depends(get_db),
): ):
"""Mark alert as resolved (only by alert creator)""" """Resolve emergency alert"""
result = await db.execute(select(EmergencyAlert).filter(EmergencyAlert.id == alert_id))
result = await db.execute(
select(EmergencyAlert).filter(EmergencyAlert.id == alert_id)
)
alert = result.scalars().first() alert = result.scalars().first()
if not alert: if not alert:
raise HTTPException(status_code=404, detail="Alert not found") raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Alert not found"
)
# Only alert creator can resolve
if alert.user_id != current_user.id: if alert.user_id != current_user.id:
raise HTTPException(status_code=403, detail="Only alert creator can resolve it") raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
if alert.is_resolved: detail="Only alert creator can resolve the alert"
raise HTTPException(status_code=400, detail="Alert already resolved") )
alert.is_resolved = True
alert.resolved_at = datetime.utcnow()
alert.resolved_by = current_user.id
# Update alert
await db.execute(
update(EmergencyAlert)
.where(EmergencyAlert.id == alert_id)
.values(
is_resolved=True,
resolved_at=datetime.utcnow(),
resolved_by=current_user.id
)
)
await db.commit() await db.commit()
return {"message": "Alert resolved successfully"} return {"message": "Alert resolved successfully"}
@app.get("/api/v1/alerts/my", response_model=list[EmergencyAlertResponse]) @app.get("/api/v1/alerts/my", response_model=List[EmergencyAlertResponse])
async def get_my_alerts( async def get_my_alerts(
current_user: User = Depends(get_current_user), current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db), db: AsyncSession = Depends(get_db)
limit: int = 50,
): ):
"""Get current user's emergency alerts""" """Get current user's emergency alerts"""
result = await db.execute( result = await db.execute(
select(EmergencyAlert) select(EmergencyAlert)
.filter(EmergencyAlert.user_id == current_user.id) .filter(EmergencyAlert.user_id == current_user.id)
.order_by(EmergencyAlert.created_at.desc()) .order_by(EmergencyAlert.created_at.desc())
.limit(limit)
) )
alerts = result.scalars().all() alerts = result.scalars().all()
return [EmergencyAlertResponse.model_validate(alert) for alert in alerts] return [EmergencyAlertResponse.model_validate(alert) for alert in alerts]
@app.get("/api/v1/alerts/active", response_model=list[EmergencyAlertResponse]) @app.get("/api/v1/alerts/active", response_model=List[EmergencyAlertResponse])
async def get_active_alerts( async def get_active_alerts(
current_user: User = Depends(get_current_user), current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db), db: AsyncSession = Depends(get_db)
limit: int = 20,
): ):
"""Get active alerts in user's area (last 2 hours)""" """Get active emergency alerts"""
# Get user's current location first
async with httpx.AsyncClient() as client:
try:
response = await client.get(
f"http://localhost:8003/api/v1/user-location/{current_user.id}",
timeout=5.0,
)
if response.status_code != 200:
raise HTTPException(
status_code=400, detail="User location not available"
)
location_data = response.json()
except Exception:
raise HTTPException(status_code=400, detail="Location service unavailable")
# Get alerts from last 2 hours
two_hours_ago = datetime.utcnow() - timedelta(hours=2)
result = await db.execute( result = await db.execute(
select(EmergencyAlert) select(EmergencyAlert)
.filter( .filter(EmergencyAlert.is_resolved == False)
EmergencyAlert.is_resolved == False,
EmergencyAlert.created_at >= two_hours_ago,
)
.order_by(EmergencyAlert.created_at.desc()) .order_by(EmergencyAlert.created_at.desc())
.limit(limit) .limit(50)
) )
alerts = result.scalars().all() alerts = result.scalars().all()
return [EmergencyAlertResponse.model_validate(alert) for alert in alerts]
@app.get("/api/v1/emergency/reports", response_model=List[EmergencyAlertResponse])
async def get_emergency_reports(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db)
):
"""Get emergency reports/alerts for admin users or general statistics"""
# For now, return all active alerts (in production, add admin check)
result = await db.execute(
select(EmergencyAlert)
.filter(EmergencyAlert.is_resolved == False)
.order_by(EmergencyAlert.created_at.desc())
.limit(50)
)
alerts = result.scalars().all()
return [EmergencyAlertResponse.model_validate(alert) for alert in alerts] return [EmergencyAlertResponse.model_validate(alert) for alert in alerts]
@app.get("/api/v1/stats", response_model=EmergencyStats) @app.get("/api/v1/stats", response_model=EmergencyStats)
async def get_emergency_stats( async def get_emergency_stats(
current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db) current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db)
): ):
"""Get emergency service statistics""" """Get emergency statistics"""
# Get total alerts count
# Get total alerts total_alerts_result = await db.execute(select(func.count(EmergencyAlert.id)))
total_result = await db.execute(select(func.count(EmergencyAlert.id))) total_alerts = total_alerts_result.scalar() or 0
total_alerts = total_result.scalar()
# Get active alerts count
# Get active alerts active_alerts_result = await db.execute(
active_result = await db.execute( select(func.count(EmergencyAlert.id)).filter(EmergencyAlert.is_resolved == False)
select(func.count(EmergencyAlert.id)).filter(
EmergencyAlert.is_resolved == False
)
) )
active_alerts = active_result.scalar() active_alerts = active_alerts_result.scalar() or 0
# Get resolved alerts # Calculate resolved alerts
resolved_alerts = total_alerts - active_alerts resolved_alerts = total_alerts - active_alerts
# Get total responders # Get total responders count
responders_result = await db.execute( total_responders_result = await db.execute(select(func.count(EmergencyResponse.id)))
select(func.count(func.distinct(EmergencyResponse.responder_id))) total_responders = total_responders_result.scalar() or 0
)
total_responders = responders_result.scalar()
return EmergencyStats( return EmergencyStats(
total_alerts=total_alerts, total_alerts=total_alerts,
@@ -322,13 +329,6 @@ async def get_emergency_stats(
) )
@app.get("/api/v1/health")
async def health_check():
"""Health check endpoint"""
return {"status": "healthy", "service": "emergency-service"}
if __name__ == "__main__": if __name__ == "__main__":
import uvicorn import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8002)
uvicorn.run(app, host="0.0.0.0", port=8002)

View File

@@ -0,0 +1,379 @@
import asyncio
from datetime import datetime, timedelta
from typing import List
import httpx
from fastapi import BackgroundTasks, Depends, FastAPI, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy import func, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from services.emergency_service.models import EmergencyAlert, EmergencyResponse
from services.emergency_service.schemas import (
EmergencyAlertCreate,
EmergencyAlertResponse,
EmergencyResponseCreate,
EmergencyResponseResponse,
EmergencyStats,
)
from services.user_service.models import User
from shared.auth import get_current_user_from_token
from shared.config import settings
from shared.database import get_db
app = FastAPI(title="Emergency Service", version="1.0.0")
# CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=settings.CORS_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
async def get_current_user(
user_data: dict = Depends(get_current_user_from_token),
db: AsyncSession = Depends(get_db),
):
"""Get current user from token via auth dependency."""
# Get full user object from database
result = await db.execute(select(User).filter(User.id == user_data["user_id"]))
user = result.scalars().first()
if user is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="User not found"
)
return user
@app.get("/health")
async def health_check():
"""Health check endpoint"""
return {"status": "healthy", "service": "emergency_service"}
async def get_nearby_users(
latitude: float, longitude: float, radius_km: float = 1.0
) -> List[dict]:
"""Get users within radius using Location Service"""
async with httpx.AsyncClient() as client:
try:
response = await client.get(
f"http://localhost:8003/api/v1/nearby-users",
params={
"latitude": latitude,
"longitude": longitude,
"radius_km": radius_km,
},
timeout=5.0,
)
if response.status_code == 200:
return response.json()
return []
except Exception:
return []
async def send_emergency_notifications(alert_id: int, nearby_users: List[dict]):
"""Send push notifications to nearby users"""
async with httpx.AsyncClient() as client:
try:
await client.post(
"http://localhost:8005/api/v1/send-emergency-notifications",
json={
"alert_id": alert_id,
"user_ids": [user["user_id"] for user in nearby_users],
},
timeout=10.0,
)
except Exception as e:
print(f"Failed to send notifications: {e}")
async def process_emergency_alert_task(alert_id: int, latitude: float, longitude: float):
"""Process emergency alert - notify nearby users"""
try:
# Get nearby users
nearby_users = await get_nearby_users(latitude, longitude)
if nearby_users:
# Update alert with notification count using dependency injection
async for db in get_db():
try:
await db.execute(
update(EmergencyAlert)
.where(EmergencyAlert.id == alert_id)
.values(notified_users_count=len(nearby_users))
)
await db.commit()
# Send notifications
await send_emergency_notifications(alert_id, nearby_users)
break
except Exception as e:
print(f"Error processing emergency alert: {e}")
await db.rollback()
except Exception as e:
print(f"Error in process_emergency_alert_task: {e}")
@app.post("/api/v1/alert", response_model=EmergencyAlertResponse)
async def create_emergency_alert(
alert_data: EmergencyAlertCreate,
background_tasks: BackgroundTasks,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""Create new emergency alert"""
# Create alert
db_alert = EmergencyAlert(
user_id=current_user.id,
latitude=alert_data.latitude,
longitude=alert_data.longitude,
address=alert_data.address,
alert_type=alert_data.alert_type,
message=alert_data.message,
)
db.add(db_alert)
await db.commit()
await db.refresh(db_alert)
# Process alert in background
background_tasks.add_task(
process_emergency_alert_task, db_alert.id, alert_data.latitude, alert_data.longitude
)
return EmergencyAlertResponse.model_validate(db_alert)
async def process_emergency_alert(alert_id: int, latitude: float, longitude: float):
"""Process emergency alert - get nearby users and send notifications"""
# Get nearby users
nearby_users = await get_nearby_users(
latitude, longitude, settings.MAX_EMERGENCY_RADIUS_KM
)
# Update alert with notified users count
async with AsyncSessionLocal() as db:
result = await db.execute(
select(EmergencyAlert).filter(EmergencyAlert.id == alert_id)
)
alert = result.scalars().first()
if alert:
alert.notified_users_count = len(nearby_users)
await db.commit()
# Send notifications
if nearby_users:
await send_emergency_notifications(alert_id, nearby_users)
@app.post("/api/v1/alert/{alert_id}/respond", response_model=EmergencyResponseResponse)
async def respond_to_alert(
alert_id: int,
response_data: EmergencyResponseCreate,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""Respond to emergency alert"""
# Check if alert exists
result = await db.execute(
select(EmergencyAlert).filter(EmergencyAlert.id == alert_id)
)
alert = result.scalars().first()
if not alert:
raise HTTPException(status_code=404, detail="Alert not found")
if alert.is_resolved:
raise HTTPException(status_code=400, detail="Alert already resolved")
# Check if user already responded
existing_response = await db.execute(
select(EmergencyResponse).filter(
EmergencyResponse.alert_id == alert_id,
EmergencyResponse.responder_id == current_user.id,
)
)
if existing_response.scalars().first():
raise HTTPException(
status_code=400, detail="You already responded to this alert"
)
# Create response
db_response = EmergencyResponse(
alert_id=alert_id,
responder_id=current_user.id,
response_type=response_data.response_type.value,
message=response_data.message,
eta_minutes=response_data.eta_minutes,
)
db.add(db_response)
# Update responded users count
alert.responded_users_count += 1
await db.commit()
await db.refresh(db_response)
return EmergencyResponseResponse.model_validate(db_response)
@app.put("/api/v1/alert/{alert_id}/resolve")
async def resolve_alert(
alert_id: int,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""Mark alert as resolved (only by alert creator)"""
result = await db.execute(
select(EmergencyAlert).filter(EmergencyAlert.id == alert_id)
)
alert = result.scalars().first()
if not alert:
raise HTTPException(status_code=404, detail="Alert not found")
if alert.user_id != current_user.id:
raise HTTPException(status_code=403, detail="Only alert creator can resolve it")
if alert.is_resolved:
raise HTTPException(status_code=400, detail="Alert already resolved")
alert.is_resolved = True
alert.resolved_at = datetime.utcnow()
alert.resolved_by = current_user.id
await db.commit()
return {"message": "Alert resolved successfully"}
@app.get("/api/v1/alerts/my", response_model=list[EmergencyAlertResponse])
async def get_my_alerts(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
limit: int = 50,
):
"""Get current user's emergency alerts"""
result = await db.execute(
select(EmergencyAlert)
.filter(EmergencyAlert.user_id == current_user.id)
.order_by(EmergencyAlert.created_at.desc())
.limit(limit)
)
alerts = result.scalars().all()
return [EmergencyAlertResponse.model_validate(alert) for alert in alerts]
@app.get("/api/v1/alerts/active", response_model=list[EmergencyAlertResponse])
async def get_active_alerts(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
limit: int = 20,
):
"""Get active alerts in user's area (last 2 hours)"""
# Get user's current location first
async with httpx.AsyncClient() as client:
try:
response = await client.get(
f"http://localhost:8003/api/v1/user-location/{current_user.id}",
timeout=5.0,
)
if response.status_code != 200:
raise HTTPException(
status_code=400, detail="User location not available"
)
location_data = response.json()
except Exception:
raise HTTPException(status_code=400, detail="Location service unavailable")
# Get alerts from last 2 hours
two_hours_ago = datetime.utcnow() - timedelta(hours=2)
result = await db.execute(
select(EmergencyAlert)
.filter(
EmergencyAlert.is_resolved == False,
EmergencyAlert.created_at >= two_hours_ago,
)
.order_by(EmergencyAlert.created_at.desc())
.limit(limit)
)
alerts = result.scalars().all()
return [EmergencyAlertResponse.model_validate(alert) for alert in alerts]
@app.get("/api/v1/stats", response_model=EmergencyStats)
async def get_emergency_stats(
current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)
):
"""Get emergency service statistics"""
# Get total alerts
total_result = await db.execute(select(func.count(EmergencyAlert.id)))
total_alerts = total_result.scalar()
# Get active alerts
active_result = await db.execute(
select(func.count(EmergencyAlert.id)).filter(
EmergencyAlert.is_resolved == False
)
)
active_alerts = active_result.scalar()
# Get resolved alerts
resolved_alerts = total_alerts - active_alerts
# Get total responders
responders_result = await db.execute(
select(func.count(func.distinct(EmergencyResponse.responder_id)))
)
total_responders = responders_result.scalar()
return EmergencyStats(
total_alerts=total_alerts,
active_alerts=active_alerts,
resolved_alerts=resolved_alerts,
avg_response_time_minutes=None, # TODO: Calculate this
total_responders=total_responders,
)
@app.get("/api/v1/emergency/reports", response_model=list[EmergencyAlertResponse])
async def get_emergency_reports(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db)
):
"""Get emergency reports/alerts for admin users or general statistics"""
# For now, return all active alerts (in production, add admin check)
result = await db.execute(
select(EmergencyAlert)
.filter(EmergencyAlert.is_resolved == False)
.order_by(EmergencyAlert.created_at.desc())
.limit(50)
)
alerts = result.scalars().all()
return [EmergencyAlertResponse.model_validate(alert) for alert in alerts]
@app.get("/api/v1/health")
async def health_check():
"""Health check endpoint"""
return {"status": "healthy", "service": "emergency-service"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8002)

View File

@@ -120,13 +120,20 @@ while true; do
# Check if services are still running # Check if services are still running
if ! curl -s http://localhost:8000/health > /dev/null 2>&1; then if ! curl -s http://localhost:8000/health > /dev/null 2>&1; then
echo "⚠️ API Gateway seems to be down, restarting..." echo "⚠️ API Gateway seems to be down, restarting..."
cd services/api_gateway && python -m uvicorn main:app --host 0.0.0.0 --port 8000 --reload & (cd services/api_gateway && python -m uvicorn main:app --host 0.0.0.0 --port 8000 --reload) &
cd ../..
fi fi
if ! curl -s http://localhost:8001/health > /dev/null 2>&1; then if ! curl -s http://localhost:8001/health > /dev/null 2>&1; then
echo "⚠️ User Service seems to be down, restarting..." echo "⚠️ User Service seems to be down, restarting..."
cd services/user_service && python -m uvicorn main:app --host 0.0.0.0 --port 8001 --reload & (cd services/user_service && python -m uvicorn main:app --host 0.0.0.0 --port 8001 --reload) &
cd ../..
fi fi
done done
curl -s -X POST "http://localhost:8000/api/v1/auth/register" \
-H "Content-Type: application/json" \
-d '{
"email": "test@example.com",
"password": "password123",
"first_name": "Test",
"last_name": "User"
}'