pipeline issues fix
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2025-09-25 11:59:54 +09:00
parent dc50a9858e
commit 4e3768a6ee
39 changed files with 1297 additions and 739 deletions

View File

@@ -5,11 +5,13 @@ This module provides common authentication functionality to avoid circular impor
from datetime import datetime, timedelta
from typing import Optional
import jwt
from jwt.exceptions import InvalidTokenError
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from jwt.exceptions import InvalidTokenError
from passlib.context import CryptContext
from shared.config import settings
# Password hashing
@@ -37,14 +39,18 @@ def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
encoded_jwt = jwt.encode(
to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM
)
return encoded_jwt
def verify_token(token: str) -> Optional[dict]:
"""Verify and decode JWT token."""
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
payload = jwt.decode(
token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]
)
user_id: str = payload.get("sub")
if user_id is None:
return None
@@ -53,16 +59,18 @@ def verify_token(token: str) -> Optional[dict]:
return None
async def get_current_user_from_token(credentials: HTTPAuthorizationCredentials = Depends(security)) -> dict:
async def get_current_user_from_token(
credentials: HTTPAuthorizationCredentials = Depends(security),
) -> dict:
"""Get current user from JWT token."""
token = credentials.credentials
user_data = verify_token(token)
if user_data is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
return user_data
return user_data

View File

@@ -1,4 +1,5 @@
import redis.asyncio as redis
from shared.config import settings
# Redis connection
@@ -10,33 +11,35 @@ class CacheService:
async def set(key: str, value: str, expire: int = 3600):
"""Set cache with expiration"""
await redis_client.set(key, value, ex=expire)
@staticmethod
async def get(key: str) -> str:
"""Get cache value"""
return await redis_client.get(key)
@staticmethod
async def delete(key: str):
"""Delete cache key"""
await redis_client.delete(key)
@staticmethod
async def exists(key: str) -> bool:
"""Check if key exists"""
return await redis_client.exists(key)
@staticmethod
async def set_location(user_id: int, latitude: float, longitude: float, expire: int = 300):
async def set_location(
user_id: int, latitude: float, longitude: float, expire: int = 300
):
"""Cache user location with expiration (5 minutes default)"""
location_data = f"{latitude},{longitude}"
await redis_client.set(f"location:{user_id}", location_data, ex=expire)
@staticmethod
async def get_location(user_id: int) -> tuple[float, float] | None:
"""Get cached user location"""
location_data = await redis_client.get(f"location:{user_id}")
if location_data:
lat, lng = location_data.decode().split(',')
lat, lng = location_data.decode().split(",")
return float(lat), float(lng)
return None
return None

View File

@@ -1,9 +1,9 @@
import os
from pydantic_settings import BaseSettings
from typing import Optional
# Load .env file manually from project root
from dotenv import load_dotenv
from pydantic_settings import BaseSettings
# Find and load .env file
current_dir = os.path.dirname(os.path.abspath(__file__))
@@ -19,35 +19,37 @@ else:
class Settings(BaseSettings):
# Database
DATABASE_URL: str = "postgresql+asyncpg://admin:password@localhost:5432/women_safety"
DATABASE_URL: str = (
"postgresql+asyncpg://admin:password@localhost:5432/women_safety"
)
# Redis
REDIS_URL: str = "redis://localhost:6379/0"
# Kafka
KAFKA_BOOTSTRAP_SERVERS: str = "localhost:9092"
# JWT
SECRET_KEY: str = "your-secret-key-change-in-production"
ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
# App
APP_NAME: str = "Women Safety App"
DEBUG: bool = True
API_V1_STR: str = "/api/v1"
# External Services
FCM_SERVER_KEY: Optional[str] = None
# Security
CORS_ORIGINS: list = ["*"] # Change in production
# Location
MAX_EMERGENCY_RADIUS_KM: float = 1.0
class Config:
env_file = ".env"
settings = Settings()
settings = Settings()

View File

@@ -1,7 +1,8 @@
from sqlalchemy import Boolean, Column, DateTime, Integer
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy import Column, Integer, DateTime, Boolean
from sqlalchemy.orm import declarative_base, sessionmaker
from sqlalchemy.sql import func
from shared.config import settings
# Database setup
@@ -25,8 +26,9 @@ Base = declarative_base()
class BaseModel(Base):
"""Base model with common fields"""
__abstract__ = True
id = Column(Integer, primary_key=True, index=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
@@ -49,9 +51,9 @@ async def init_db():
"""Initialize database"""
async with engine.begin() as conn:
# Import all models here to ensure they are registered
from services.user_service.models import User
from services.calendar_service.models import CalendarEntry
from services.emergency_service.models import EmergencyAlert
from services.location_service.models import UserLocation
from services.calendar_service.models import CalendarEntry
await conn.run_sync(Base.metadata.create_all)
from services.user_service.models import User
await conn.run_sync(Base.metadata.create_all)