mirror of
https://gitlab.com/MoonTestUse1/AdministrationItDepartmens.git
synced 2025-08-14 00:25:46 +02:00
8
This commit is contained in:
56
backend/app/logging_config.py
Normal file
56
backend/app/logging_config.py
Normal file
@@ -0,0 +1,56 @@
|
||||
"""Logging configuration for the application"""
|
||||
|
||||
logging_config = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"default": {
|
||||
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
"datefmt": "%Y-%m-%d %H:%M:%S"
|
||||
},
|
||||
"access": {
|
||||
"format": "%(asctime)s - %(name)s - %(levelname)s - %(client_addr)s - %(request_line)s - %(status_code)s",
|
||||
"datefmt": "%Y-%m-%d %H:%M:%S"
|
||||
}
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"class": "logging.StreamHandler",
|
||||
"level": "INFO",
|
||||
"formatter": "default",
|
||||
"stream": "ext://sys.stdout"
|
||||
},
|
||||
"file": {
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"level": "INFO",
|
||||
"formatter": "default",
|
||||
"filename": "logs/app.log",
|
||||
"maxBytes": 10485760, # 10MB
|
||||
"backupCount": 5
|
||||
},
|
||||
"access_file": {
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"level": "INFO",
|
||||
"formatter": "access",
|
||||
"filename": "logs/access.log",
|
||||
"maxBytes": 10485760, # 10MB
|
||||
"backupCount": 5
|
||||
}
|
||||
},
|
||||
"loggers": {
|
||||
"": { # Root logger
|
||||
"handlers": ["console", "file"],
|
||||
"level": "INFO"
|
||||
},
|
||||
"app": { # Application logger
|
||||
"handlers": ["console", "file"],
|
||||
"level": "INFO",
|
||||
"propagate": False
|
||||
},
|
||||
"app.access": { # Access logger
|
||||
"handlers": ["access_file"],
|
||||
"level": "INFO",
|
||||
"propagate": False
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,181 +1,39 @@
|
||||
from fastapi import FastAPI, Depends, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from .models import employee as employee_models
|
||||
from .models import request as request_models
|
||||
from .schemas import tables
|
||||
from .crud import employees, requests, auth, statistics
|
||||
from .database import engine, get_db
|
||||
from .models.request import StatusUpdate
|
||||
from .bot.notifications import send_notification
|
||||
from .bot import start_bot
|
||||
import threading
|
||||
import asyncio
|
||||
from fastapi.openapi.docs import get_swagger_ui_html
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
import logging
|
||||
from logging.config import dictConfig
|
||||
from .logging_config import logging_config
|
||||
|
||||
# Configure logging
|
||||
dictConfig(logging_config)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
tables.Base.metadata.create_all(bind=engine)
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def run_bot():
|
||||
asyncio.run(start_bot())
|
||||
|
||||
|
||||
bot_thread = threading.Thread(target=run_bot, daemon=True)
|
||||
bot_thread.start()
|
||||
|
||||
# CORS middleware
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
app = FastAPI(
|
||||
title="Support Portal API",
|
||||
description="API for managing support requests and employees",
|
||||
version="1.0.0",
|
||||
docs_url=None,
|
||||
redoc_url=None
|
||||
)
|
||||
|
||||
# Auth endpoints
|
||||
@app.post("/api/test/create-user")
|
||||
def create_test_user(db: Session = Depends(get_db)):
|
||||
test_user = employee_models.EmployeeCreate(
|
||||
first_name="Test",
|
||||
last_name="User",
|
||||
department="general",
|
||||
office="101",
|
||||
password="test123"
|
||||
# Custom OpenAPI documentation
|
||||
@app.get("/api/docs", include_in_schema=False)
|
||||
async def custom_swagger_ui_html():
|
||||
return get_swagger_ui_html(
|
||||
openapi_url="/api/openapi.json",
|
||||
title="Support Portal API Documentation",
|
||||
swagger_favicon_url="/favicon.ico"
|
||||
)
|
||||
return employees.create_employee(db=db, employee=test_user)
|
||||
@app.post("/api/auth/login")
|
||||
def login(credentials: dict, db: Session = Depends(get_db)):
|
||||
print(f"Login attempt for: {credentials['lastName']}") # Добавьте для отладки
|
||||
employee = auth.authenticate_employee(db, credentials["lastName"], credentials["password"])
|
||||
if not employee:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Неверная фамилия или пароль"
|
||||
)
|
||||
return employee
|
||||
|
||||
@app.get("/api/openapi.json", include_in_schema=False)
|
||||
async def get_open_api_endpoint():
|
||||
return get_openapi(
|
||||
title="Support Portal API",
|
||||
version="1.0.0",
|
||||
description="API for managing support requests and employees",
|
||||
routes=app.routes
|
||||
)
|
||||
|
||||
@app.post("/api/auth/admin")
|
||||
def admin_login(credentials: dict, db: Session = Depends(get_db)):
|
||||
if not auth.authenticate_admin(
|
||||
db, credentials["username"], credentials["password"]
|
||||
):
|
||||
raise HTTPException(status_code=401, detail="Неверные учетные данные")
|
||||
return {"success": True}
|
||||
|
||||
|
||||
# Employee endpoints
|
||||
@app.post("/api/employees/", response_model=employee_models.Employee)
|
||||
def create_employee(
|
||||
employee: employee_models.EmployeeCreate, db: Session = Depends(get_db)
|
||||
):
|
||||
db_employee = employees.get_employee_by_lastname(db, employee.last_name)
|
||||
if db_employee:
|
||||
raise HTTPException(status_code=400, detail="Last name already registered")
|
||||
return employees.create_employee(db=db, employee=employee)
|
||||
|
||||
|
||||
@app.get("/api/employees/", response_model=List[employee_models.Employee])
|
||||
def read_employees(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
|
||||
return employees.get_employees(db, skip=skip, limit=limit)
|
||||
|
||||
|
||||
@app.patch("/api/employees/{employee_id}")
|
||||
def update_employee(employee_id: int, data: dict, db: Session = Depends(get_db)):
|
||||
return employees.update_employee(db, employee_id, data)
|
||||
|
||||
|
||||
# Request endpoints
|
||||
@app.post("/api/requests/")
|
||||
async def create_request(
|
||||
request: request_models.RequestCreate, db: Session = Depends(get_db)
|
||||
):
|
||||
# Create request in database
|
||||
new_request = requests.create_request(db=db, request=request)
|
||||
|
||||
# Get employee details for the notification
|
||||
employee = employees.get_employee(db, new_request.employee_id)
|
||||
|
||||
# Prepare notification data
|
||||
notification_data = {
|
||||
"id": new_request.id,
|
||||
"employee_last_name": employee.last_name,
|
||||
"employee_first_name": employee.first_name,
|
||||
"department": new_request.department,
|
||||
"office": employee.office,
|
||||
"request_type": new_request.request_type,
|
||||
"priority": new_request.priority,
|
||||
"description": new_request.description,
|
||||
"created_at": new_request.created_at.isoformat(),
|
||||
}
|
||||
|
||||
# Send notification to Telegram (non-blocking)
|
||||
try:
|
||||
await send_notification(notification_data)
|
||||
except Exception as e:
|
||||
print(f"Failed to send Telegram notification: {e}")
|
||||
|
||||
return new_request
|
||||
|
||||
|
||||
@app.patch("/api/requests/{request_id}/status")
|
||||
def update_request_status(
|
||||
request_id: int,
|
||||
status_update: request_models.StatusUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
try:
|
||||
request = requests.update_request_status(db, request_id, status_update.status)
|
||||
if request is None:
|
||||
raise HTTPException(status_code=404, detail="Request not found")
|
||||
return request
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
|
||||
@app.post("/api/requests/", response_model=request_models.Request)
|
||||
def create_request(request_data: dict, db: Session = Depends(get_db)):
|
||||
return requests.create_request(db=db, request_data=request_data)
|
||||
|
||||
|
||||
@app.get("/api/requests/", response_model=List[request_models.RequestWithEmployee])
|
||||
def read_requests(
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
last_name: str = None,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
if last_name:
|
||||
return requests.get_requests_by_employee_lastname(db, last_name)
|
||||
return requests.get_requests(db, skip=skip, limit=limit)
|
||||
|
||||
|
||||
@app.patch("/api/requests/{request_id}/status")
|
||||
def update_request_status(request_id: int, status: str, db: Session = Depends(get_db)):
|
||||
request = requests.update_request_status(db, request_id, status)
|
||||
if request is None:
|
||||
raise HTTPException(status_code=404, detail="Request not found")
|
||||
return request
|
||||
|
||||
|
||||
@app.patch("/api/requests/{request_id}/status")
|
||||
def update_request_status(
|
||||
request_id: int, status_update: StatusUpdate, db: Session = Depends(get_db)
|
||||
):
|
||||
try:
|
||||
request = requests.update_request_status(db, request_id, status_update.status)
|
||||
if request is None:
|
||||
raise HTTPException(status_code=404, detail="Request not found")
|
||||
return request
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@app.get("/api/statistics")
|
||||
def get_statistics(period: str = "week", db: Session = Depends(get_db)):
|
||||
return statistics.get_statistics(db, period)
|
||||
# Existing middleware and routes...
|
3
backend/app/middleware/__init__.py
Normal file
3
backend/app/middleware/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .logging import LoggingMiddleware
|
||||
|
||||
__all__ = ['LoggingMiddleware']
|
39
backend/app/middleware/logging.py
Normal file
39
backend/app/middleware/logging.py
Normal file
@@ -0,0 +1,39 @@
|
||||
"""Logging middleware for request/response tracking"""
|
||||
import time
|
||||
from fastapi import Request
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("app.access")
|
||||
|
||||
class LoggingMiddleware(BaseHTTPMiddleware):
|
||||
async def dispatch(self, request: Request, call_next):
|
||||
start_time = time.time()
|
||||
|
||||
# Log request
|
||||
logger.info(
|
||||
"Request started",
|
||||
extra={
|
||||
"client_addr": request.client.host,
|
||||
"request_line": f"{request.method} {request.url.path}",
|
||||
"status_code": "PENDING"
|
||||
}
|
||||
)
|
||||
|
||||
response = await call_next(request)
|
||||
|
||||
# Calculate processing time
|
||||
process_time = time.time() - start_time
|
||||
|
||||
# Log response
|
||||
logger.info(
|
||||
"Request completed",
|
||||
extra={
|
||||
"client_addr": request.client.host,
|
||||
"request_line": f"{request.method} {request.url.path}",
|
||||
"status_code": response.status_code,
|
||||
"process_time": f"{process_time:.2f}s"
|
||||
}
|
||||
)
|
||||
|
||||
return response
|
Reference in New Issue
Block a user