초기 커밋
This commit is contained in:
0
app/api/v1/__init__.py
Normal file
0
app/api/v1/__init__.py
Normal file
0
app/api/v1/endpoints/__init__.py
Normal file
0
app/api/v1/endpoints/__init__.py
Normal file
73
app/api/v1/endpoints/analytics.py
Normal file
73
app/api/v1/endpoints/analytics.py
Normal file
@@ -0,0 +1,73 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
|
||||
from app.core.constants import Role
|
||||
from app.core.dependencies import require_role
|
||||
from app.schemas.analytics import (
|
||||
AnalyticsResultRead,
|
||||
ReportResponse,
|
||||
TelemetryAggregateResponse,
|
||||
)
|
||||
from app.services.analytics_service import AnalyticsService
|
||||
|
||||
router = APIRouter(prefix="/analytics", tags=["analytics"])
|
||||
|
||||
|
||||
@router.get("/telemetry/{device_id}", response_model=TelemetryAggregateResponse)
|
||||
async def get_telemetry_aggregate(
|
||||
device_id: str,
|
||||
start: datetime = Query(...),
|
||||
end: datetime = Query(...),
|
||||
interval: str = Query("1h"),
|
||||
_: dict = Depends(require_role(*Role.MANAGEMENT_ROLES)),
|
||||
) -> TelemetryAggregateResponse:
|
||||
service = AnalyticsService()
|
||||
return await service.get_telemetry_aggregate(device_id, start, end, interval)
|
||||
|
||||
|
||||
@router.post("/reports/{device_id}", response_model=ReportResponse)
|
||||
async def generate_report(
|
||||
device_id: str,
|
||||
start: datetime = Query(...),
|
||||
end: datetime = Query(...),
|
||||
_: dict = Depends(require_role(*Role.MANAGEMENT_ROLES)),
|
||||
) -> ReportResponse:
|
||||
service = AnalyticsService()
|
||||
return await service.generate_report(device_id, start, end)
|
||||
|
||||
|
||||
@router.get("/status/{device_id}")
|
||||
async def device_status_analysis(
|
||||
device_id: str,
|
||||
start: datetime = Query(...),
|
||||
end: datetime = Query(...),
|
||||
_: dict = Depends(require_role(*Role.MANAGEMENT_ROLES)),
|
||||
) -> dict:
|
||||
service = AnalyticsService()
|
||||
return await service.get_device_status_analysis(device_id, start, end)
|
||||
|
||||
|
||||
@router.get("/trends/{device_id}")
|
||||
async def trend_analysis(
|
||||
device_id: str,
|
||||
start: datetime = Query(...),
|
||||
end: datetime = Query(...),
|
||||
_: dict = Depends(require_role(*Role.MANAGEMENT_ROLES)),
|
||||
) -> dict:
|
||||
service = AnalyticsService()
|
||||
return await service.get_trend_analysis(device_id, start, end)
|
||||
|
||||
|
||||
@router.get("/results", response_model=list[AnalyticsResultRead])
|
||||
async def list_analytics_results(
|
||||
analysis_type: str = Query(...),
|
||||
device_id: str | None = Query(None),
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(20, ge=1, le=100),
|
||||
_: dict = Depends(require_role(*Role.MANAGEMENT_ROLES)),
|
||||
) -> list[AnalyticsResultRead]:
|
||||
service = AnalyticsService()
|
||||
return await service.list_results(analysis_type, device_id, skip, limit)
|
||||
53
app/api/v1/endpoints/auth.py
Normal file
53
app/api/v1/endpoints/auth.py
Normal file
@@ -0,0 +1,53 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.api.deps import get_session
|
||||
from app.core.dependencies import get_current_user_id
|
||||
from app.schemas.auth import (
|
||||
LoginRequest,
|
||||
RefreshTokenRequest,
|
||||
RegisterRequest,
|
||||
TokenResponse,
|
||||
)
|
||||
from app.services.auth_service import AuthService
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["auth"])
|
||||
|
||||
|
||||
@router.post("/register", response_model=TokenResponse, status_code=201)
|
||||
async def register(
|
||||
body: RegisterRequest,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> TokenResponse:
|
||||
service = AuthService(session)
|
||||
user = await service.register(body.email, body.password, body.full_name)
|
||||
return await service._create_tokens(user)
|
||||
|
||||
|
||||
@router.post("/login", response_model=TokenResponse)
|
||||
async def login(
|
||||
body: LoginRequest,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> TokenResponse:
|
||||
service = AuthService(session)
|
||||
return await service.login(body.email, body.password)
|
||||
|
||||
|
||||
@router.post("/refresh", response_model=TokenResponse)
|
||||
async def refresh_token(
|
||||
body: RefreshTokenRequest,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> TokenResponse:
|
||||
service = AuthService(session)
|
||||
return await service.refresh(body.refresh_token)
|
||||
|
||||
|
||||
@router.post("/logout", status_code=204)
|
||||
async def logout(
|
||||
user_id: int = Depends(get_current_user_id),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> None:
|
||||
service = AuthService(session)
|
||||
await service.logout(user_id)
|
||||
70
app/api/v1/endpoints/devices.py
Normal file
70
app/api/v1/endpoints/devices.py
Normal file
@@ -0,0 +1,70 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.api.deps import get_session
|
||||
from app.core.constants import Role
|
||||
from app.core.dependencies import get_current_user_payload, require_role
|
||||
from app.schemas.common import PaginatedResponse
|
||||
from app.schemas.device import DeviceCreate, DeviceRead, DeviceUpdate
|
||||
from app.services.device_service import DeviceService
|
||||
|
||||
router = APIRouter(prefix="/devices", tags=["devices"])
|
||||
|
||||
|
||||
@router.get("", response_model=PaginatedResponse[DeviceRead])
|
||||
async def list_devices(
|
||||
page: int = Query(1, ge=1),
|
||||
size: int = Query(20, ge=1, le=100),
|
||||
_: dict = Depends(get_current_user_payload),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> PaginatedResponse[DeviceRead]:
|
||||
service = DeviceService(session)
|
||||
skip = (page - 1) * size
|
||||
items = await service.list_devices(skip=skip, limit=size)
|
||||
total = await service.count_devices()
|
||||
return PaginatedResponse(
|
||||
items=items, total=total, page=page, size=size, pages=(total + size - 1) // size
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{device_id}", response_model=DeviceRead)
|
||||
async def get_device(
|
||||
device_id: int,
|
||||
_: dict = Depends(get_current_user_payload),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> DeviceRead:
|
||||
service = DeviceService(session)
|
||||
return await service.get_device(device_id)
|
||||
|
||||
|
||||
@router.post("", response_model=DeviceRead, status_code=201)
|
||||
async def create_device(
|
||||
body: DeviceCreate,
|
||||
_: dict = Depends(require_role(Role.SUPERADMIN, Role.ADMIN, Role.MANAGER)),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> DeviceRead:
|
||||
service = DeviceService(session)
|
||||
return await service.create_device(body)
|
||||
|
||||
|
||||
@router.patch("/{device_id}", response_model=DeviceRead)
|
||||
async def update_device(
|
||||
device_id: int,
|
||||
body: DeviceUpdate,
|
||||
_: dict = Depends(require_role(Role.SUPERADMIN, Role.ADMIN, Role.MANAGER)),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> DeviceRead:
|
||||
service = DeviceService(session)
|
||||
return await service.update_device(device_id, body)
|
||||
|
||||
|
||||
@router.delete("/{device_id}", status_code=204)
|
||||
async def delete_device(
|
||||
device_id: int,
|
||||
_: dict = Depends(require_role(Role.SUPERADMIN, Role.ADMIN)),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> None:
|
||||
service = DeviceService(session)
|
||||
await service.delete_device(device_id)
|
||||
61
app/api/v1/endpoints/monitoring.py
Normal file
61
app/api/v1/endpoints/monitoring.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.api.deps import get_session
|
||||
from app.core.constants import Role
|
||||
from app.core.dependencies import get_current_user_id, require_role
|
||||
from app.schemas.monitoring import AlertRead, AlertRuleCreate, AlertRuleRead, SystemHealthResponse
|
||||
from app.services.monitoring_service import MonitoringService
|
||||
|
||||
router = APIRouter(prefix="/monitoring", tags=["monitoring"])
|
||||
|
||||
|
||||
@router.get("/health", response_model=SystemHealthResponse)
|
||||
async def system_health(
|
||||
_: dict = Depends(require_role(*Role.MANAGEMENT_ROLES)),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> SystemHealthResponse:
|
||||
service = MonitoringService(session)
|
||||
return await service.get_system_health()
|
||||
|
||||
|
||||
@router.get("/alerts", response_model=list[AlertRead])
|
||||
async def list_alerts(
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(50, ge=1, le=200),
|
||||
_: dict = Depends(require_role(*Role.MANAGEMENT_ROLES)),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> list[AlertRead]:
|
||||
service = MonitoringService(session)
|
||||
return await service.list_active_alerts(skip=skip, limit=limit)
|
||||
|
||||
|
||||
@router.post("/alerts/{alert_id}/acknowledge", response_model=AlertRead)
|
||||
async def acknowledge_alert(
|
||||
alert_id: int,
|
||||
user_id: int = Depends(get_current_user_id),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> AlertRead:
|
||||
service = MonitoringService(session)
|
||||
return await service.acknowledge_alert(alert_id, user_id)
|
||||
|
||||
|
||||
@router.get("/alert-rules", response_model=list[AlertRuleRead])
|
||||
async def list_alert_rules(
|
||||
_: dict = Depends(require_role(*Role.MANAGEMENT_ROLES)),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> list[AlertRuleRead]:
|
||||
service = MonitoringService(session)
|
||||
return await service.list_alert_rules()
|
||||
|
||||
|
||||
@router.post("/alert-rules", response_model=AlertRuleRead, status_code=201)
|
||||
async def create_alert_rule(
|
||||
body: AlertRuleCreate,
|
||||
user_id: int = Depends(get_current_user_id),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> AlertRuleRead:
|
||||
service = MonitoringService(session)
|
||||
return await service.create_alert_rule(body, user_id)
|
||||
32
app/api/v1/endpoints/system.py
Normal file
32
app/api/v1/endpoints/system.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.api.deps import get_session
|
||||
from app.core.config import settings
|
||||
from app.core.constants import Role
|
||||
from app.core.dependencies import require_role
|
||||
|
||||
router = APIRouter(prefix="/system", tags=["system"])
|
||||
|
||||
|
||||
@router.get("/health")
|
||||
async def health_check() -> dict:
|
||||
return {
|
||||
"status": "ok",
|
||||
"service": settings.APP_NAME,
|
||||
"version": "0.1.0",
|
||||
}
|
||||
|
||||
|
||||
@router.get("/info")
|
||||
async def system_info(
|
||||
_: dict = Depends(require_role(Role.SUPERADMIN)),
|
||||
) -> dict:
|
||||
return {
|
||||
"app_name": settings.APP_NAME,
|
||||
"environment": settings.APP_ENV,
|
||||
"debug": settings.DEBUG,
|
||||
"api_prefix": settings.API_V1_PREFIX,
|
||||
}
|
||||
91
app/api/v1/endpoints/users.py
Normal file
91
app/api/v1/endpoints/users.py
Normal file
@@ -0,0 +1,91 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.api.deps import get_session
|
||||
from app.core.constants import Role
|
||||
from app.core.dependencies import get_current_user_id, require_role
|
||||
from app.schemas.common import PaginatedResponse
|
||||
from app.schemas.user import UserCreate, UserRead, UserUpdate
|
||||
from app.services.user_service import UserService
|
||||
|
||||
router = APIRouter(prefix="/users", tags=["users"])
|
||||
|
||||
|
||||
@router.get("/me", response_model=UserRead)
|
||||
async def get_me(
|
||||
user_id: int = Depends(get_current_user_id),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> UserRead:
|
||||
service = UserService(session)
|
||||
return await service.get_user(user_id)
|
||||
|
||||
|
||||
@router.patch("/me", response_model=UserRead)
|
||||
async def update_me(
|
||||
body: UserUpdate,
|
||||
user_id: int = Depends(get_current_user_id),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> UserRead:
|
||||
body.role = None
|
||||
body.is_active = None
|
||||
service = UserService(session)
|
||||
return await service.update_user(user_id, body)
|
||||
|
||||
|
||||
@router.get("", response_model=PaginatedResponse[UserRead])
|
||||
async def list_users(
|
||||
page: int = Query(1, ge=1),
|
||||
size: int = Query(20, ge=1, le=100),
|
||||
_: dict = Depends(require_role(Role.SUPERADMIN, Role.ADMIN)),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> PaginatedResponse[UserRead]:
|
||||
service = UserService(session)
|
||||
skip = (page - 1) * size
|
||||
items = await service.list_users(skip=skip, limit=size)
|
||||
total = await service.count_users()
|
||||
return PaginatedResponse(
|
||||
items=items, total=total, page=page, size=size, pages=(total + size - 1) // size
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{user_id}", response_model=UserRead)
|
||||
async def get_user(
|
||||
user_id: int,
|
||||
_: dict = Depends(require_role(Role.SUPERADMIN, Role.ADMIN)),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> UserRead:
|
||||
service = UserService(session)
|
||||
return await service.get_user(user_id)
|
||||
|
||||
|
||||
@router.post("", response_model=UserRead, status_code=201)
|
||||
async def create_user(
|
||||
body: UserCreate,
|
||||
_: dict = Depends(require_role(Role.SUPERADMIN, Role.ADMIN)),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> UserRead:
|
||||
service = UserService(session)
|
||||
return await service.create_user(body)
|
||||
|
||||
|
||||
@router.patch("/{user_id}", response_model=UserRead)
|
||||
async def update_user(
|
||||
user_id: int,
|
||||
body: UserUpdate,
|
||||
_: dict = Depends(require_role(Role.SUPERADMIN, Role.ADMIN)),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> UserRead:
|
||||
service = UserService(session)
|
||||
return await service.update_user(user_id, body)
|
||||
|
||||
|
||||
@router.delete("/{user_id}", status_code=204)
|
||||
async def delete_user(
|
||||
user_id: int,
|
||||
_: dict = Depends(require_role(Role.SUPERADMIN, Role.ADMIN)),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> None:
|
||||
service = UserService(session)
|
||||
await service.delete_user(user_id)
|
||||
13
app/api/v1/router.py
Normal file
13
app/api/v1/router.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.api.v1.endpoints import analytics, auth, devices, monitoring, system, users
|
||||
|
||||
v1_router = APIRouter()
|
||||
v1_router.include_router(system.router)
|
||||
v1_router.include_router(auth.router)
|
||||
v1_router.include_router(users.router)
|
||||
v1_router.include_router(devices.router)
|
||||
v1_router.include_router(monitoring.router)
|
||||
v1_router.include_router(analytics.router)
|
||||
Reference in New Issue
Block a user