Compare commits
No commits in common. "161e0b3ec45213931e524943ca552dfbee6715e5" and "1f11bd8012658efbef4dc87a1582f16bcffd15d3" have entirely different histories.
161e0b3ec4
...
1f11bd8012
40
fill_db.py
40
fill_db.py
@ -1,7 +1,7 @@
|
||||
import random
|
||||
from uuid import uuid4
|
||||
from sqlmodel import Session
|
||||
from main import AUTH_DB_ENGINE, TgAgent, Ref, Sale, Transaction, Account, Company
|
||||
from main import AUTH_DB_ENGINE, TgAgent, Ref, Sale, Transaction, Account
|
||||
from sqlalchemy import text
|
||||
from datetime import datetime, timedelta
|
||||
from hashlib import sha256
|
||||
@ -80,39 +80,23 @@ def fill_db():
|
||||
session.execute(text("DELETE FROM ref"))
|
||||
session.execute(text("DELETE FROM tgagent"))
|
||||
session.execute(text("DELETE FROM account"))
|
||||
session.execute(text('DELETE FROM "transaction"'))
|
||||
session.execute(text("DELETE FROM company"))
|
||||
session.commit()
|
||||
# 0. Company
|
||||
company = Company(
|
||||
name="RE: Premium",
|
||||
commission=10.0,
|
||||
key="re-premium-key",
|
||||
)
|
||||
session.add(company)
|
||||
session.commit()
|
||||
session.refresh(company)
|
||||
# 1. Accounts
|
||||
# 0. Accounts
|
||||
accounts = []
|
||||
for i in range(4):
|
||||
name_parts = NAMES[i % len(NAMES)].split()
|
||||
first_name = name_parts[0]
|
||||
surname = name_parts[1] if len(name_parts) > 1 else 'Тестов'
|
||||
acc = Account(
|
||||
login=f"user{i+1}",
|
||||
password_hash=get_password_hash("password123"),
|
||||
firstName=first_name,
|
||||
surname=surname,
|
||||
phone=PHONES[i % len(PHONES)],
|
||||
password_hash=get_password_hash("password123"), # теперь храним хеш
|
||||
name=NAMES[i % len(NAMES)],
|
||||
email=f"user{i+1}@example.com",
|
||||
company_id=company.id
|
||||
balance=round(random.uniform(1000, 10000), 2)
|
||||
)
|
||||
session.add(acc)
|
||||
accounts.append(acc)
|
||||
session.commit()
|
||||
for acc in accounts:
|
||||
session.refresh(acc)
|
||||
# 2. TgAgents
|
||||
# 1. TgAgents
|
||||
tg_agents = []
|
||||
for i, tg_agent_id in enumerate(USER_IDS):
|
||||
dt = random.choice(date_list)
|
||||
@ -123,7 +107,6 @@ def fill_db():
|
||||
phone=PHONES[i % len(PHONES)],
|
||||
name=NAMES[i % len(NAMES)],
|
||||
login=LOGINS[i % len(LOGINS)],
|
||||
company_id=company.id,
|
||||
create_dttm=dt,
|
||||
update_dttm=dt,
|
||||
hash=hash_value
|
||||
@ -133,7 +116,8 @@ def fill_db():
|
||||
session.commit()
|
||||
for tg_agent in tg_agents:
|
||||
session.refresh(tg_agent)
|
||||
# 3. Refs (минимум 22 на агента)
|
||||
|
||||
# 2. Refs (минимум 22 на агента)
|
||||
refs = []
|
||||
desc_count = len(ALL_DESCRIPTIONS)
|
||||
for tg_agent in tg_agents:
|
||||
@ -154,7 +138,8 @@ def fill_db():
|
||||
session.commit()
|
||||
for ref in refs:
|
||||
session.refresh(ref)
|
||||
# 4. Sales (минимум 20 на каждый ref)
|
||||
|
||||
# 3. Sales (минимум 20 на каждый ref)
|
||||
for ref in refs:
|
||||
sale_count = random.randint(20, int(20 * 1.25)) # от 20 до 25
|
||||
for _ in range(sale_count):
|
||||
@ -166,13 +151,13 @@ def fill_db():
|
||||
crediting=crediting,
|
||||
ref=ref.id,
|
||||
sale_id=str(uuid4()),
|
||||
company_id=company.id,
|
||||
create_dttm=dt,
|
||||
update_dttm=dt
|
||||
)
|
||||
session.add(sale)
|
||||
session.commit()
|
||||
# 5. Transactions (только withdrawal на агента)
|
||||
|
||||
# 4. Transactions (только withdrawal на агента)
|
||||
TRANSACTION_STATUSES = ['process', 'done', 'error', 'waiting']
|
||||
for tg_agent in tg_agents:
|
||||
withdrawal_count = random.randint(5, int(5 * 1.25)) # от 5 до 6
|
||||
@ -190,7 +175,6 @@ def fill_db():
|
||||
sum=round(random.uniform(200, 3000), 2),
|
||||
tg_agent_id=tg_agent.id,
|
||||
status=status,
|
||||
company_id=company.id,
|
||||
create_dttm=dt,
|
||||
update_dttm=dt
|
||||
)
|
||||
|
||||
144
main.py
144
main.py
@ -10,21 +10,11 @@ from fastapi.responses import JSONResponse
|
||||
from sqlalchemy import func
|
||||
from hashlib import sha256
|
||||
import jwt
|
||||
from jwt.exceptions import InvalidTokenError
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
# Конфигурация
|
||||
AUTH_DATABASE_ADDRESS = "sqlite:///partner.db"
|
||||
|
||||
#SQLModel
|
||||
class Company(SQLModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
name: str
|
||||
commission: float # процент комиссии
|
||||
key: str = Field(index=True, unique=True)
|
||||
create_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
class TgAgent(SQLModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
tg_id: int = Field(index=True, unique=True)
|
||||
@ -33,7 +23,6 @@ class TgAgent(SQLModel, table=True):
|
||||
name: Optional[str] = None
|
||||
login: Optional[str] = None
|
||||
hash: Optional[str] = None
|
||||
company_id: int = Field(foreign_key="company.id")
|
||||
create_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
@ -51,7 +40,6 @@ class Sale(SQLModel, table=True):
|
||||
crediting: float # сколько начислено за продажу
|
||||
ref: int = Field(foreign_key="ref.id")
|
||||
sale_id: str
|
||||
company_id: int = Field(foreign_key="company.id")
|
||||
create_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
@ -61,7 +49,6 @@ class Transaction(SQLModel, table=True):
|
||||
sum: float
|
||||
tg_agent_id: int = Field(foreign_key="tgagent.id")
|
||||
status: str # 'process' || 'done' || 'error' || 'waiting'
|
||||
company_id: int = Field(foreign_key="company.id")
|
||||
create_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
@ -69,23 +56,9 @@ class Account(SQLModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
login: str = Field(index=True, unique=True)
|
||||
password_hash: str # теперь хранится hash пароля
|
||||
firstName: Optional[str] = None
|
||||
surname: Optional[str] = None
|
||||
phone: Optional[str] = None
|
||||
name: Optional[str] = None
|
||||
email: Optional[str] = None
|
||||
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 AccountProfileUpdateRequest(BaseModel):
|
||||
firstName: str
|
||||
surname: str
|
||||
email: EmailStr
|
||||
phone: str
|
||||
|
||||
class AccountPasswordChangeRequest(BaseModel):
|
||||
currentPassword: str
|
||||
newPassword: str
|
||||
balance: float = 0.0
|
||||
|
||||
# Создание движка базы данных
|
||||
AUTH_DB_ENGINE = create_engine(AUTH_DATABASE_ADDRESS, echo=True)
|
||||
@ -137,25 +110,12 @@ def register(req: RegisterRequest, db: Session = Depends(get_db)):
|
||||
phone = req.phone
|
||||
name = getattr(req, 'name', None)
|
||||
login = getattr(req, 'login', None)
|
||||
company_key = req.company_key
|
||||
print(f'tg_id: {tg_id}, chat_id: {chat_id}, phone: {phone}, name: {name}, login: {login}, company_key: {company_key}')
|
||||
print(f'tg_id: {tg_id}, chat_id: {chat_id}, phone: {phone}, name: {name}, login: {login}')
|
||||
tg_agent = get_tg_agent_by_tg_id(db, tg_id)
|
||||
if tg_agent:
|
||||
raise HTTPException(status_code=400, detail="tg_id already registered")
|
||||
# Поиск компании по ключу
|
||||
company = db.exec(select(Company).where(Company.key == company_key)).first()
|
||||
if not company:
|
||||
raise HTTPException(status_code=400, detail="Компания с таким ключом не найдена")
|
||||
hash_value = sha256(f"{tg_id}sold".encode()).hexdigest()
|
||||
new_tg_agent = TgAgent(
|
||||
tg_id=tg_id,
|
||||
chat_id=chat_id,
|
||||
phone=phone,
|
||||
name=name,
|
||||
login=login,
|
||||
hash=hash_value,
|
||||
company_id=company.id
|
||||
)
|
||||
new_tg_agent = TgAgent(tg_id=tg_id, chat_id=chat_id, phone=phone, name=name, login=login, hash=hash_value)
|
||||
db.add(new_tg_agent)
|
||||
db.commit()
|
||||
db.refresh(new_tg_agent)
|
||||
@ -512,7 +472,18 @@ def get_billing_chart_pie(db: Session = Depends(get_db)):
|
||||
]
|
||||
return JSONResponse(content=data)
|
||||
|
||||
|
||||
@app.get("/account", tags=["bff"])
|
||||
def get_account(db: Session = Depends(get_db)):
|
||||
account = db.exec(select(Account)).first()
|
||||
if not account:
|
||||
raise HTTPException(status_code=404, detail="Account not found")
|
||||
return {
|
||||
"id": account.id,
|
||||
"login": account.login,
|
||||
"name": account.name,
|
||||
"email": account.email,
|
||||
"balance": account.balance
|
||||
}
|
||||
|
||||
@app.post("/tg_auth", tags=["partner-tg"])
|
||||
def tg_auth(hash: str = Body(..., embed=True), db: Session = Depends(get_db)):
|
||||
@ -530,86 +501,3 @@ def verify_password(plain_password, hashed_password):
|
||||
def get_account_by_login(db: Session, login: str) -> Optional[Account]:
|
||||
statement = select(Account).where(Account.login == login)
|
||||
return db.exec(statement).first()
|
||||
|
||||
def get_current_account(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
|
||||
credentials_exception = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Could not validate credentials",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
try:
|
||||
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
||||
login: str = payload.get("sub")
|
||||
if login is None:
|
||||
raise credentials_exception
|
||||
except InvalidTokenError:
|
||||
raise credentials_exception
|
||||
account = get_account_by_login(db, login)
|
||||
if account is None:
|
||||
raise credentials_exception
|
||||
return account
|
||||
|
||||
@app.get("/account", tags=["bff"])
|
||||
def get_account(current_account: Account = Depends(get_current_account)):
|
||||
return {
|
||||
"firstName": current_account.firstName,
|
||||
"surname": current_account.surname
|
||||
}
|
||||
|
||||
@app.get("/account/profile", tags=["bff"])
|
||||
def get_account_profile(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
|
||||
company = db.exec(select(Company).where(Company.id == current_account.company_id)).first()
|
||||
if not company:
|
||||
raise HTTPException(status_code=404, detail="Компания не найдена")
|
||||
return {
|
||||
"firstName": current_account.firstName,
|
||||
"surname": current_account.surname,
|
||||
"phone": current_account.phone,
|
||||
"email": current_account.email,
|
||||
"create_dttm": current_account.create_dttm,
|
||||
"company": {
|
||||
"name": company.name,
|
||||
"key": company.key,
|
||||
"commission": company.commission
|
||||
}
|
||||
}
|
||||
|
||||
@app.post("/account/profile", tags=["bff"])
|
||||
def update_account_profile(
|
||||
req: AccountProfileUpdateRequest,
|
||||
current_account: Account = Depends(get_current_account),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
# Проверка, что все поля заполнены (Pydantic уже валидирует email и обязательность)
|
||||
if not req.firstName.strip() or not req.surname.strip() or not req.email or not req.phone.strip():
|
||||
raise HTTPException(status_code=400, detail="Все поля должны быть заполнены")
|
||||
# Обновляем поля
|
||||
current_account.firstName = req.firstName.strip()
|
||||
current_account.surname = req.surname.strip()
|
||||
current_account.email = req.email
|
||||
current_account.phone = req.phone.strip()
|
||||
db.add(current_account)
|
||||
db.commit()
|
||||
db.refresh(current_account)
|
||||
return {"msg": "Профиль обновлён успешно"}
|
||||
|
||||
@app.post("/account/password", tags=["bff"])
|
||||
def change_account_password(
|
||||
req: AccountPasswordChangeRequest,
|
||||
current_account: Account = Depends(get_current_account),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
# Проверяем текущий пароль
|
||||
if not verify_password(req.currentPassword, current_account.password_hash):
|
||||
raise HTTPException(status_code=400, detail="Текущий пароль неверный")
|
||||
# Проверяем, что новый пароль не пустой и отличается от текущего
|
||||
if not req.newPassword.strip():
|
||||
raise HTTPException(status_code=400, detail="Новый пароль не может быть пустым")
|
||||
if verify_password(req.newPassword, current_account.password_hash):
|
||||
raise HTTPException(status_code=400, detail="Новый пароль не должен совпадать с текущим")
|
||||
# Хешируем и сохраняем новый пароль
|
||||
current_account.password_hash = pwd_context.hash(req.newPassword)
|
||||
db.add(current_account)
|
||||
db.commit()
|
||||
db.refresh(current_account)
|
||||
return {"msg": "Пароль успешно изменён"}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user