linkedin2/model/database.py

154 lines
6.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from sqlalchemy import Column, Integer, String, Text, DateTime, Float, Boolean, BigInteger, ForeignKey, DateTime
from sqlalchemy.dialects.mysql import JSON
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
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
from datetime import datetime
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)
applications = relationship("AppliedJob", back_populates="users")
# Модель профиля
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) # Вакансия активна?
# Связь с AppliedJobs
applications = relationship("AppliedJob", back_populates="job")
class Client(Base):
__tablename__ = "client"
id = Column(Integer, primary_key=True, index=True)
username = Column(String(55), unique=True, index=True, nullable=False) # ✅ Правильно
phone = Column(String(55), unique=True, index=True, nullable=True) # ✅ Правильно
email = Column(String(55), unique=True, index=True, nullable=True) # ✅ Правильно
link = Column(String(2083), nullable=True) # URL вакансии
is_active = Column(Boolean, default=True)
# Связь с AppliedJobs (заявки на вакансии)
applications = relationship("AppliedJob", back_populates="client")
class AppliedJob(Base):
__tablename__ = "applied_jobs"
id = Column(Integer, primary_key=True, index=True)
client_id = Column(Integer, ForeignKey("client.id"), nullable=False)
job_id = Column(BigInteger, ForeignKey("jobs.job_id"), nullable=False)
applied_on = Column(DateTime, nullable=True) # ✅ Теперь может быть NULL
status = Column(String(50), nullable=True) # ✅ Может быть NULL
assignee = Column(Integer, ForeignKey("users.id"), nullable=True) # ✅ Может быть NULL
priority = Column(String(50), nullable=True) # ✅ Может быть NULL
client = relationship("Client", back_populates="applications")
job = relationship("Job", back_populates="applications")
users = relationship("User", back_populates="applications")