Добавлены новые модели для интеграционных токенов в bff_models.py и sql_models.py. Реализованы функции для создания, обновления и удаления токенов в main.py, а также обновлено заполнение базы данных в fill_db.py для генерации токенов. Обновлены запросы к базе данных для учета новых полей и логики работы с токенами.
This commit is contained in:
parent
57188186c0
commit
076cdd1828
@ -1,4 +1,4 @@
|
||||
from pydantic import BaseModel, Field, EmailStr
|
||||
from pydantic import BaseModel, Field, EmailStr, ConfigDict
|
||||
from typing import Optional, List
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
@ -169,3 +169,21 @@ class AutoApproveSettingsUpdateResponse(BaseModel):
|
||||
class ApproveTransactionsResult(BaseModel):
|
||||
msg: str
|
||||
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
|
||||
42
fill_db.py
42
fill_db.py
@ -1,7 +1,7 @@
|
||||
import random
|
||||
from uuid import uuid4
|
||||
from sqlmodel import Session
|
||||
from sql_models import TgAgent, Ref, Sale, Account, Company, AgentTransaction, PartnerTransaction, CompanyBalance, AgentBalance
|
||||
from sql_models import TgAgent, Ref, Sale, Account, Company, AgentTransaction, PartnerTransaction, CompanyBalance, AgentBalance, IntegrationToken
|
||||
from sqlalchemy import text
|
||||
from datetime import datetime, timedelta
|
||||
from hashlib import sha256
|
||||
@ -90,6 +90,23 @@ def fill_db():
|
||||
session.add(company)
|
||||
session.commit()
|
||||
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
|
||||
accounts = []
|
||||
for i in range(4):
|
||||
@ -158,16 +175,23 @@ def fill_db():
|
||||
for _ in range(sale_count):
|
||||
cost = round(random.uniform(100, 1000), 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(
|
||||
cost=cost,
|
||||
crediting=crediting,
|
||||
ref=ref.id,
|
||||
sale_id=str(uuid4()),
|
||||
company_id=company.id,
|
||||
sale_date=dt,
|
||||
create_dttm=dt,
|
||||
update_dttm=dt
|
||||
sale_dttm=sale_dttm,
|
||||
create_dttm=sale_dttm, # create_dttm также будет случайным в этом диапазоне
|
||||
update_dttm=sale_dttm # update_dttm также будет случайным в этом диапазоне
|
||||
)
|
||||
session.add(sale)
|
||||
session.commit()
|
||||
@ -204,12 +228,20 @@ def fill_db():
|
||||
PARTNER_TRANSACTION_TYPES = ['deposit', 'agent_payout', 'service_fee']
|
||||
PARTNER_TRANSACTION_STATUSES = ['process', 'done', 'error', 'new']
|
||||
|
||||
waiting_transactions_to_ensure = 7
|
||||
waiting_transactions_count = 0
|
||||
|
||||
for tg_agent in tg_agents:
|
||||
# Генерируем несколько групп транзакций для каждого агента
|
||||
for _ in range(random.randint(3, 6)): # От 3 до 6 групп на агента
|
||||
transaction_group_id = uuid4()
|
||||
dt = random.choice(date_list)
|
||||
agent_trans_amount = round(random.uniform(500, 3000), 2)
|
||||
|
||||
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
|
||||
|
||||
111
main.py
111
main.py
@ -8,7 +8,7 @@ from fastapi import (
|
||||
Body,
|
||||
)
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
from sqlmodel import SQLModel, Session, select
|
||||
from sqlmodel import SQLModel, Session, select, Field
|
||||
from typing import Optional, List, Dict
|
||||
from datetime import timedelta, datetime
|
||||
from bff_models import (
|
||||
@ -37,7 +37,10 @@ from bff_models import (
|
||||
AutoApproveSettingsRequest,
|
||||
ApproveTransactionsRequest,
|
||||
AgentTransactionResponse,
|
||||
TransactionStatus
|
||||
TransactionStatus,
|
||||
IntegrationTokenResponse,
|
||||
IntegrationTokenCreateRequest,
|
||||
IntegrationTokenUpdateRequest
|
||||
)
|
||||
from tg_models import RefAddRequest, RefResponse, RegisterRequest, RefAddResponse, RefStatResponse, StatResponse
|
||||
from sql_models import (
|
||||
@ -48,7 +51,8 @@ from sql_models import (
|
||||
AgentTransaction,
|
||||
PartnerTransaction,
|
||||
AgentBalance,
|
||||
Account
|
||||
Account,
|
||||
IntegrationToken
|
||||
)
|
||||
from sqlalchemy import func
|
||||
import hashlib
|
||||
@ -65,6 +69,7 @@ from helpers_bff import (
|
||||
pwd_context,
|
||||
)
|
||||
|
||||
|
||||
# Создание движка базы данных
|
||||
SQLModel.metadata.create_all(AUTH_DB_ENGINE)
|
||||
|
||||
@ -236,11 +241,11 @@ def get_dashboard_chart_total(current_account: Account = Depends(get_current_acc
|
||||
# Группируем продажи по дате (день)
|
||||
result = db.exec(
|
||||
select(
|
||||
func.strftime('%Y-%m-%d', Sale.sale_date).label('date'),
|
||||
func.strftime('%Y-%m-%d', Sale.sale_dttm).label('date'),
|
||||
func.sum(Sale.cost).label('revenue'),
|
||||
func.count(Sale.id).label('sales')
|
||||
).where(Sale.company_id == current_account.company_id).group_by(func.strftime('%Y-%m-%d', Sale.sale_date))
|
||||
.order_by(func.strftime('%Y-%m-%d', Sale.sale_date))
|
||||
).where(Sale.company_id == current_account.company_id).group_by(func.strftime('%Y-%m-%d', Sale.sale_dttm))
|
||||
.order_by(func.strftime('%Y-%m-%d', Sale.sale_dttm))
|
||||
).all()
|
||||
# Преобразуем результат в нужный формат
|
||||
data = [
|
||||
@ -368,9 +373,9 @@ def get_sales_stat(
|
||||
"""
|
||||
sales_query = select(Sale).where(Sale.company_id == current_account.company_id)
|
||||
if date_start:
|
||||
sales_query = sales_query.where(Sale.sale_date >= date_start)
|
||||
sales_query = sales_query.where(Sale.sale_dttm >= date_start)
|
||||
if date_end:
|
||||
sales_query = sales_query.where(Sale.sale_date <= date_end)
|
||||
sales_query = sales_query.where(Sale.sale_dttm <= date_end)
|
||||
sales = db.exec(sales_query).all()
|
||||
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 []
|
||||
@ -745,3 +750,93 @@ def approve_agent_transactions(
|
||||
db.commit()
|
||||
|
||||
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,7 +1,8 @@
|
||||
from typing import Optional
|
||||
from typing import Optional, List
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
from sqlmodel import SQLModel, Field
|
||||
from sqlmodel import SQLModel, Field, Relationship
|
||||
from sqlalchemy import Column, String
|
||||
|
||||
class Company(SQLModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
@ -12,6 +13,8 @@ class Company(SQLModel, table=True):
|
||||
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||
auto_approve_transactions: bool = Field(default=False)
|
||||
|
||||
integration_tokens: List["IntegrationToken"] = Relationship(back_populates="company")
|
||||
|
||||
class TgAgent(SQLModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
tg_id: int = Field(index=True, unique=True)
|
||||
@ -92,3 +95,16 @@ class Account(SQLModel, table=True):
|
||||
company_id: int = Field(foreign_key="company.id")
|
||||
create_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