1
0
mirror of https://gitlab.com/MoonTestUse1/AdministrationItDepartmens.git synced 2025-08-14 00:25:46 +02:00

добавление редисаъ5

This commit is contained in:
MoonTestUse1
2025-01-03 16:56:54 +06:00
parent 9f5cb4d4c2
commit 25982e622c
3 changed files with 126 additions and 179 deletions

View File

@@ -1,10 +1,13 @@
"""Initial migration """initial migration
Revision ID: initial_migration Revision ID: initial_migration
Create Date: 2024-03-14 12:00:00.000000 Revises:
Create Date: 2024-01-03 11:00:00.000000
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'initial_migration' revision = 'initial_migration'
@@ -13,7 +16,14 @@ branch_labels = None
depends_on = None depends_on = None
def upgrade() -> None: def upgrade() -> None:
# Create employees table # Создаем enum типы
request_status = postgresql.ENUM('new', 'in_progress', 'completed', 'rejected', name='requeststatus')
request_status.create(op.get_bind())
request_priority = postgresql.ENUM('low', 'medium', 'high', name='requestpriority')
request_priority.create(op.get_bind())
# Создаем таблицу employees
op.create_table( op.create_table(
'employees', 'employees',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
@@ -21,29 +31,57 @@ def upgrade() -> None:
sa.Column('last_name', sa.String(), nullable=False), sa.Column('last_name', sa.String(), nullable=False),
sa.Column('department', sa.String(), nullable=False), sa.Column('department', sa.String(), nullable=False),
sa.Column('office', sa.String(), nullable=False), sa.Column('office', sa.String(), nullable=False),
sa.Column('password', sa.String(), nullable=False), sa.Column('hashed_password', sa.String(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()')),
sa.PrimaryKeyConstraint('id') sa.PrimaryKeyConstraint('id')
) )
op.create_index(op.f('ix_employees_id'), 'employees', ['id'], unique=False)
op.create_index(op.f('ix_employees_last_name'), 'employees', ['last_name'], unique=False)
# Create requests table # Создаем таблицу requests
op.create_table( op.create_table(
'requests', 'requests',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('title', sa.String(), nullable=False), sa.Column('title', sa.String(), nullable=False),
sa.Column('description', sa.String(), nullable=False), sa.Column('description', sa.String(), nullable=False),
sa.Column('status', sa.String(), nullable=False, server_default='new'), sa.Column('status', sa.Enum('new', 'in_progress', 'completed', 'rejected', name='requeststatus'), nullable=False),
sa.Column('priority', sa.String(), nullable=False), sa.Column('priority', sa.Enum('low', 'medium', 'high', name='requestpriority'), nullable=False),
sa.Column('employee_id', sa.Integer(), nullable=True), sa.Column('employee_id', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()')), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), onupdate=sa.text('now()')), sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(['employee_id'], ['employees.id'], ), sa.ForeignKeyConstraint(['employee_id'], ['employees.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id') sa.PrimaryKeyConstraint('id')
) )
# Создаем таблицу tokens
op.create_table(
'tokens',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('access_token', sa.String(), nullable=False),
sa.Column('employee_id', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('expires_at', sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(['employee_id'], ['employees.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
# Создаем индексы
op.create_index(op.f('ix_employees_id'), 'employees', ['id'], unique=False)
op.create_index(op.f('ix_employees_last_name'), 'employees', ['last_name'], unique=False)
op.create_index(op.f('ix_requests_id'), 'requests', ['id'], unique=False) op.create_index(op.f('ix_requests_id'), 'requests', ['id'], unique=False)
op.create_index(op.f('ix_tokens_access_token'), 'tokens', ['access_token'], unique=True)
op.create_index(op.f('ix_tokens_id'), 'tokens', ['id'], unique=False)
def downgrade() -> None: def downgrade() -> None:
# Удаляем индексы
op.drop_index(op.f('ix_tokens_id'), table_name='tokens')
op.drop_index(op.f('ix_tokens_access_token'), table_name='tokens')
op.drop_index(op.f('ix_requests_id'), table_name='requests')
op.drop_index(op.f('ix_employees_last_name'), table_name='employees')
op.drop_index(op.f('ix_employees_id'), table_name='employees')
# Удаляем таблицы
op.drop_table('tokens')
op.drop_table('requests') op.drop_table('requests')
op.drop_table('employees') op.drop_table('employees')
# Удаляем enum типы
op.execute('DROP TYPE requeststatus')
op.execute('DROP TYPE requestpriority')

View File

@@ -1,179 +1,78 @@
"""Requests router""" """Requests router"""
from fastapi import APIRouter, Depends, HTTPException from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from typing import List, Optional from typing import List
from ..database import get_db from ..database import get_db
from ..models.request import Request, RequestStatus, RequestPriority from ..crud import requests
from ..schemas.request import RequestCreate, RequestResponse, RequestUpdate, RequestStatistics from ..schemas.request import Request, RequestCreate, RequestUpdate, RequestStatistics
from ..utils.auth import get_current_admin, get_current_employee from ..utils.auth import get_current_employee, get_current_admin
from sqlalchemy import func from ..utils.telegram import notify_new_request
from ..models.employee import Employee
from ..utils.telegram import notify_new_request, notify_status_change
import logging
# Initialize logger
logger = logging.getLogger(__name__)
router = APIRouter() router = APIRouter()
def request_to_dict(request: Request) -> dict: @router.post("", response_model=Request)
"""Convert Request model to dictionary""" async def create_request(
return {
"id": request.id,
"title": request.title,
"description": request.description,
"priority": request.priority,
"status": request.status,
"employee_id": request.employee_id,
"created_at": request.created_at,
"updated_at": request.updated_at
}
@router.get("/", response_model=List[RequestResponse])
def get_requests(
db: Session = Depends(get_db),
_: dict = Depends(get_current_admin)
):
"""Get all requests"""
try:
requests = db.query(Request).all()
return [request_to_dict(request) for request in requests]
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/", response_model=RequestResponse)
def create_request(
request: RequestCreate, request: RequestCreate,
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_employee: dict = Depends(get_current_employee) current_employee: dict = Depends(get_current_employee)
): ):
"""Create new request""" """
try: Создание новой заявки
db_request = Request( """
title=request.title, db_request = requests.create_request(db=db, request=request, employee_id=current_employee.id)
description=request.description, await notify_new_request(db_request.id)
priority=request.priority, return db_request
status=RequestStatus.NEW,
employee_id=current_employee["id"]
)
db.add(db_request) @router.get("", response_model=List[Request])
db.commit()
db.refresh(db_request)
# Получаем информацию о сотруднике
employee = db.query(Employee).filter(Employee.id == current_employee["id"]).first()
# Преобразуем объект запроса в словарь для уведомления
request_dict = request_to_dict(db_request)
request_dict["employee_name"] = f"{employee.last_name} {employee.first_name}"
# Отправляем уведомление в Telegram
notify_new_request(request_dict)
return request_to_dict(db_request)
except Exception as e:
db.rollback()
logger.error(f"Error creating request: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))
@router.get("/my", response_model=List[RequestResponse])
def get_employee_requests( def get_employee_requests(
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_employee: dict = Depends(get_current_employee) current_employee: dict = Depends(get_current_employee)
): ):
"""Get employee's requests""" """
try: Получение списка заявок текущего сотрудника
requests = db.query(Request).filter( """
Request.employee_id == current_employee["id"] return requests.get_employee_requests(db, employee_id=current_employee.id, skip=skip, limit=limit)
).all()
# Преобразуем объекты в словари до закрытия сессии @router.get("/statistics", response_model=RequestStatistics)
return [request_to_dict(request) for request in requests]
except Exception as e:
logger.error(f"Error getting employee requests: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))
@router.patch("/{request_id}/status", response_model=RequestResponse)
def update_request_status(
request_id: int,
status_update: RequestUpdate,
db: Session = Depends(get_db),
_: dict = Depends(get_current_admin)
):
"""Update request status"""
try:
db_request = db.query(Request).filter(Request.id == request_id).first()
if not db_request:
raise HTTPException(status_code=404, detail="Заявка не найдена")
old_status = db_request.status
db_request.status = status_update.status
db.commit()
db.refresh(db_request)
# Отправляем уведомление об изменении статуса, если у сотрудника есть telegram_id
if db_request.employee and db_request.employee.telegram_id:
notify_status_change(
request_id=db_request.id,
new_status=status_update.status,
employee_telegram_id=db_request.employee.telegram_id
)
return request_to_dict(db_request)
except HTTPException:
raise
except Exception as e:
db.rollback()
raise HTTPException(status_code=500, detail=str(e))
@router.get("/admin", response_model=List[RequestResponse])
def get_all_requests(
status: Optional[str] = None,
db: Session = Depends(get_db),
_: dict = Depends(get_current_admin)
):
"""Get all requests with optional status filter"""
try:
query = db.query(Request)
if status:
query = query.filter(Request.status == status)
requests = query.all()
# Преобразуем объекты в словари до закрытия сессии
return [request_to_dict(request) for request in requests]
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/statistics")
def get_request_statistics( def get_request_statistics(
db: Session = Depends(get_db), db: Session = Depends(get_db),
_: dict = Depends(get_current_admin) _: dict = Depends(get_current_admin)
): ):
"""Get request statistics""" """
try: Получение статистики по заявкам (только для админа)
total_requests = db.query(Request).count() """
return requests.get_statistics(db)
# Статистика по статусам @router.put("/{request_id}", response_model=Request)
status_stats = db.query( def update_request(
Request.status, request_id: int,
func.count(Request.id) request_update: RequestUpdate,
).group_by(Request.status).all() db: Session = Depends(get_db),
_: dict = Depends(get_current_admin)
):
"""
Обновление статуса заявки (только для админа)
"""
db_request = requests.get_request(db, request_id=request_id)
if db_request is None:
raise HTTPException(status_code=404, detail="Request not found")
# Статистика по приоритетам return requests.update_request(db=db, request_id=request_id, request_update=request_update)
priority_stats = db.query(
Request.priority,
func.count(Request.id)
).group_by(Request.priority).all()
return { @router.delete("/{request_id}")
"total_requests": total_requests, def delete_request(
"by_status": { request_id: int,
status: count for status, count in status_stats db: Session = Depends(get_db),
}, _: dict = Depends(get_current_admin)
"by_priority": { ):
priority: count for priority, count in priority_stats """
} Удаление заявки (только для админа)
} """
except Exception as e: db_request = requests.get_request(db, request_id=request_id)
raise HTTPException(status_code=500, detail=str(e)) if db_request is None:
raise HTTPException(status_code=404, detail="Request not found")
requests.delete_request(db=db, request_id=request_id)
return {"message": "Request deleted successfully"}

View File

@@ -8,6 +8,7 @@ class RequestStatus(str, Enum):
NEW = "new" NEW = "new"
IN_PROGRESS = "in_progress" IN_PROGRESS = "in_progress"
COMPLETED = "completed" COMPLETED = "completed"
REJECTED = "rejected"
class RequestPriority(str, Enum): class RequestPriority(str, Enum):
LOW = "low" LOW = "low"
@@ -21,17 +22,26 @@ class RequestBase(BaseModel):
status: RequestStatus = RequestStatus.NEW status: RequestStatus = RequestStatus.NEW
class RequestCreate(RequestBase): class RequestCreate(RequestBase):
employee_id: int pass
class RequestUpdate(BaseModel):
status: RequestStatus
class Request(RequestBase):
model_config = ConfigDict(from_attributes=True) model_config = ConfigDict(from_attributes=True)
class Request(RequestBase):
id: int id: int
employee_id: int employee_id: int
created_at: datetime created_at: datetime
updated_at: Optional[datetime] = None updated_at: Optional[datetime] = None
class RequestUpdate(BaseModel):
model_config = ConfigDict(from_attributes=True) model_config = ConfigDict(from_attributes=True)
status: RequestStatus class RequestStatistics(BaseModel):
total: int
new: int
in_progress: int
completed: int
rejected: int
model_config = ConfigDict(from_attributes=True)