111 lines
4.6 KiB
Python
111 lines
4.6 KiB
Python
|
from sqlalchemy import Column, Integer, String, Text, DateTime, Float, Boolean, BigInteger
|
|||
|
from sqlalchemy.dialects.mysql import JSON
|
|||
|
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
|||
|
from sqlalchemy.orm import sessionmaker, declarative_base
|
|||
|
from sqlalchemy.sql import func
|
|||
|
from passlib.context import CryptContext
|
|||
|
from dotenv import load_dotenv
|
|||
|
from sqlalchemy.future import select
|
|||
|
import os
|
|||
|
|
|||
|
# Загружаем переменные окружения
|
|||
|
load_dotenv()
|
|||
|
|
|||
|
# Правильная строка подключения
|
|||
|
DATABASE_URL = os.getenv('DATABASE_URL') # Должно быть "mysql+aiomysql://..." или "postgresql+asyncpg://..."
|
|||
|
|
|||
|
# Создаём асинхронный движок
|
|||
|
async_engine = create_async_engine(DATABASE_URL, echo=True)
|
|||
|
|
|||
|
# Создаём фабрику сессий
|
|||
|
async_session = sessionmaker(async_engine, class_=AsyncSession, expire_on_commit=False)
|
|||
|
|
|||
|
# Базовый класс для моделей
|
|||
|
Base = declarative_base()
|
|||
|
|
|||
|
# Контекст хеширования паролей
|
|||
|
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
|||
|
|
|||
|
# Функция для инициализации базы данных
|
|||
|
async def init_db():
|
|||
|
async with async_engine.begin() as conn:
|
|||
|
await conn.run_sync(Base.metadata.create_all)
|
|||
|
async with async_session() as session:
|
|||
|
# Проверяем, есть ли уже данные в таблице пользователей
|
|||
|
result = await session.execute(select(User).limit(1))
|
|||
|
user_exists = result.scalars().first()
|
|||
|
|
|||
|
if not user_exists:
|
|||
|
new_user = User(
|
|||
|
username="admin",
|
|||
|
hashed_password=hash_password("admin123"), # Пароль хешируем
|
|||
|
role="admin",
|
|||
|
is_active=True
|
|||
|
)
|
|||
|
session.add(new_user)
|
|||
|
await session.commit()
|
|||
|
|
|||
|
# Зависимость FastAPI для работы с БД
|
|||
|
async def get_async_session() -> AsyncSession:
|
|||
|
async with async_session() as session:
|
|||
|
yield session
|
|||
|
|
|||
|
# Функции для хеширования паролей
|
|||
|
def hash_password(password: str) -> str:
|
|||
|
return pwd_context.hash(password)
|
|||
|
|
|||
|
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
|||
|
return pwd_context.verify(plain_password, hashed_password)
|
|||
|
|
|||
|
# async def get_db():
|
|||
|
# async with SessionLocal() as session:
|
|||
|
# yield session
|
|||
|
|
|||
|
|
|||
|
# Модель пользователя
|
|||
|
class User(Base):
|
|||
|
__tablename__ = "users"
|
|||
|
|
|||
|
id = Column(Integer, primary_key=True, index=True)
|
|||
|
username = Column(String(55), unique=True, index=True, nullable=False) # ✅ Правильно
|
|||
|
hashed_password = Column(String(255), nullable=False)
|
|||
|
role = Column(String(55), default="user")
|
|||
|
is_active = Column(Boolean, default=True)
|
|||
|
|
|||
|
# Модель профиля
|
|||
|
class Profile(Base):
|
|||
|
__tablename__ = "profile"
|
|||
|
|
|||
|
id = Column(Integer, primary_key=True, index=True)
|
|||
|
link = Column(String(255), unique=True, nullable=True)
|
|||
|
first_name = Column(String(255), nullable=False)
|
|||
|
last_name = Column(String(255), nullable=False)
|
|||
|
pronouns = Column(String(50), nullable=True)
|
|||
|
email = Column(String(255), nullable=True)
|
|||
|
telephone = Column(String(20), nullable=True)
|
|||
|
location = Column(String(255), nullable=True)
|
|||
|
statement = Column(Text, nullable=True)
|
|||
|
skills = Column(JSON, nullable=True) # JSON-поле для списка навыков
|
|||
|
websites = Column(JSON, nullable=True) # JSON-поле для списка сайтов
|
|||
|
languages = Column(JSON, nullable=True) # JSON-поле для языков
|
|||
|
date = Column(DateTime, server_default=func.now())
|
|||
|
|
|||
|
# Модель вакансий
|
|||
|
class Job(Base):
|
|||
|
__tablename__ = "jobs"
|
|||
|
|
|||
|
job_id = Column(BigInteger, primary_key=True, index=True)
|
|||
|
job_title = Column(String(255), nullable=False)
|
|||
|
job_company = Column(String(255), nullable=True)
|
|||
|
minimum_annual_salary = Column(Float, nullable=True)
|
|||
|
salary_currency = Column(String(10), nullable=True)
|
|||
|
location_type = Column(String(50), nullable=True) # Remote, On-site, Hybrid
|
|||
|
location = Column(String(255), nullable=True)
|
|||
|
job_level = Column(String(50), nullable=True) # Entry-level, Junior, Mid
|
|||
|
job_type = Column(String(50), nullable=True) # Full-time, Part-time
|
|||
|
days_posted = Column(Integer, nullable=True)
|
|||
|
hourly_rate = Column(Float, nullable=True)
|
|||
|
link = Column(String(2083), nullable=True) # URL вакансии
|
|||
|
link_company = Column(String(2083), nullable=True) # URL компании
|
|||
|
active = Column(Boolean, default=True) # Вакансия активна?
|