mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-20 03:40:26 +00:00
140 lines
4.9 KiB
Python
140 lines
4.9 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.database.crud.promo_group import (
|
|
count_promo_group_members,
|
|
create_promo_group,
|
|
delete_promo_group,
|
|
get_promo_group_by_id,
|
|
get_promo_groups_with_counts,
|
|
update_promo_group,
|
|
)
|
|
from app.database.models import PromoGroup
|
|
|
|
from ..dependencies import get_db_session, require_api_token
|
|
from ..schemas.promo_groups import (
|
|
PromoGroupCreateRequest,
|
|
PromoGroupResponse,
|
|
PromoGroupUpdateRequest,
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
def _normalize_period_discounts(group: PromoGroup) -> dict[int, int]:
|
|
raw = group.period_discounts or {}
|
|
normalized: dict[int, int] = {}
|
|
if isinstance(raw, dict):
|
|
for key, value in raw.items():
|
|
try:
|
|
normalized[int(key)] = int(value)
|
|
except (TypeError, ValueError):
|
|
continue
|
|
return normalized
|
|
|
|
|
|
def _serialize(group: PromoGroup, members_count: int = 0) -> PromoGroupResponse:
|
|
return PromoGroupResponse(
|
|
id=group.id,
|
|
name=group.name,
|
|
server_discount_percent=group.server_discount_percent,
|
|
traffic_discount_percent=group.traffic_discount_percent,
|
|
device_discount_percent=group.device_discount_percent,
|
|
period_discounts=_normalize_period_discounts(group),
|
|
auto_assign_total_spent_kopeks=group.auto_assign_total_spent_kopeks,
|
|
apply_discounts_to_addons=group.apply_discounts_to_addons,
|
|
is_default=group.is_default,
|
|
members_count=members_count,
|
|
created_at=group.created_at,
|
|
updated_at=group.updated_at,
|
|
)
|
|
|
|
|
|
@router.get("", response_model=list[PromoGroupResponse])
|
|
async def list_promo_groups(
|
|
_: Any = Depends(require_api_token),
|
|
db: AsyncSession = Depends(get_db_session),
|
|
) -> list[PromoGroupResponse]:
|
|
groups_with_counts = await get_promo_groups_with_counts(db)
|
|
return [_serialize(group, members_count=count) for group, count in groups_with_counts]
|
|
|
|
|
|
@router.get("/{group_id}", response_model=PromoGroupResponse)
|
|
async def get_promo_group(
|
|
group_id: int,
|
|
_: Any = Depends(require_api_token),
|
|
db: AsyncSession = Depends(get_db_session),
|
|
) -> PromoGroupResponse:
|
|
group = await get_promo_group_by_id(db, group_id)
|
|
if not group:
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, "Promo group not found")
|
|
|
|
members_count = await count_promo_group_members(db, group_id)
|
|
return _serialize(group, members_count=members_count)
|
|
|
|
|
|
@router.post("", response_model=PromoGroupResponse, status_code=status.HTTP_201_CREATED)
|
|
async def create_promo_group_endpoint(
|
|
payload: PromoGroupCreateRequest,
|
|
_: Any = Depends(require_api_token),
|
|
db: AsyncSession = Depends(get_db_session),
|
|
) -> PromoGroupResponse:
|
|
group = await create_promo_group(
|
|
db,
|
|
name=payload.name,
|
|
server_discount_percent=payload.server_discount_percent,
|
|
traffic_discount_percent=payload.traffic_discount_percent,
|
|
device_discount_percent=payload.device_discount_percent,
|
|
period_discounts=payload.period_discounts,
|
|
auto_assign_total_spent_kopeks=payload.auto_assign_total_spent_kopeks,
|
|
apply_discounts_to_addons=payload.apply_discounts_to_addons,
|
|
)
|
|
return _serialize(group, members_count=0)
|
|
|
|
|
|
@router.patch("/{group_id}", response_model=PromoGroupResponse)
|
|
async def update_promo_group_endpoint(
|
|
group_id: int,
|
|
payload: PromoGroupUpdateRequest,
|
|
_: Any = Depends(require_api_token),
|
|
db: AsyncSession = Depends(get_db_session),
|
|
) -> PromoGroupResponse:
|
|
group = await get_promo_group_by_id(db, group_id)
|
|
if not group:
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, "Promo group not found")
|
|
|
|
group = await update_promo_group(
|
|
db,
|
|
group,
|
|
name=payload.name,
|
|
server_discount_percent=payload.server_discount_percent,
|
|
traffic_discount_percent=payload.traffic_discount_percent,
|
|
device_discount_percent=payload.device_discount_percent,
|
|
period_discounts=payload.period_discounts,
|
|
auto_assign_total_spent_kopeks=payload.auto_assign_total_spent_kopeks,
|
|
apply_discounts_to_addons=payload.apply_discounts_to_addons,
|
|
)
|
|
members_count = await count_promo_group_members(db, group_id)
|
|
return _serialize(group, members_count=members_count)
|
|
|
|
|
|
@router.delete("/{group_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
async def delete_promo_group_endpoint(
|
|
group_id: int,
|
|
_: Any = Depends(require_api_token),
|
|
db: AsyncSession = Depends(get_db_session),
|
|
) -> None:
|
|
group = await get_promo_group_by_id(db, group_id)
|
|
if not group:
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, "Promo group not found")
|
|
|
|
success = await delete_promo_group(db, group)
|
|
if not success:
|
|
raise HTTPException(status.HTTP_400_BAD_REQUEST, "Cannot delete default promo group")
|
|
|
|
return None
|