Compare commits
No commits in common. "076cdd18281bb2130aebcb31477dcd9b87de752b" and "6e804953c094f051747c5254180474e5ffc54d4d" have entirely different histories.
076cdd1828
...
6e804953c0
@ -1,4 +1,4 @@
|
|||||||
from pydantic import BaseModel, Field, EmailStr, ConfigDict
|
from pydantic import BaseModel, Field, EmailStr
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import uuid
|
import uuid
|
||||||
@ -168,22 +168,4 @@ class AutoApproveSettingsUpdateResponse(BaseModel):
|
|||||||
|
|
||||||
class ApproveTransactionsResult(BaseModel):
|
class ApproveTransactionsResult(BaseModel):
|
||||||
msg: str
|
msg: str
|
||||||
approved_count: int
|
approved_count: int
|
||||||
|
|
||||||
# New models for integration tokens
|
|
||||||
class IntegrationTokenResponse(BaseModel):
|
|
||||||
id: int
|
|
||||||
description: str
|
|
||||||
masked_token: str
|
|
||||||
rawToken: Optional[str] = None
|
|
||||||
create_dttm: datetime
|
|
||||||
use_dttm: Optional[datetime] = None
|
|
||||||
|
|
||||||
model_config = ConfigDict(from_attributes=True)
|
|
||||||
|
|
||||||
class IntegrationTokenCreateRequest(BaseModel):
|
|
||||||
description: str
|
|
||||||
|
|
||||||
class IntegrationTokenUpdateRequest(BaseModel):
|
|
||||||
id: int
|
|
||||||
description: str
|
|
||||||
43
fill_db.py
43
fill_db.py
@ -1,7 +1,7 @@
|
|||||||
import random
|
import random
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from sqlmodel import Session
|
from sqlmodel import Session
|
||||||
from sql_models import TgAgent, Ref, Sale, Account, Company, AgentTransaction, PartnerTransaction, CompanyBalance, AgentBalance, IntegrationToken
|
from sql_models import TgAgent, Ref, Sale, Account, Company, AgentTransaction, PartnerTransaction, CompanyBalance, AgentBalance
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
@ -90,23 +90,6 @@ def fill_db():
|
|||||||
session.add(company)
|
session.add(company)
|
||||||
session.commit()
|
session.commit()
|
||||||
session.refresh(company)
|
session.refresh(company)
|
||||||
|
|
||||||
# 0.1 IntegrationTokens
|
|
||||||
for _ in range(3): # Создаем 3 токена для каждой компании
|
|
||||||
new_token_value = str(uuid4()) # Генерируем уникальный токен
|
|
||||||
token_hash = sha256(new_token_value.encode()).hexdigest() # Хешируем токен для хранения
|
|
||||||
masked_token = new_token_value[:5] + "***********************" + new_token_value[-4:] # Генерируем замаскированный токен
|
|
||||||
|
|
||||||
integration_token = IntegrationToken(
|
|
||||||
description=random.choice(DESCRIPTIONS), # Используем существующие описания
|
|
||||||
token_hash=token_hash,
|
|
||||||
masked_token=masked_token,
|
|
||||||
company_id=company.id,
|
|
||||||
use_dttm=random.choice(date_list) if random.random() < 0.7 else None # Пример: 70% токенов будут иметь дату использования
|
|
||||||
)
|
|
||||||
session.add(integration_token)
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
# 1. Accounts
|
# 1. Accounts
|
||||||
accounts = []
|
accounts = []
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
@ -175,23 +158,15 @@ def fill_db():
|
|||||||
for _ in range(sale_count):
|
for _ in range(sale_count):
|
||||||
cost = round(random.uniform(100, 1000), 2)
|
cost = round(random.uniform(100, 1000), 2)
|
||||||
crediting = round(cost * random.uniform(0.5, 1.0), 2)
|
crediting = round(cost * random.uniform(0.5, 1.0), 2)
|
||||||
|
dt = random.choice(date_list)
|
||||||
# Генерируем случайную дату и время в пределах последних 7 дней
|
|
||||||
end_dttm = datetime.utcnow()
|
|
||||||
start_dttm = end_dttm - timedelta(days=7)
|
|
||||||
time_diff = end_dttm - start_dttm
|
|
||||||
random_seconds = random.uniform(0, time_diff.total_seconds())
|
|
||||||
sale_dttm = start_dttm + timedelta(seconds=random_seconds)
|
|
||||||
|
|
||||||
sale = Sale(
|
sale = Sale(
|
||||||
cost=cost,
|
cost=cost,
|
||||||
crediting=crediting,
|
crediting=crediting,
|
||||||
ref=ref.id,
|
ref=ref.id,
|
||||||
sale_id=str(uuid4()),
|
sale_id=str(uuid4()),
|
||||||
company_id=company.id,
|
company_id=company.id,
|
||||||
sale_dttm=sale_dttm,
|
create_dttm=dt,
|
||||||
create_dttm=sale_dttm, # create_dttm также будет случайным в этом диапазоне
|
update_dttm=dt
|
||||||
update_dttm=sale_dttm # update_dttm также будет случайным в этом диапазоне
|
|
||||||
)
|
)
|
||||||
session.add(sale)
|
session.add(sale)
|
||||||
session.commit()
|
session.commit()
|
||||||
@ -228,21 +203,13 @@ def fill_db():
|
|||||||
PARTNER_TRANSACTION_TYPES = ['deposit', 'agent_payout', 'service_fee']
|
PARTNER_TRANSACTION_TYPES = ['deposit', 'agent_payout', 'service_fee']
|
||||||
PARTNER_TRANSACTION_STATUSES = ['process', 'done', 'error', 'new']
|
PARTNER_TRANSACTION_STATUSES = ['process', 'done', 'error', 'new']
|
||||||
|
|
||||||
waiting_transactions_to_ensure = 7
|
|
||||||
waiting_transactions_count = 0
|
|
||||||
|
|
||||||
for tg_agent in tg_agents:
|
for tg_agent in tg_agents:
|
||||||
# Генерируем несколько групп транзакций для каждого агента
|
# Генерируем несколько групп транзакций для каждого агента
|
||||||
for _ in range(random.randint(3, 6)): # От 3 до 6 групп на агента
|
for _ in range(random.randint(3, 6)): # От 3 до 6 групп на агента
|
||||||
transaction_group_id = uuid4()
|
transaction_group_id = uuid4()
|
||||||
dt = random.choice(date_list)
|
dt = random.choice(date_list)
|
||||||
agent_trans_amount = round(random.uniform(500, 3000), 2)
|
agent_trans_amount = round(random.uniform(500, 3000), 2)
|
||||||
|
agent_trans_status = random.choice(AGENT_TRANSACTION_STATUSES)
|
||||||
if waiting_transactions_count < waiting_transactions_to_ensure:
|
|
||||||
agent_trans_status = 'waiting'
|
|
||||||
waiting_transactions_count += 1
|
|
||||||
else:
|
|
||||||
agent_trans_status = random.choice(AGENT_TRANSACTION_STATUSES)
|
|
||||||
|
|
||||||
# Создаем AgentTransaction
|
# Создаем AgentTransaction
|
||||||
agent_transaction = AgentTransaction(
|
agent_transaction = AgentTransaction(
|
||||||
|
|||||||
@ -1,75 +0,0 @@
|
|||||||
from fastapi import FastAPI, HTTPException, status, Depends, Request
|
|
||||||
from sqlmodel import Session, select
|
|
||||||
from typing import Optional
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
import jwt
|
|
||||||
from jwt.exceptions import InvalidTokenError
|
|
||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
from sql_models import Sale
|
|
||||||
from helpers_bff import get_db, AUTH_DB_ENGINE # Assuming these are the correct imports
|
|
||||||
|
|
||||||
app = FastAPI()
|
|
||||||
|
|
||||||
# Конфигурация для интеграционного API токена
|
|
||||||
INTEGRATION_SECRET_KEY = "your-integration-super-secret-key" # Смените это на безопасный ключ!
|
|
||||||
INTEGRATION_ALGORITHM = "HS256"
|
|
||||||
INTEGRATION_TOKEN_EXPIRE_MINUTES = 60 * 24 # 24 часа
|
|
||||||
|
|
||||||
class IntegrationTokenData(BaseModel):
|
|
||||||
client_id: str
|
|
||||||
|
|
||||||
class SaleCreate(BaseModel):
|
|
||||||
cost: float
|
|
||||||
crediting: float
|
|
||||||
ref_id: int
|
|
||||||
sale_id: str
|
|
||||||
company_id: int
|
|
||||||
sale_date: datetime = datetime.utcnow()
|
|
||||||
|
|
||||||
def create_integration_access_token(data: dict, expires_delta: timedelta = None):
|
|
||||||
to_encode = data.copy()
|
|
||||||
if expires_delta:
|
|
||||||
expire = datetime.utcnow() + expires_delta
|
|
||||||
else:
|
|
||||||
expire = datetime.utcnow() + timedelta(minutes=INTEGRATION_TOKEN_EXPIRE_MINUTES)
|
|
||||||
to_encode.update({"exp": expire})
|
|
||||||
encoded_jwt = jwt.encode(to_encode, INTEGRATION_SECRET_KEY, algorithm=INTEGRATION_ALGORITHM)
|
|
||||||
return encoded_jwt
|
|
||||||
|
|
||||||
async def verify_integration_token(request: Request):
|
|
||||||
credentials_exception = HTTPException(
|
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
||||||
detail="Could not validate integration credentials",
|
|
||||||
headers={"WWW-Authenticate": "Bearer"},
|
|
||||||
)
|
|
||||||
auth_header = request.headers.get("Authorization")
|
|
||||||
if not auth_header or not auth_header.startswith("Bearer "):
|
|
||||||
raise credentials_exception
|
|
||||||
token = auth_header.replace("Bearer ", "").strip()
|
|
||||||
try:
|
|
||||||
payload = jwt.decode(token, INTEGRATION_SECRET_KEY, algorithms=[INTEGRATION_ALGORITHM])
|
|
||||||
client_id: str = payload.get("client_id")
|
|
||||||
if client_id is None:
|
|
||||||
raise credentials_exception
|
|
||||||
# Здесь вы можете добавить логику для проверки client_id, например, из базы данных
|
|
||||||
except InvalidTokenError:
|
|
||||||
raise credentials_exception
|
|
||||||
return True # Токен действителен
|
|
||||||
|
|
||||||
@app.post("/sale", status_code=status.HTTP_201_CREATED)
|
|
||||||
async def upload_sale(sale_data: SaleCreate, db: Session = Depends(get_db), verified: bool = Depends(verify_integration_token)):
|
|
||||||
if not verified:
|
|
||||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authorized")
|
|
||||||
|
|
||||||
db_sale = Sale(cost=sale_data.cost, crediting=sale_data.crediting, ref=sale_data.ref_id, sale_id=sale_data.sale_id, company_id=sale_data.company_id, sale_date=sale_data.sale_date)
|
|
||||||
db.add(db_sale)
|
|
||||||
db.commit()
|
|
||||||
db.refresh(db_sale)
|
|
||||||
return {"message": "Sale uploaded successfully", "sale_id": db_sale.id}
|
|
||||||
|
|
||||||
@app.get("/generate-integration-token")
|
|
||||||
async def generate_token_endpoint(client_id: str):
|
|
||||||
token_data = {"client_id": client_id}
|
|
||||||
token = create_integration_access_token(token_data)
|
|
||||||
return {"access_token": token, "token_type": "bearer"}
|
|
||||||
111
main.py
111
main.py
@ -8,7 +8,7 @@ from fastapi import (
|
|||||||
Body,
|
Body,
|
||||||
)
|
)
|
||||||
from fastapi.security import OAuth2PasswordRequestForm
|
from fastapi.security import OAuth2PasswordRequestForm
|
||||||
from sqlmodel import SQLModel, Session, select, Field
|
from sqlmodel import SQLModel, Session, select
|
||||||
from typing import Optional, List, Dict
|
from typing import Optional, List, Dict
|
||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
from bff_models import (
|
from bff_models import (
|
||||||
@ -37,10 +37,7 @@ from bff_models import (
|
|||||||
AutoApproveSettingsRequest,
|
AutoApproveSettingsRequest,
|
||||||
ApproveTransactionsRequest,
|
ApproveTransactionsRequest,
|
||||||
AgentTransactionResponse,
|
AgentTransactionResponse,
|
||||||
TransactionStatus,
|
TransactionStatus
|
||||||
IntegrationTokenResponse,
|
|
||||||
IntegrationTokenCreateRequest,
|
|
||||||
IntegrationTokenUpdateRequest
|
|
||||||
)
|
)
|
||||||
from tg_models import RefAddRequest, RefResponse, RegisterRequest, RefAddResponse, RefStatResponse, StatResponse
|
from tg_models import RefAddRequest, RefResponse, RegisterRequest, RefAddResponse, RefStatResponse, StatResponse
|
||||||
from sql_models import (
|
from sql_models import (
|
||||||
@ -51,8 +48,7 @@ from sql_models import (
|
|||||||
AgentTransaction,
|
AgentTransaction,
|
||||||
PartnerTransaction,
|
PartnerTransaction,
|
||||||
AgentBalance,
|
AgentBalance,
|
||||||
Account,
|
Account
|
||||||
IntegrationToken
|
|
||||||
)
|
)
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
import hashlib
|
import hashlib
|
||||||
@ -69,7 +65,6 @@ from helpers_bff import (
|
|||||||
pwd_context,
|
pwd_context,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Создание движка базы данных
|
# Создание движка базы данных
|
||||||
SQLModel.metadata.create_all(AUTH_DB_ENGINE)
|
SQLModel.metadata.create_all(AUTH_DB_ENGINE)
|
||||||
|
|
||||||
@ -241,11 +236,11 @@ def get_dashboard_chart_total(current_account: Account = Depends(get_current_acc
|
|||||||
# Группируем продажи по дате (день)
|
# Группируем продажи по дате (день)
|
||||||
result = db.exec(
|
result = db.exec(
|
||||||
select(
|
select(
|
||||||
func.strftime('%Y-%m-%d', Sale.sale_dttm).label('date'),
|
func.strftime('%Y-%m-%d', Sale.create_dttm).label('date'),
|
||||||
func.sum(Sale.cost).label('revenue'),
|
func.sum(Sale.cost).label('revenue'),
|
||||||
func.count(Sale.id).label('sales')
|
func.count(Sale.id).label('sales')
|
||||||
).where(Sale.company_id == current_account.company_id).group_by(func.strftime('%Y-%m-%d', Sale.sale_dttm))
|
).where(Sale.company_id == current_account.company_id).group_by(func.strftime('%Y-%m-%d', Sale.create_dttm))
|
||||||
.order_by(func.strftime('%Y-%m-%d', Sale.sale_dttm))
|
.order_by(func.strftime('%Y-%m-%d', Sale.create_dttm))
|
||||||
).all()
|
).all()
|
||||||
# Преобразуем результат в нужный формат
|
# Преобразуем результат в нужный формат
|
||||||
data = [
|
data = [
|
||||||
@ -373,9 +368,9 @@ def get_sales_stat(
|
|||||||
"""
|
"""
|
||||||
sales_query = select(Sale).where(Sale.company_id == current_account.company_id)
|
sales_query = select(Sale).where(Sale.company_id == current_account.company_id)
|
||||||
if date_start:
|
if date_start:
|
||||||
sales_query = sales_query.where(Sale.sale_dttm >= date_start)
|
sales_query = sales_query.where(Sale.create_dttm >= date_start)
|
||||||
if date_end:
|
if date_end:
|
||||||
sales_query = sales_query.where(Sale.sale_dttm <= date_end)
|
sales_query = sales_query.where(Sale.create_dttm <= date_end)
|
||||||
sales = db.exec(sales_query).all()
|
sales = db.exec(sales_query).all()
|
||||||
ref_ids = list(set(sale.ref for sale in sales))
|
ref_ids = list(set(sale.ref for sale in sales))
|
||||||
refs = db.exec(select(Ref).where(Ref.id.in_(ref_ids))).all() if ref_ids else []
|
refs = db.exec(select(Ref).where(Ref.id.in_(ref_ids))).all() if ref_ids else []
|
||||||
@ -750,93 +745,3 @@ def approve_agent_transactions(
|
|||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
return {"msg": f"Переведено в статус NEW {approved_count} транзакций", "approved_count": approved_count}
|
return {"msg": f"Переведено в статус NEW {approved_count} транзакций", "approved_count": approved_count}
|
||||||
|
|
||||||
# --- Новый функционал для интеграционных токенов ---
|
|
||||||
|
|
||||||
@app.get("/account/integration-tokens", tags=["bff", "account"], response_model=List[IntegrationTokenResponse])
|
|
||||||
def get_integration_tokens(
|
|
||||||
current_account: Account = Depends(get_current_account),
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Возвращает список интеграционных токенов для компании текущего пользователя.
|
|
||||||
"""
|
|
||||||
tokens = db.exec(select(IntegrationToken).where(IntegrationToken.company_id == current_account.company_id)).all()
|
|
||||||
return tokens # Позволяем FastAPI самостоятельно сериализовать объекты IntegrationToken в IntegrationTokenResponse
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/account/integration-tokens", tags=["bff", "account"], response_model=IntegrationTokenResponse)
|
|
||||||
def create_integration_token(
|
|
||||||
req: IntegrationTokenCreateRequest,
|
|
||||||
current_account: Account = Depends(get_current_account),
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Создает новый интеграционный токен для компании текущего пользователя.
|
|
||||||
Возвращает созданный токен (замаскированный).
|
|
||||||
"""
|
|
||||||
new_token_value = str(uuid.uuid4()) # Генерируем уникальный токен
|
|
||||||
token_hash = hashlib.sha256(new_token_value.encode()).hexdigest() # Хешируем токен для хранения
|
|
||||||
|
|
||||||
# Генерируем замаскированный токен
|
|
||||||
masked_token = new_token_value[:5] + "***********************" + new_token_value[-4:]
|
|
||||||
|
|
||||||
new_integration_token = IntegrationToken(
|
|
||||||
description=req.description,
|
|
||||||
token_hash=token_hash,
|
|
||||||
masked_token=masked_token,
|
|
||||||
company_id=current_account.company_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
db.add(new_integration_token)
|
|
||||||
db.commit()
|
|
||||||
db.refresh(new_integration_token)
|
|
||||||
|
|
||||||
# Создаем объект ответа, используя model_validate для извлечения данных из new_integration_token
|
|
||||||
response_token = IntegrationTokenResponse.model_validate(new_integration_token)
|
|
||||||
response_token.rawToken = new_token_value # Добавляем незамаскированный токен
|
|
||||||
|
|
||||||
return response_token
|
|
||||||
|
|
||||||
@app.post("/account/integration-tokens/update-description", tags=["bff", "account"], response_model=Dict[str, str])
|
|
||||||
def update_integration_token_description(
|
|
||||||
req: IntegrationTokenUpdateRequest,
|
|
||||||
current_account: Account = Depends(get_current_account),
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Обновляет описание интеграционного токена по его ID.
|
|
||||||
"""
|
|
||||||
token = db.exec(
|
|
||||||
select(IntegrationToken).where(IntegrationToken.id == req.id).where(IntegrationToken.company_id == current_account.company_id)
|
|
||||||
).first()
|
|
||||||
|
|
||||||
if not token:
|
|
||||||
raise HTTPException(status_code=404, detail="Токен не найден")
|
|
||||||
|
|
||||||
token.description = req.description
|
|
||||||
token.update_dttm = datetime.utcnow() # Обновляем дату изменения, если поле существует
|
|
||||||
db.add(token)
|
|
||||||
db.commit()
|
|
||||||
db.refresh(token)
|
|
||||||
return {"msg": "Описание токена обновлено успешно"}
|
|
||||||
|
|
||||||
@app.delete("/account/integration-tokens/{token_id}", tags=["bff", "account"], response_model=Dict[str, str])
|
|
||||||
def delete_integration_token(
|
|
||||||
token_id: int,
|
|
||||||
current_account: Account = Depends(get_current_account),
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Удаляет интеграционный токен по его ID для компании текущего пользователя.
|
|
||||||
"""
|
|
||||||
token = db.exec(
|
|
||||||
select(IntegrationToken).where(IntegrationToken.id == token_id).where(IntegrationToken.company_id == current_account.company_id)
|
|
||||||
).first()
|
|
||||||
|
|
||||||
if not token:
|
|
||||||
raise HTTPException(status_code=404, detail="Токен не найден")
|
|
||||||
|
|
||||||
db.delete(token)
|
|
||||||
db.commit()
|
|
||||||
return {"msg": "Токен удален успешно"}
|
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
from typing import Optional, List
|
from typing import Optional
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import uuid
|
import uuid
|
||||||
from sqlmodel import SQLModel, Field, Relationship
|
from sqlmodel import SQLModel, Field
|
||||||
from sqlalchemy import Column, String
|
|
||||||
|
|
||||||
class Company(SQLModel, table=True):
|
class Company(SQLModel, table=True):
|
||||||
id: Optional[int] = Field(default=None, primary_key=True)
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
@ -13,8 +12,6 @@ class Company(SQLModel, table=True):
|
|||||||
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||||
auto_approve_transactions: bool = Field(default=False)
|
auto_approve_transactions: bool = Field(default=False)
|
||||||
|
|
||||||
integration_tokens: List["IntegrationToken"] = Relationship(back_populates="company")
|
|
||||||
|
|
||||||
class TgAgent(SQLModel, table=True):
|
class TgAgent(SQLModel, table=True):
|
||||||
id: Optional[int] = Field(default=None, primary_key=True)
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
tg_id: int = Field(index=True, unique=True)
|
tg_id: int = Field(index=True, unique=True)
|
||||||
@ -42,7 +39,6 @@ class Sale(SQLModel, table=True):
|
|||||||
ref: int = Field(foreign_key="ref.id")
|
ref: int = Field(foreign_key="ref.id")
|
||||||
sale_id: str
|
sale_id: str
|
||||||
company_id: int = Field(foreign_key="company.id")
|
company_id: int = Field(foreign_key="company.id")
|
||||||
sale_dttm: datetime = Field(default_factory=datetime.utcnow)
|
|
||||||
create_dttm: datetime = Field(default_factory=datetime.utcnow)
|
create_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||||
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||||
|
|
||||||
@ -94,17 +90,4 @@ class Account(SQLModel, table=True):
|
|||||||
email: Optional[str] = None
|
email: Optional[str] = None
|
||||||
company_id: int = Field(foreign_key="company.id")
|
company_id: int = Field(foreign_key="company.id")
|
||||||
create_dttm: datetime = Field(default_factory=datetime.utcnow)
|
create_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||||
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||||
|
|
||||||
# Новая модель для интеграционных токенов
|
|
||||||
class IntegrationToken(SQLModel, table=True):
|
|
||||||
id: Optional[int] = Field(default=None, primary_key=True)
|
|
||||||
description: str
|
|
||||||
token_hash: str = Field(sa_column=Column(String, unique=True, index=True))
|
|
||||||
masked_token: str = Field(sa_column=Column(String))
|
|
||||||
company_id: int = Field(foreign_key="company.id")
|
|
||||||
create_dttm: datetime = Field(default_factory=datetime.utcnow, nullable=False)
|
|
||||||
update_dttm: datetime = Field(default_factory=datetime.utcnow, nullable=False)
|
|
||||||
use_dttm: Optional[datetime] = None
|
|
||||||
|
|
||||||
company: Company = Relationship(back_populates="integration_tokens")
|
|
||||||
Loading…
x
Reference in New Issue
Block a user