json
This commit is contained in:
parent
ab4454320a
commit
a3723bcdd6
18519
logs/app.log
18519
logs/app.log
File diff suppressed because it is too large
Load Diff
13
main.py
13
main.py
|
@ -3,7 +3,8 @@ from fastapi.responses import RedirectResponse
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from model.database import init_db
|
from model.database import init_db
|
||||||
from routers import index, logins, users, product, profile, jobs, client
|
from routers import index, logins, users, product, profile, jobs, client, auth1
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -23,6 +24,14 @@ app = FastAPI(title="API для turboapply",
|
||||||
# on_startup=[start_workers]
|
# on_startup=[start_workers]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=["*"], # Разрешить запросы отовсюду (для тестов)
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
# Настройка шаблонов
|
# Настройка шаблонов
|
||||||
templates = Jinja2Templates(directory="templates")
|
templates = Jinja2Templates(directory="templates")
|
||||||
|
|
||||||
|
@ -35,6 +44,8 @@ app.include_router(logins.router, tags=["login"], include_in_schema=False)
|
||||||
app.include_router(users.router, tags=["users"], include_in_schema=False)
|
app.include_router(users.router, tags=["users"], include_in_schema=False)
|
||||||
app.include_router(product.router, tags=["product"], include_in_schema=False)
|
app.include_router(product.router, tags=["product"], include_in_schema=False)
|
||||||
app.include_router(client.router, tags=["client"])
|
app.include_router(client.router, tags=["client"])
|
||||||
|
app.include_router(auth1.router, tags=["auth1"], include_in_schema=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Подключение роутеров
|
# Подключение роутеров
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from sqlalchemy import Column, Integer, String, Text, DateTime, Float, Boolean, BigInteger, ForeignKey, DateTime
|
from sqlalchemy import Column, Integer, String, Text, DateTime, Float, Boolean, BigInteger, ForeignKey, DateTime
|
||||||
from sqlalchemy.dialects.mysql import JSON
|
from sqlalchemy.dialects.mysql import JSON
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||||
|
from typing import AsyncGenerator
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from sqlalchemy.sql import func
|
from sqlalchemy.sql import func
|
||||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||||
|
@ -50,9 +51,14 @@ async def init_db():
|
||||||
await session.commit()
|
await session.commit()
|
||||||
|
|
||||||
# Зависимость FastAPI для работы с БД
|
# Зависимость FastAPI для работы с БД
|
||||||
async def get_async_session() -> AsyncSession:
|
# async def get_async_session() -> AsyncSession:
|
||||||
|
# async with async_session() as session:
|
||||||
|
# yield session
|
||||||
|
|
||||||
|
async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
|
||||||
async with async_session() as session:
|
async with async_session() as session:
|
||||||
yield session
|
yield session # Сессия остается открытой во время запроса
|
||||||
|
|
||||||
|
|
||||||
# Функции для хеширования паролей
|
# Функции для хеширования паролей
|
||||||
def hash_password(password: str) -> str:
|
def hash_password(password: str) -> str:
|
||||||
|
@ -115,6 +121,7 @@ class Job(Base):
|
||||||
link = Column(String(2083), nullable=True) # URL вакансии
|
link = Column(String(2083), nullable=True) # URL вакансии
|
||||||
link_company = Column(String(2083), nullable=True) # URL компании
|
link_company = Column(String(2083), nullable=True) # URL компании
|
||||||
active = Column(Boolean, default=True) # Вакансия активна?
|
active = Column(Boolean, default=True) # Вакансия активна?
|
||||||
|
text = Column(Text, nullable=True)
|
||||||
|
|
||||||
|
|
||||||
# Связь с AppliedJobs
|
# Связь с AppliedJobs
|
||||||
|
@ -129,6 +136,9 @@ class Client(Base):
|
||||||
user_login = Column(String(55), unique=True, index=True, nullable=False) # ✅ Правильно
|
user_login = Column(String(55), unique=True, index=True, nullable=False) # ✅ Правильно
|
||||||
user_nicename = Column(String(55), unique=True, index=True, nullable=True) # ✅ Правильно
|
user_nicename = Column(String(55), unique=True, index=True, nullable=True) # ✅ Правильно
|
||||||
user_email = Column(String(55), unique=True, index=True, nullable=True) # ✅ Правильно
|
user_email = Column(String(55), unique=True, index=True, nullable=True) # ✅ Правильно
|
||||||
|
phone = Column(String(55), unique=True, index=True, nullable=True) # ✅ Правильно
|
||||||
|
|
||||||
|
json_data = Column(Text, nullable=True)
|
||||||
# user_registered = Column(String(2083), nullable=True) # URL вакансии
|
# user_registered = Column(String(2083), nullable=True) # URL вакансии
|
||||||
user_status = Column(Boolean, default=True)
|
user_status = Column(Boolean, default=True)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
from fastapi import FastAPI, Depends, HTTPException, status, Form, Response, Request, APIRouter
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from sqlalchemy.future import select
|
||||||
|
from passlib.context import CryptContext
|
||||||
|
import jwt
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from model.database import get_async_session, User
|
||||||
|
|
||||||
|
SECRET_KEY = "your_secret_key"
|
||||||
|
REFRESH_SECRET_KEY = "your_refresh_secret_key"
|
||||||
|
ALGORITHM = "HS256"
|
||||||
|
ACCESS_TOKEN_EXPIRE_MINUTES = 1
|
||||||
|
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||||
|
|
||||||
|
def create_access_token(data: dict, expires_delta: timedelta | None = None):
|
||||||
|
to_encode = data.copy()
|
||||||
|
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
|
||||||
|
to_encode.update({"exp": expire})
|
||||||
|
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||||
|
|
||||||
|
async def authenticate_user(db: AsyncSession, username: str, password: str):
|
||||||
|
result = await db.execute(select(User).where(User.username == username))
|
||||||
|
user = result.scalars().first()
|
||||||
|
return user if user and pwd_context.verify(password, user.hashed_password) else None
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/auth", tags=["auth"])
|
||||||
|
|
||||||
|
@router.post("/logins")
|
||||||
|
async def logins(username: str = Form(...), password: str = Form(...), db: AsyncSession = Depends(get_async_session)):
|
||||||
|
user = await authenticate_user(db, username, password)
|
||||||
|
if not user:
|
||||||
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Неправильный логин или пароль")
|
||||||
|
|
||||||
|
access_token = create_access_token({"sub": user.username, "role": user.role})
|
||||||
|
refresh_token = create_access_token({"sub": user.username}, expires_delta=timedelta(days=7))
|
||||||
|
|
||||||
|
response = Response()
|
||||||
|
response.set_cookie(key="access_token", value=access_token, httponly=True)
|
||||||
|
response.set_cookie(key="refresh_token", value=refresh_token, httponly=True)
|
||||||
|
|
||||||
|
return {"message": "Успешный вход"}
|
||||||
|
|
||||||
|
@router.post("/logout")
|
||||||
|
async def logout(response: Response):
|
||||||
|
response.delete_cookie("access_token")
|
||||||
|
response.delete_cookie("refresh_token")
|
||||||
|
return {"message": "Вы вышли"}
|
||||||
|
|
||||||
|
@router.post("/refresh")
|
||||||
|
async def refresh_token(request: Request, response: Response):
|
||||||
|
refresh_token = request.cookies.get("refresh_token")
|
||||||
|
if not refresh_token:
|
||||||
|
raise HTTPException(status_code=401, detail="❌ Refresh token отсутствует")
|
||||||
|
|
||||||
|
try:
|
||||||
|
payload = jwt.decode(refresh_token, REFRESH_SECRET_KEY, algorithms=[ALGORITHM])
|
||||||
|
username = payload.get("sub")
|
||||||
|
if not username:
|
||||||
|
raise HTTPException(status_code=401, detail="❌ Ошибка токена")
|
||||||
|
except jwt.ExpiredSignatureError:
|
||||||
|
raise HTTPException(status_code=401, detail="❌ Refresh token истёк")
|
||||||
|
except jwt.InvalidTokenError:
|
||||||
|
raise HTTPException(status_code=401, detail="❌ Ошибка refresh токена")
|
||||||
|
|
||||||
|
new_access_token = create_access_token({"sub": username})
|
||||||
|
response.set_cookie(key="access_token", value=new_access_token, httponly=True)
|
||||||
|
|
||||||
|
return {"access_token": new_access_token}
|
|
@ -1,9 +1,13 @@
|
||||||
from fastapi import FastAPI, HTTPException, APIRouter, Request, Header
|
from fastapi import FastAPI, HTTPException, APIRouter, Request, Header, Depends
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
import json
|
import json
|
||||||
|
from model.database import get_async_session, Client
|
||||||
|
from utils.clients import upsert_client
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
templates = Jinja2Templates(directory="templates")
|
templates = Jinja2Templates(directory="templates")
|
||||||
|
@ -11,7 +15,7 @@ API_KEY = "4545454"
|
||||||
|
|
||||||
# Пример данных
|
# Пример данных
|
||||||
clients = {
|
clients = {
|
||||||
27: {"username": "John Doe", "email": "john@example.com", "phone": "+123456781"},
|
1: {"username": "John Doe", "email": "john@example.com", "phone": "+123456781"},
|
||||||
44: {"username": "Jane Smith", "email": "jane@example.com", "phone": "+987654321"}
|
44: {"username": "Jane Smith", "email": "jane@example.com", "phone": "+987654321"}
|
||||||
}
|
}
|
||||||
@router.get("/get_client/{client_id}", include_in_schema=False)
|
@router.get("/get_client/{client_id}", include_in_schema=False)
|
||||||
|
@ -22,17 +26,36 @@ async def get_client_modal(client_id: int):
|
||||||
return JSONResponse(content=client)
|
return JSONResponse(content=client)
|
||||||
|
|
||||||
class JsonData(BaseModel):
|
class JsonData(BaseModel):
|
||||||
json_data: str
|
json_data: Union[dict, str]
|
||||||
|
|
||||||
|
|
||||||
@router.post("/client/")
|
@router.post("/client/")
|
||||||
async def client(data: JsonData, x_api_key: str = Header(None)):
|
async def client(data: JsonData, x_api_key: str = Header(...), db: Session = Depends(get_async_session)):
|
||||||
# Проверяем API-ключ
|
|
||||||
if x_api_key != "4545454":
|
if x_api_key != "4545454":
|
||||||
raise HTTPException(status_code=403, detail="Invalid API Key")
|
raise HTTPException(status_code=403, detail="Invalid API Key")
|
||||||
|
|
||||||
|
# Если json_data строка — декодируем
|
||||||
|
if isinstance(data.json_data, str):
|
||||||
|
try:
|
||||||
|
data.json_data = json.loads(data.json_data)
|
||||||
|
|
||||||
|
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
raise HTTPException(status_code=400, detail="Invalid JSON format")
|
||||||
|
|
||||||
|
print("Полученные данные:", data.json_data)
|
||||||
|
return {"message": "JSON получен", "data": "ok"}
|
||||||
|
|
||||||
try:
|
|
||||||
parsed_data = json.loads(data.json_data) # Декодируем JSON
|
|
||||||
print("Полученные данные:", parsed_data)
|
|
||||||
return {"message": "JSON получен", "data": parsed_data}
|
# first_name = parsed_data['first_name']
|
||||||
except json.JSONDecodeError as e:
|
# last_name = parsed_data['last_name']
|
||||||
raise HTTPException(status_code=400, detail=f"Invalid JSON: {str(e)}")
|
# email_addr = parsed_data['email_addr']
|
||||||
|
# user_id = parsed_data['user_id']
|
||||||
|
# phone_num = parsed_data['phone_num']
|
||||||
|
|
||||||
|
# print(first_name)
|
||||||
|
# # data = await upsert_client(db, first_name, last_name, email_addr, parsed_data)
|
||||||
|
# client = await upsert_client(db, user_id, first_name, last_name, email_addr, phone_num, str(parsed_data))
|
||||||
|
# print(f"Received data: data={client}")
|
|
@ -52,7 +52,7 @@ async def login(
|
||||||
return Response(content="Неправильный логин или пароль", media_type="text/html")
|
return Response(content="Неправильный логин или пароль", media_type="text/html")
|
||||||
|
|
||||||
access_token = create_access_token(data={"sub": username, "role": user.role})
|
access_token = create_access_token(data={"sub": username, "role": user.role})
|
||||||
response = RedirectResponse(url="/", status_code=303)
|
response = RedirectResponse(url="/product", status_code=303)
|
||||||
response.set_cookie(key="access_token", value=access_token, httponly=True)
|
response.set_cookie(key="access_token", value=access_token, httponly=True)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
4780
search_jobes2.json
4780
search_jobes2.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -28,12 +28,7 @@
|
||||||
</a>
|
</a>
|
||||||
<div class="side-nav__devider my-6"></div>
|
<div class="side-nav__devider my-6"></div>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
|
||||||
<a href="/" class="side-menu {% if current_path == '/' %}side-menu--active{% endif %}">
|
|
||||||
<div class="side-menu__icon"> <i data-feather="home"></i> </div>
|
|
||||||
<div class="side-menu__title"> Dashboard </div>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<a href="/product" class="side-menu {% if current_path.startswith('/product') %}side-menu--active{% endif %}">
|
<a href="/product" class="side-menu {% if current_path.startswith('/product') %}side-menu--active{% endif %}">
|
||||||
<div class="side-menu__icon"> <i data-feather="credit-card"></i> </div>
|
<div class="side-menu__icon"> <i data-feather="credit-card"></i> </div>
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<h2 class="text-lg font-medium mr-auto">Add Users</h2>
|
<h2 class="text-lg font-medium mr-auto">Add Users</h2>
|
||||||
|
|
||||||
<form action="/users/create" method="post">
|
<form action="/users/create" method="post">
|
||||||
<div class="mt-3"> <label>Email</label> <input type="text" class="input w-full border mt-2" name="username" placeholder="username"> </div>
|
<div class="mt-3"> <label>Username</label> <input type="text" class="input w-full border mt-2" name="username" placeholder="username"> </div>
|
||||||
<div class="mt-3"> <label>Password</label> <input type="password" name="password"class="input w-full border mt-2" placeholder="secret"> </div>
|
<div class="mt-3"> <label>Password</label> <input type="password" name="password"class="input w-full border mt-2" placeholder="secret"> </div>
|
||||||
|
|
||||||
<label>Role:</label>
|
<label>Role:</label>
|
||||||
|
|
179
utils/app.py
179
utils/app.py
|
@ -47,10 +47,15 @@ def pars_jobs(geo):
|
||||||
}
|
}
|
||||||
for item in search_jobs
|
for item in search_jobs
|
||||||
]
|
]
|
||||||
# print(search_job)
|
|
||||||
file_path = "search_jobes2.json"
|
|
||||||
|
# file_path = "search_jobes2.json"
|
||||||
|
# with open(file_path, "w", encoding="utf-8") as json_file:
|
||||||
|
# json.dump(search_jobes, json_file, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
file_path = "search_jobes3.json"
|
||||||
with open(file_path, "w", encoding="utf-8") as json_file:
|
with open(file_path, "w", encoding="utf-8") as json_file:
|
||||||
json.dump(search_jobes, json_file, indent=4, ensure_ascii=False)
|
json.dump(search_jobs, json_file, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
print(f"Результаты успешно сохранены в {file_path}")
|
print(f"Результаты успешно сохранены в {file_path}")
|
||||||
|
|
||||||
|
@ -59,31 +64,90 @@ def add_to_bd():
|
||||||
#[ ]: Написать функцию записи в БД
|
#[ ]: Написать функцию записи в БД
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_job(job_id):
|
async def get_job(db: AsyncSession, job_id: str):
|
||||||
jobs = api.get_job(job_id)
|
try:
|
||||||
text = jobs['description']['text']
|
jobs = api.get_job(job_id)
|
||||||
location = jobs['formattedLocation']
|
|
||||||
title = jobs['title']
|
# Проверка наличия всех необходимых данных в ответе
|
||||||
listedAt = jobs['listedAt']
|
required_keys = ["description", "formattedLocation", "title", "listedAt", "companyDetails"]
|
||||||
|
for key in required_keys:
|
||||||
|
if key not in jobs:
|
||||||
|
logging.error(f"❌ Ошибка: Ключ {key} отсутствует в API-ответе")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Извлечение данных
|
||||||
|
text = jobs['description']['text']
|
||||||
|
location = jobs['formattedLocation']
|
||||||
|
title = jobs['title']
|
||||||
|
listed_at = jobs['listedAt']
|
||||||
|
|
||||||
|
company_info = jobs.get("companyDetails", {}).get("com.linkedin.voyager.deco.jobs.web.shared.WebCompactJobPostingCompany", {}).get("companyResolutionResult", {})
|
||||||
|
company_name = company_info.get("name", "Unknown")
|
||||||
|
company_url = company_info.get("url", "")
|
||||||
|
|
||||||
|
link = f'https://www.linkedin.com/jobs/view/{job_id}/'
|
||||||
|
|
||||||
|
|
||||||
|
workplace_types = jobs.get("workplaceTypesResolutionResults", {})
|
||||||
|
|
||||||
# Преобразование из миллисекунд в секунды и конвертация
|
if workplace_types:
|
||||||
future_date = datetime.fromtimestamp(listedAt / 1000)
|
first_key = next(iter(workplace_types)) # Берём первый (и единственный) ключ
|
||||||
# Текущая дата
|
workplace_data = workplace_types[first_key]
|
||||||
current_date = datetime.now()
|
|
||||||
# Разница в днях
|
localized_name = workplace_data.get("localizedName", "Unknown")
|
||||||
difference = abs((future_date - current_date).days)
|
entity_urn = workplace_data.get("entityUrn", "")
|
||||||
jobPostingId = jobs['jobPostingId']
|
|
||||||
localizedName = jobs['workplaceTypesResolutionResults']
|
|
||||||
# Извлекаем все localizedName
|
|
||||||
localized_names = [value['localizedName'] for value in localizedName.values()]
|
|
||||||
localized_name = ", ".join(localized_names)
|
|
||||||
# localized_name = workplaceTypesResolutionResults['urn:li:fs_workplaceType:2']['localizedName']
|
|
||||||
link = f'https://www.linkedin.com/jobs/view/{job_id}/'
|
|
||||||
names = jobs['companyDetails']['com.linkedin.voyager.deco.jobs.web.shared.WebCompactJobPostingCompany']['companyResolutionResult']['name']
|
|
||||||
url = jobs['companyDetails']['com.linkedin.voyager.deco.jobs.web.shared.WebCompactJobPostingCompany']['companyResolutionResult']['url']
|
|
||||||
|
|
||||||
|
logging.info(f"🏢 Тип работы: {localized_name} ({entity_urn})")
|
||||||
|
else:
|
||||||
|
localized_name = "Unknown"
|
||||||
|
entity_urn = ""
|
||||||
|
|
||||||
|
# Теперь можно добавить эти значения в БД
|
||||||
|
# job.location_type = localized_name
|
||||||
|
# job.entity_urn = entity_urn
|
||||||
|
|
||||||
|
# Проверка, есть ли вакансия в базе
|
||||||
|
query = select(Job).filter(Job.job_id == job_id)
|
||||||
|
result = await db.execute(query)
|
||||||
|
job = result.scalars().first()
|
||||||
|
|
||||||
|
if job:
|
||||||
|
logging.info(f"🔄 Обновление вакансии {job_id} в базе...")
|
||||||
|
job.text = json.dumps(jobs)
|
||||||
|
job.link = link
|
||||||
|
job.location = location
|
||||||
|
job.job_company = company_name
|
||||||
|
job.link_company = company_url
|
||||||
|
job.location_type = localized_name
|
||||||
|
else:
|
||||||
|
logging.info(f"🆕 Добавление вакансии {job_id} в базу...")
|
||||||
|
job = Job(
|
||||||
|
job_id=job_id,
|
||||||
|
text=json.dumps(jobs),
|
||||||
|
link=link,
|
||||||
|
location=location,
|
||||||
|
job_company=company_name,
|
||||||
|
link_company=company_url
|
||||||
|
)
|
||||||
|
db.add(job)
|
||||||
|
|
||||||
|
# Коммит и обновление внутри активной сессии
|
||||||
|
await db.commit()
|
||||||
|
await db.refresh(job)
|
||||||
|
logging.info(f"✅ Вакансия {job_id} успешно сохранена")
|
||||||
|
return job
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# await db.rollback() # Откат транзакции при ошибке
|
||||||
|
logging.error(f"❌ Ошибка при обработке вакансии {job_id}: {e}")
|
||||||
|
# return None
|
||||||
|
|
||||||
|
# except Exception as e:
|
||||||
|
# await db.rollback()
|
||||||
|
# logging.error(f"❌ Ошибка при обработке вакансии {job_id}: {e}")
|
||||||
|
# return None
|
||||||
# [ ]: job_level job_type hourly_rate найти minimum_annual_salary и salary_currency добавил description names Компании url на компанию
|
# [ ]: job_level job_type hourly_rate найти minimum_annual_salary и salary_currency добавил description names Компании url на компанию
|
||||||
logging.info(f"title: {title}, location: {location}, jobPostingId: {jobPostingId}, difference: {difference}, location_type: {localized_name}, link: {link} ===== {names} {url}") #text:{text},
|
# logging.info(f"title: {title}, location: {location}, jobPostingId: {jobPostingId}, difference: {difference}, location_type: {localized_name}, link: {link} ===== {url}") #text:{text},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,41 +196,53 @@ async def get_vakansi():
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
geo = '100025096'
|
# geo = '100025096'
|
||||||
# pars_jobs(geo)
|
# pars_jobs(geo)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# def main():
|
# async def main():
|
||||||
# get_vakansi()
|
# # get_vakansi()
|
||||||
# logging.info("WORK")
|
# # logging.info("WORK")
|
||||||
# get_job('4130181356')
|
# # jobs =
|
||||||
|
# # async def main():
|
||||||
|
# async for db in get_async_session(): # Асинхронный генератор сессий
|
||||||
|
|
||||||
|
# query = select(Job).filter(Job.active == 2)
|
||||||
|
# result = await db.execute(query)
|
||||||
|
# job = result.scalars().first()
|
||||||
|
# for j in job:
|
||||||
|
# ids = j.job_id
|
||||||
|
# print(ids)
|
||||||
|
# # await get_job(db, '4192842821')
|
||||||
|
# # break # Выход после первого использования
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# pars_jobs(geo)
|
# # pars_jobs(geo)
|
||||||
|
|
||||||
# main()
|
# if __name__ == "__main__":
|
||||||
|
# asyncio.run(main())
|
||||||
|
|
||||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
# from sqlalchemy.orm import sessionmaker, declarative_base
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
# from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||||
|
|
||||||
DATABASE_URL = os.getenv('DATABASE_URL')
|
# DATABASE_URL = os.getenv('DATABASE_URL')
|
||||||
engine = create_async_engine(DATABASE_URL, echo=True)
|
# engine = create_async_engine(DATABASE_URL, echo=True)
|
||||||
|
|
||||||
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
# async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||||||
|
|
||||||
|
|
||||||
async_session_maker = sessionmaker(
|
# async_session_maker = sessionmaker(
|
||||||
engine, class_=AsyncSession, expire_on_commit=False
|
# engine, class_=AsyncSession, expire_on_commit=False
|
||||||
)
|
# )
|
||||||
async def main():
|
# async def main():
|
||||||
await get_vakansi()
|
# await get_vakansi()
|
||||||
await engine.dispose() # Корректно закрываем соединение перед завершением
|
# await engine.dispose() # Корректно закрываем соединение перед завершением
|
||||||
|
|
||||||
if __name__ == "__main__":
|
# if __name__ == "__main__":
|
||||||
asyncio.run(main()) # 🚀 Запускаем программу в единственном event loop
|
# asyncio.run(main()) # 🚀 Запускаем программу в единственном event loop
|
||||||
|
|
||||||
# [x] Обмен по времени не удалять main() что бы при старте сразу отрабатывала)
|
# [x] Обмен по времени не удалять main() что бы при старте сразу отрабатывала)
|
||||||
# Запуск функции каждые 5 минут
|
# Запуск функции каждые 5 минут
|
||||||
|
@ -184,3 +260,16 @@ if __name__ == "__main__":
|
||||||
# time.sleep(1) # Пауза между проверками
|
# time.sleep(1) # Пауза между проверками
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async for db in get_async_session(): # Асинхронный генератор сессий
|
||||||
|
query = select(Job).filter(Job.active == 2)
|
||||||
|
result = await db.execute(query)
|
||||||
|
jobs = result.scalars().all() # Получаем ВСЕ записи в виде списка
|
||||||
|
|
||||||
|
for job in jobs:
|
||||||
|
print(job.job_id)
|
||||||
|
await get_job(db, job.job_id)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
|
@ -0,0 +1,43 @@
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from sqlalchemy.future import select
|
||||||
|
from sqlalchemy.exc import IntegrityError
|
||||||
|
from model.database import Client
|
||||||
|
|
||||||
|
async def upsert_client(db: AsyncSession, user_id: str, user_login: str, user_nicename: str, user_email: str, phone: str, json_data: str):
|
||||||
|
# Проверяем, существует ли клиент с таким логином или email
|
||||||
|
async with db.begin():
|
||||||
|
result = await db.execute(
|
||||||
|
select(Client).filter((Client.id == user_id))# | (Client.user_email == user_email))
|
||||||
|
)
|
||||||
|
client = result.scalars().first() # Получаем первый результат или None
|
||||||
|
|
||||||
|
if client:
|
||||||
|
# Если клиент существует, обновляем его данные
|
||||||
|
client.user_nicename = user_nicename
|
||||||
|
client.phone = phone
|
||||||
|
client.json_data = json_data
|
||||||
|
# Можно добавить другие поля для обновления
|
||||||
|
|
||||||
|
try:
|
||||||
|
await db.commit() # Применяем изменения в базе данных
|
||||||
|
await db.refresh(client) # Обновляем объект в Python
|
||||||
|
return client
|
||||||
|
except IntegrityError:
|
||||||
|
await db.rollback() # В случае ошибки откатываем изменения
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
# Если клиента нет, создаем нового
|
||||||
|
new_client = Client(
|
||||||
|
user_login=user_login,
|
||||||
|
user_nicename=user_nicename,
|
||||||
|
user_email=user_email,
|
||||||
|
json_data=json_data,
|
||||||
|
)
|
||||||
|
db.add(new_client)
|
||||||
|
try:
|
||||||
|
await db.commit() # Сохраняем нового клиента в базе данных
|
||||||
|
await db.refresh(new_client) # Обновляем объект в Python
|
||||||
|
return new_client
|
||||||
|
except IntegrityError:
|
||||||
|
await db.rollback() # В случае ошибки откатываем изменения
|
||||||
|
raise
|
Loading…
Reference in New Issue