About A telegram bot client for gozargah/marzban with multi-user and multi-server support (Free version)
from aiogram import Dispatcher

from app.logger import get_logger

logger = get_logger("handlers")

from . import admin, base, start, user


def include_routers(dp: Dispatcher) -> None:
    for handler in [start, admin, user, base]:
        logger.debug(f"Initializing Handler {handler.__name__!r}")
        if hasattr(handler, "init_handler"):
            handler.init_handler()
        dp.include_router(handler.router)
        logger.debug(f"Router '{handler.router.name}' included!")

app/handlers/__init__.py
govfvck/Marzbot-free
import importlib

from aiogram import Router

from app.logger import get_logger

router = Router(name="admin")
logger = get_logger("handlers/admin")

handlers = [
    "admin",
    "user",
    "server",
    "service",
    "setting",
]


def init_handler() -> None:
    for name in handlers:
        importlib.import_module(f".{name}", "app.handlers.admin")

app/handlers/admin/__init__.py
govfvck/Marzbot-free
import asyncio

from aiogram import F, exceptions
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, Message

from app.keyboards.admin.admin import AdminPanel, AdminPanelAction
from app.main import bot
from app.models.user import User
from app.utils.filters import SuperUserAccess

from . import logger, router


@router.message(Command("admin"), SuperUserAccess())
@router.callback_query(
    AdminPanel.Callback.filter(F.action == AdminPanelAction.panel), SuperUserAccess()
)
async def show_admin_panel(
    message: Message | CallbackQuery, user: User, state: FSMContext = None
):
    if (state is not None) and (await state.get_state() is not None):
        await state.clear()

    text = "admin panel:"
    if isinstance(message, CallbackQuery):
        return await message.message.edit_text(
            text,
            reply_markup=AdminPanel().as_markup(),
        )
    return await message.answer(
        text,
        reply_markup=AdminPanel().as_markup(),
    )


# send message
@router.message(Command("msg"), SuperUserAccess())
async def msg_command(message: Message, user: User):
    """send message to a user
    Args:
        user (int | str): user id or username of the user
        text (str): text to be sent to the user

    Example:
        /msg @test hello
    """
    user_id = message.text.split()[1]
    text = " ".join(message.text.split()[2:])

    if user_id.isnumeric():
        user_to_get = await User.filter(id=int(user_id)).first()
    else:
        user_to_get = await User.filter(username__iexact=user_id.lstrip("@")).first()

    if not user_to_get:
        return await message.answer(f"User {user_id} not found!")

    try:
        msg_text = f"""
🔔 شما یک پیام از طرف پشتیبانی دارید:
~~~~~~~~~~~~~~~~~~~~~~~~
{text}
‌‌
"""
        await bot.send_message(chat_id=user.id, text=msg_text)
        return await message.reply(
            f"message sent to <a href='tg://user?id={user_to_get.id}'>{user_to_get.id}</a>\n\n{msg_text}"
        )
    except Exception as exc:
        await message.reply(f"Error:\n{exc}")
        raise exc


# Broadcast messages
async def fwd_msg(message: Message, user: User):
    try:
        await message.forward(user.id)
    except exceptions.TelegramRetryAfter as err:
        await asyncio.sleep(err.retry_after)
        return await fwd_msg(message, user)
    except exceptions.TelegramAPIError:
        return False
    except Exception as err:
        logger.error(f"Unknown error in fwd_msg: {err}")
        return False
    return True


async def send_msg(message: Message, user: User):
    try:
        await bot(message.send_copy(user.id))
    except exceptions.TelegramRetryAfter as err:
        await asyncio.sleep(err.retry_after)
        return await send_msg(message, user)
    except exceptions.TelegramAPIError:
        return False
    except Exception as err:
        logger.error(f"Unknown error in send_msg: {err}")
        return False
    return True


async def broadcast(message: Message, sender: callable, type: str):
    if not message.reply_to_message:
        return await message.reply(f"برای {type} باید روی یک پیام ریپلای کنید!")

    success = 0
    fails = 0
    waiter = 0.1

    users = await User.filter(is_blocked=False).all()
    total = len(users)

    progres = await message.reply(
        f"{type} پیام به {total} کاربر...\n" f"زمان تقریبی: {int((waiter*total)/60)}"
    )

    for idx, user in enumerate(users):
        if await sender(message.reply_to_message, user):
            success += 1
        else:
            fails += 1
        if idx and (idx % 250) == 0:
            await progres.edit_text(
                f"{type} پیام به {total} کاربر...\n" f"پیشرفت: {int(idx/total*100)}%"
            )
        await asyncio.sleep(0.1)
    await progres.edit_text(f"{type} پیام به {total} کاربر...\n" f"پیشرفت: 100%")
    return await message.reply(f"پیام {type} شد!\nموفق: {success}\n ناموفق: {fails}")


@router.message(Command("forward"), SuperUserAccess())
async def forward_command(message: Message, user: User):
    """forwards a message to all users

    Example:
        /forward (reply)
    """
    asyncio.create_task(broadcast(message, fwd_msg, "فوروارد"))


@router.message(Command("broadcast"), SuperUserAccess())
async def broadcast_command(message: Message, user: User):
    """sends a message to all users

    Example:
        /broadcast (reply)
    """
    asyncio.create_task(broadcast(message, send_msg, "ارسال"))

app/handlers/admin/admin.py
govfvck/Marzbot-free
from aiogram import F
from aiogram.filters import Command, StateFilter
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, Message, ReplyKeyboardRemove

from app.keyboards.admin.admin import (
    AdminPanel,
    AdminPanelAction,
    CancelFormAdmin,
    YesOrNoFormAdmin,
)
from app.keyboards.admin.server import (
    ConfirmServerAction,
    EditServer,
    EditServerAction,
    ServerAct,
    ServerActAction,
    Servers,
    ServersAction,
)
from app.marzban import Marzban
from app.models.server import Server
from app.models.user import User
from app.utils.filters import SuperUserAccess
from marzban_client import AuthenticatedClient
from marzban_client.api.user import get_users_api_users_get

from . import router

cancel_form = CancelFormAdmin().as_markup(resize_keyboard=True, one_time_only=True)
yes_or_no_form = YesOrNoFormAdmin().as_markup(
    resize_keyboard=True, one_time_keyboard=True
)


class AddServerForm(StatesGroup):
    name = State()
    host = State()
    port = State()
    token = State()
    https = State()
    confirm = State()


class EditServerForm(StatesGroup):
    id = State()
    name = State()
    host = State()
    port = State()
    token = State()
    https = State()


@router.message(
    F.text.casefold() == "cancel", SuperUserAccess(), StateFilter(AddServerForm)
)
@router.message(Command("cancel"), SuperUserAccess(), StateFilter(AddServerForm))
@router.callback_query(
    AdminPanel.Callback.filter(F.action == AdminPanelAction.servers), SuperUserAccess()
)
async def show_servers(
    query: CallbackQuery | Message, user: User, state: FSMContext | None = None
):
    if (state is not None) and (await state.get_state() is not None):
        await state.clear()
        await query.answer(text="Canceled!", reply_markup=ReplyKeyboardRemove())
    count = await Server.all().count()
    if count:
        servers = Servers(servers=await Server.all()).as_markup()
        if isinstance(query, CallbackQuery):
            return await query.message.edit_text(
                f"List of servers ({count}):",
                reply_markup=servers,
            )
        return await query.answer(
            f"List of servers ({count}):",
            reply_markup=servers,
        )
    servers = Servers(servers=[]).as_markup()
    if isinstance(query, CallbackQuery):
        return await query.message.edit_text(f"No server added!", reply_markup=servers)
    return await query.answer(f"No server added!", reply_markup=servers)


# Add Servers
@router.callback_query(
    Servers.Callback.filter(F.action == ServersAction.add_server),
    SuperUserAccess(),
)
async def add_server(query: CallbackQuery, user: User, state: FSMContext):
    await state.set_state(AddServerForm.name)
    await query.message.answer(
        "Enter a name for the server:",
        reply_markup=cancel_form,
    )


@router.message(AddServerForm.name, SuperUserAccess())
async def get_server_name(message: Message, user: User, state: FSMContext):
    if await Server.filter(name=message.text).first():
        return message.answer(
            "a server with this name already exists! try again:",
            reply_markup=cancel_form,
        )
    await state.update_data(name=message.text)
    await state.set_state(AddServerForm.host)
    await message.answer(
        "Enter domain or ip for the api server:",
        reply_markup=cancel_form,
    )


@router.message(AddServerForm.host, SuperUserAccess())
async def get_server_host(message: Message, user: User, state: FSMContext):
    # TODO: validate address
    await state.update_data(host=message.text)
    await state.set_state(AddServerForm.port)
    await message.answer(
        "Enter port of the api server(0 for not using a port):",
        reply_markup=cancel_form,
    )


@router.message(AddServerForm.port, SuperUserAccess())
async def get_server_port(message: Message, user: User, state: FSMContext):
    if not message.text.isdigit():
        return await message.answer(
            "port number must be an integer! try again:",
            reply_markup=cancel_form,
        )
    await state.update_data(port=int(message.text))
    await state.set_state(AddServerForm.token)
    await message.answer(
        "enter the auth token for the api server", reply_markup=cancel_form
    )


@router.message(AddServerForm.token, SuperUserAccess())
async def get_server_token_handler(message: Message, user: User, state: FSMContext):
    await state.update_data(token=message.text)
    await state.set_state(AddServerForm.https)
    await message.answer("does the server supports https?", reply_markup=yes_or_no_form)


@router.message(AddServerForm.https, SuperUserAccess(), F.text.casefold() == "yes")
async def get_server_https_yes(message: Message, user: User, state: FSMContext):
    await state.update_data(https=True)
    await confirm_add_server(message, user, state)


@router.message(AddServerForm.https, SuperUserAccess(), F.text.casefold() == "no")
async def get_server_https_no(message: Message, user: User, state: FSMContext):
    await state.update_data(https=False)
    await confirm_add_server(message, user, state)


@router.message(AddServerForm.https, SuperUserAccess())
async def get_server_https_unknown(message: Message, user: User, state: FSMContext):
    await message.answer(
        text="Unknown answer! Please select one of the buttons:",
        reply_markup=yes_or_no_form,
    )


async def confirm_add_server(message: Message, user: User, state: FSMContext) -> None:
    data = await state.get_data()
    await state.set_state(AddServerForm.confirm)
    await message.answer(
        "is this data correct?\n"
        f"name: {data['name']}\n"
        f"host: {data['host']}\n"
        f"port: {data['port']}\n"
        f"token: <code>{data['token']}</code>\n"
        f"https: {data['https']}",
        reply_markup=yes_or_no_form,
    )


@router.message(AddServerForm.confirm, SuperUserAccess(), F.text.casefold() == "yes")
async def get_server_confirm_yes(message: Message, user: User, state: FSMContext):
    data = await state.get_data()
    server = Server(**data)
    client = AuthenticatedClient(base_url=server.url, token=server.token)
    try:  # test server
        await get_users_api_users_get.asyncio(client=client)
    except Exception as err:
        await message.answer(f"Aborting, could not connect to server! error: {err}")
        raise err
    await server.save()

    await message.reply(
        f"Server created:\nidentifier: {server.identifier}\nurl: {server.url}"
    )
    await Marzban.refresh_servers()
    await show_servers(message, user)


@router.message(AddServerForm.confirm, SuperUserAccess(), F.text.casefold() == "no")
async def get_server_confirm_no(message: Message, user: User, state: FSMContext):
    await state.set_state(AddServerForm.name)
    await message.answer(
        "Enter the data again!\nEnter a name for the server:",
        reply_markup=cancel_form,
    )


# Show Servers
@router.callback_query(
    Servers.Callback.filter(F.action == ServersAction.show), SuperUserAccess()
)
async def show_server(
    query: CallbackQuery,
    user: User,
    callback_data: Servers.Callback,
    state: FSMContext = None,
):
    if (state is not None) and (await state.get_state() is not None):
        await state.clear()
    server = await Server.filter(id=callback_data.server_id).first()
    if not server:
        await query.answer("Server not found!", show_alert=True)
        return await show_servers(
            query,
            user,
        )

    text = f"""
server id: <b>{server.id}</b>
server name: <b>{server.name}</b>
server url: <b>{server.url}</b>
is_enabled: <b>{server.is_enabled}</b>
server token: <code>{server.token}</code>
    """
    await query.message.edit_text(
        text, reply_markup=ServerAct(server).as_markup(), disable_web_page_preview=True
    )


# Remove Servers
@router.callback_query(
    ServerAct.Callback.filter(F.action == ServerActAction.rem),
    SuperUserAccess(),
)
async def remove_server(
    query: CallbackQuery, user: User, callback_data: ServerAct.Callback
):
    server = await Server.filter(id=callback_data.server_id).first()
    if not server:
        await query.answer("Server not found!", show_alert=True)
        return await show_servers(
            query,
            user,
        )

    if not callback_data.confirmed:
        await query.answer()
        text = """
Confirm removing server: 

❗️❗️<strong>be careful, this action is permenant and all the proxies will be deleted! you can also disable this server so no one could purchase from it.</strong>
"""
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmServerAction(
                server=server, action=ServerActAction.rem
            ).as_markup(),
        )
    await server.delete()
    await query.answer("Server Removed!", show_alert=True)
    return await show_servers(
        query,
        user,
    )


# Update Servers
@router.callback_query(
    ServerAct.Callback.filter(
        (F.action == ServerActAction.enable) | (F.action == ServerActAction.disable)
    ),
    SuperUserAccess(),
)
async def server_status_update(
    query: CallbackQuery, user: User, callback_data: ServerAct.Callback
):
    server = await Server.filter(id=callback_data.server_id).first()
    if not server:
        await query.answer("Server not found!", show_alert=True)
        return await show_servers(
            query,
            user,
        )

    if callback_data.action == ServerActAction.disable:
        if not server.is_enabled:
            await query.answer(f"Server is not enabled!", show_alert=True)
            return await show_server(
                query,
                user,
                callback_data=Servers.Callback(server_id=server.id, action="show"),
            )
        if not callback_data.confirmed:
            await query.answer()
            return await query.message.edit_text(
                "Confirm disabling server:",
                reply_markup=ConfirmServerAction(
                    server=server, action=ServerActAction.disable
                ).as_markup(),
            )
        server.is_enabled = False
        await server.save()
        await query.answer(f"Server disabled!", show_alert=True)
    elif callback_data.action == ServerActAction.enable:
        if server.is_enabled:
            await query.answer(f"Server is not disabled!", show_alert=True)
            return await show_server(
                query,
                user,
                callback_data=Servers.Callback(server_id=server.id, action="show"),
            )
        if not callback_data.confirmed:
            await query.answer()
            return await query.message.edit_text(
                "Confirm enabling server:",
                reply_markup=ConfirmServerAction(
                    server=server, action=ServerActAction.enable
                ).as_markup(),
            )
        server.is_enabled = True
        await server.save()
        await query.answer(f"Server enabled!", show_alert=True)
    return await show_server(
        query,
        user,
        callback_data=Servers.Callback(server_id=server.id, action="show"),
    )


@router.message(
    F.text.casefold() == "cancel", SuperUserAccess(), StateFilter(EditServerForm)
)
@router.callback_query(
    ServerAct.Callback.filter(F.action == ServerActAction.edit),
    SuperUserAccess(),
)
async def edit_server(
    query: CallbackQuery | Message,
    user: User,
    state: FSMContext,
    callback_data: ServerAct.Callback = None,
):
    if callback_data:
        server_id = callback_data.server_id
    else:
        server_id = (await state.get_data()).get("id")
    server = await Server.filter(id=server_id).first()
    if not server:
        if isinstance(query, CallbackQuery):
            await query.answer("Server not found!", show_alert=True)
            return await show_servers(
                query,
                user,
            )
        else:
            return await query.answer("Server not found!")

    await state.set_state(EditServerForm.id)
    data = await state.get_data()
    unsaved_changes = []
    for key, value in data.items():
        if server.__dict__.get(key) != value:
            unsaved_changes.append(key)
    await state.update_data(id=server.id)
    text = f"""
unsaved changes: {'-' if not unsaved_changes else ', '.join(unsaved_changes)}

server id: <b>{server.id}</b>
server name: <b>{data.get('name') or server.name}</b>
server host: <b>{data.get('host') or server.host}</b>
server port: <b>{data.get('port') or server.port}</b>
https: <b>{server.https if data.get('https') is None else data.get('https')}</b>
is_enabled: <b>{server.is_enabled}</b>

server token: <code>{data.get('token') or server.token}</code>
    """
    if isinstance(query, Message):
        return await query.answer(
            text, reply_markup=EditServer(server=server).as_markup()
        )
    return await query.message.edit_text(
        text, reply_markup=EditServer(server=server).as_markup()
    )


@router.callback_query(
    EditServer.Callback.filter(F.action == EditServerAction.save),
    SuperUserAccess(),
    StateFilter(EditServerForm),
)
async def edit_server_save(
    query: CallbackQuery,
    user: User,
    callback_data: EditServer.Callback,
    state: FSMContext,
):
    server = await Server.filter(id=callback_data.server_id).first()
    if not server:
        await query.answer("Server not found!", show_alert=True)
        return await show_servers(
            query,
            user,
        )
    data = await state.get_data()
    del data["id"]
    if not data:
        return await query.answer(f"Nothing changed! press cancel.", show_alert=True)

    await server.update_from_dict(data).save()
    await state.clear()
    await query.answer("Updated! fields: " + ", ".join(data), show_alert=True)
    await Marzban.refresh_servers()
    await show_server(
        query,
        user,
        callback_data=Servers.Callback(server_id=server.id, action=ServersAction.show),
        state=None,
    )


@router.callback_query(
    EditServer.Callback.filter(
        (F.action.in_(EditServerAction)) & ~(F.action == EditServerAction.save)
    ),
    SuperUserAccess(),
)
async def edit_server_action(
    query: CallbackQuery,
    user: User,
    callback_data: EditServer.Callback,
    state: FSMContext,
):
    server = await Server.filter(id=callback_data.server_id).first()
    if not server:
        await query.answer("Server not found!", show_alert=True)
        return await show_servers(
            query,
            user,
        )

    if callback_data.action == EditServerAction.name:
        await state.set_state(EditServerForm.name)
        await query.message.reply(
            "Enter new name for the server:",
            reply_markup=cancel_form,
        )
    elif callback_data.action == EditServerAction.host:
        await state.set_state(EditServerForm.host)
        await query.message.reply(
            "Enter new domain or ip for the api server:",
            reply_markup=cancel_form,
        )
    elif callback_data.action == EditServerAction.port:
        await state.set_state(EditServerForm.port)
        await query.message.reply(
            "Enter new port of the api server(0 for not using a port):",
            reply_markup=cancel_form,
        )
    elif callback_data.action == EditServerAction.token:
        await state.set_state(EditServerForm.token)
        await query.message.reply(
            "enter the new auth token for the api server", reply_markup=cancel_form
        )
    elif callback_data.action == EditServerAction.https:
        https = (await state.get_data()).get("https") or server.https
        if https:
            await state.update_data(https=False)
        else:
            await state.update_data(https=True)
        await edit_server(query, user, state)


@router.message(EditServerForm.name, SuperUserAccess())
async def edit_server_name(message: Message, user: User, state: FSMContext):
    server_id = (await state.get_data()).get("id")
    server = await Server.filter(id=int(server_id)).first()
    if not server:
        await state.clear()
        return await message.answer(
            "An error occured! open a new panel with '/admin' and try again."
        )
    if server.name == message.text:
        return await message.answer(
            "the new name can't be the same as the old name! Enter again or press cancel."
        )

    if await Server.filter(name=message.text).exists():
        return message.answer(
            "a server with this name already exists! try again:",
            reply_markup=cancel_form,
        )

    await state.update_data(name=message.text)
    await edit_server(message, user, state)


@router.message(EditServerForm.host, SuperUserAccess())
async def edit_server_host(message: Message, user: User, state: FSMContext):
    server_id = (await state.get_data()).get("id")
    server = await Server.filter(id=int(server_id)).first()
    if not server:
        await state.clear()
        return await message.answer(
            "An error occured! open a new panel with '/admin' and try again."
        )
    if server.host == message.text:
        return await message.answer(
            "the new host can't be the same as the old host! Enter again or press cancel."
        )
    await state.update_data(host=message.text)
    await edit_server(message, user, state)


@router.message(EditServerForm.port, SuperUserAccess())
async def edit_server_port(message: Message, user: User, state: FSMContext):
    server_id = (await state.get_data()).get("id")
    server = await Server.filter(id=int(server_id)).first()
    if not server:
        await state.clear()
        return await message.answer(
            "An error occured! open a new panel with '/admin' and try again."
        )
    if not message.text.isdigit():
        return await message.answer(
            "port number must be an integer! try again:",
            reply_markup=cancel_form,
        )
    if server.port == int(message.text):
        return await message.answer(
            "the new port can't be the same as the old port! Enter again or press cancel."
        )
    await state.update_data(port=int(message.text))
    await edit_server(message, user, state)


@router.message(EditServerForm.token, SuperUserAccess())
async def edit_server_token(message: Message, user: User, state: FSMContext):
    server_id = (await state.get_data()).get("id")
    server = await Server.filter(id=int(server_id)).first()
    if not server:
        await state.clear()
        return await message.answer(
            "An error occured! open a new panel with '/admin' and try again."
        )
    if server.token == message.text:
        return await message.answer(
            "the new token can't be the same as the old token! Enter again or press cancel."
        )
    await state.update_data(token=message.text)
    await edit_server(message, user, state)


# # Templates

# # Add Templates
# @router.callback_query(
#     Templates.Callback.filter(F.action == Templates.add),
#     IsSuperUser(),
# )
# async def add_template(query: CallbackQuery, user: User, state: FSMContext):
#     await state.set_state(AddTemplateForm.id)
#     await query.message.answer(
#         "Enter a name for the server:",
#         reply_markup=cancel_form,
#     )

# # Show Templates
# @router.callback_query(
#     ServerAct.Callback.filter(F.action == ServerActAction.templates),
#     IsSuperUser(),
# )
# async def show_templates(
#     query: CallbackQuery, user: User, callback_data: ServerAct.Callback
# ):
#     server = await Server.filter(id=callback_data.server_id).first()
#     if not server:
#         await query.answer("Server not found!", show_alert=True)
#         return await show_servers(
#             query,
#             user,
#         )

#     client = Marzban.get_server(server.id)
#     templates = await get_user_templates_api_user_template_get.asyncio(client=client)
#     if len(templates) < 1:
#         text = "No template Added!"
#         return await query.message.edit_text("No template added!", reply_markup=Templates(templates=[], server_id=server.id))
#     return await query.message.edit_text(f"Templates: ({len(templates)})", reply_markup=Templates(templates=templates, server_id=server.id))

app/handlers/admin/server.py
govfvck/Marzbot-free
import re

from aiogram import F
from aiogram.filters import Command, StateFilter
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, Message, ReplyKeyboardRemove

from app.keyboards.admin.admin import (
    AdminPanel,
    AdminPanelAction,
    CancelFormAdmin,
    YesOrNoFormAdmin,
)
from app.keyboards.admin.service import (
    ConfirmServiceAction,
    EditService,
    EditServiceAction,
    SelectInbounds,
    SelectServer,
    ServiceAct,
    ServiceActAction,
    Services,
    ServicesAction,
)
from app.marzban import Marzban
from app.models.server import Server
from app.models.service import Service
from app.models.user import User
from app.utils import helpers
from app.utils.filters import SuperUserAccess
from marzban_client.api.system import get_inbounds_api_inbounds_get

from . import router

cancel_form = CancelFormAdmin().as_markup(resize_keyboard=True, one_time_only=True)
yes_or_no_form = YesOrNoFormAdmin().as_markup(
    resize_keyboard=True, one_time_keyboard=True
)


class AddServiceForm(StatesGroup):
    name = State()
    data_limit = State()
    expire_duration = State()
    server_id = State()
    inbounds = State()
    price = State()
    confirm = State()


class EditServiceForm(StatesGroup):
    id = State()
    name = State()
    data_limit = State()
    expire_duration = State()
    inbounds = State()
    price = State()


@router.message(
    F.text.casefold() == "cancel", SuperUserAccess(), StateFilter(AddServiceForm)
)
@router.message(Command("cancel"), SuperUserAccess(), StateFilter(AddServiceForm))
@router.callback_query(
    AdminPanel.Callback.filter(F.action == AdminPanelAction.services), SuperUserAccess()
)
async def show_services(
    query: CallbackQuery | Message, user: User, state: FSMContext | None = None
):
    if (state is not None) and (await state.get_state() is not None):
        await state.clear()
        await query.answer(text="Canceled!", reply_markup=ReplyKeyboardRemove())
    count = await Service.all().count()
    if count:
        servers = Services(services=await Service.all()).as_markup()
        if isinstance(query, CallbackQuery):
            return await query.message.edit_text(
                f"List of services ({count}):",
                reply_markup=servers,
            )
        return await query.answer(
            f"List of services ({count}):",
            reply_markup=servers,
        )
    services = Services(services=[]).as_markup()
    if isinstance(query, CallbackQuery):
        return await query.message.edit_text(
            f"No service added!", reply_markup=services
        )
    return await query.answer(f"No service added!", reply_markup=services)


# Add Services
@router.callback_query(
    Services.Callback.filter(F.action == ServicesAction.add),
    SuperUserAccess(),
)
async def add_service(query: CallbackQuery, user: User, state: FSMContext):
    await state.set_state(AddServiceForm.name)
    await query.message.answer(
        "Enter a name for the service:",
        reply_markup=cancel_form,
    )


@router.message(AddServiceForm.name, SuperUserAccess())
async def get_service_name(message: Message, user: User, state: FSMContext):
    if await Service.filter(name=message.text).first():
        return message.answer(
            "a service with this name already exists! try again:",
            reply_markup=cancel_form,
        )
    await state.update_data(name=message.text)
    await state.set_state(AddServiceForm.data_limit)
    await message.answer(
        "Enter data_limit for the service(in GB, 0 for unlimited):",
        reply_markup=cancel_form,
    )


@router.message(AddServiceForm.data_limit, SuperUserAccess())
async def get_service_data_limit(message: Message, user: User, state: FSMContext):
    try:
        if float(message.text) < 0:
            return await message.answer(
                message.chat.id,
                "❌ Data limit must be greater or equal to 0.",
                reply_markup=cancel_form(),
            )
        data_limit = float(message.text) * 1024 * 1024 * 1024
    except ValueError:
        return await message.answer(
            "data_limit must be an integer or float! try again:",
            reply_markup=cancel_form,
        )
    await state.update_data(data_limit=data_limit)
    await state.set_state(AddServiceForm.expire_duration)
    await message.answer(
        "'⬆️ Enter Expire Duration You Can Use Regex Symbol: ^[0-9]{1,3}(D|M|Y|H) :\n⚠️ Send 0 for never expire.'",
        reply_markup=cancel_form,
    )


@router.message(AddServiceForm.expire_duration, SuperUserAccess())
async def get_service_expire_duration(message: Message, user: User, state: FSMContext):
    try:
        if message.text.isnumeric() and int(message.text) == 0:
            expire_duration = None
        if re.match(r"^[0-9]{1,3}(M|m|Y|y|D|d|H|h)$", message.text):
            expire_duration = 0
            number_pattern = r"^[0-9]{1,3}"
            number = int(re.findall(number_pattern, message.text)[0])
            symbol_pattern = r"(M|m|Y|y|D|d|H|h)$"
            symbol = re.findall(symbol_pattern, message.text)[0].upper()
            if symbol == "H":
                expire_duration = 3600 * number
            elif symbol == "D":
                expire_duration += 86400 * number
            elif symbol == "M":
                expire_duration += 2592000 * number
            elif symbol == "Y":
                expire_duration = 31104000 * number
        else:
            raise ValueError("Could not parse expire_duration")
    except ValueError:
        return await message.answer(
            "❌ Expire duration must be in 1m or 2m or 1d, Regex Symbol: ^[0-9]{1,3}(D|M|Y|H)",
            reply_markup=cancel_form,
        )
    await state.update_data(expire_duration=expire_duration)
    await state.set_state(AddServiceForm.price)
    await message.answer("Enter price for this service:", reply_markup=cancel_form)


@router.message(AddServiceForm.price, SuperUserAccess())
async def get_service_price(message: Message, user: User, state: FSMContext):
    try:
        await state.update_data(price=int(message.text))
        await state.set_state(AddServiceForm.server_id)
        servers = await Server.all()
        await message.answer(
            "Selecet a server for this service:",
            reply_markup=SelectServer(servers=servers).as_markup(),
        )
    except ValueError:
        return await message.answer("Price must be integer! enter again:")


@router.callback_query(
    AddServiceForm.server_id, SuperUserAccess(), SelectServer.Callback.filter()
)
async def get_service_server_id(
    query: CallbackQuery,
    user: User,
    state: FSMContext,
    callback_data: SelectServer.Callback,
):
    try:
        client = Marzban.get_server(callback_data.server_id)
    except KeyError:
        return await query.answer(
            text=f"Could not get server {callback_data.server_id!r} api client!"
        )
    inbounds: dict[str, list[str]] = {
        protocol: [inbound.tag for inbound in protocol_inbounds]
        for protocol, protocol_inbounds in (
            await get_inbounds_api_inbounds_get.asyncio(client=client)
        ).additional_properties.items()
    }
    await state.update_data(server_id=callback_data.server_id)
    data = await state.get_data()

    text = f"""
name: <b>{data.get('name')}</b>
data_limit: <b>{helpers.hr_size(data.get('data_limit')) if data.get('data_limit') else 'Unlimited'}</b>
expire_duration: <b>{helpers.hr_time(data.get('expire_duration')) if data.get('expire_duration') else 'Never'}</b>
price: <b>{data.get('price')}</b>
server_id: <b>{data.get('server_id')}</b>
    """
    await state.set_state(AddServiceForm.inbounds)
    await query.message.edit_text(
        text,
        reply_markup=SelectInbounds(
            inbounds=inbounds,
            selected_inbounds={},
            server_id=callback_data.server_id,
        ).as_markup(),
    )


@router.callback_query(
    EditServiceForm.inbounds,
    SuperUserAccess(),
    SelectInbounds.Callback.filter(F.for_edit == True),
)
@router.callback_query(
    AddServiceForm.inbounds,
    SuperUserAccess(),
    SelectInbounds.Callback.filter(F.for_edit == False),
)
async def select_service_inbounds(
    query: CallbackQuery,
    user: User,
    state: FSMContext,
    callback_data: SelectInbounds.Callback,
):
    data = await state.get_data()
    selected_inbounds: dict[str, list[str]] = data.get("inbounds", dict())

    try:
        client = Marzban.get_server(callback_data.server_id)
    except KeyError:
        return await query.answer(
            text=f"Could not get server {callback_data.server_id!r} api client!"
        )
    inbounds: dict[str, list[str]] = {
        protocol: [inbound.tag for inbound in protocol_inbounds]
        for protocol, protocol_inbounds in (
            await get_inbounds_api_inbounds_get.asyncio(client=client)
        ).additional_properties.items()
    }

    if callback_data.inbound is None:
        if callback_data.protocol not in selected_inbounds:
            selected_inbounds.update(
                {callback_data.protocol: inbounds[callback_data.protocol].copy()}
            )
        else:
            del selected_inbounds[callback_data.protocol]
    else:
        if callback_data.protocol not in selected_inbounds:
            selected_inbounds.update(
                {callback_data.protocol: inbounds[callback_data.protocol].copy()}
            )
        else:
            if callback_data.inbound not in selected_inbounds[callback_data.protocol]:
                selected_inbounds[callback_data.protocol].append(callback_data.inbound)
            else:
                selected_inbounds[callback_data.protocol].remove(callback_data.inbound)
                if not selected_inbounds[
                    callback_data.protocol
                ]:  # delete protocol with no inbound
                    del selected_inbounds[callback_data.protocol]
    await state.update_data(inbounds=selected_inbounds)

    if not callback_data.for_edit:
        text = f"""
name: <b>{data.get('name')}</b>
data_limit: <b>{helpers.hr_size(data.get('data_limit')) if data.get('data_limit') else 'Unlimited'}</b>
expire_duration: <b>{helpers.hr_time(data.get('expire_duration')) if data.get('expire_duration') else 'Never'}</b>
price: <b>{data.get('price')}</b>
server_id: <b>{data.get('server_id')}</b>

inbounds: <code>{selected_inbounds}</code>
        """
        return await query.message.edit_text(
            text,
            reply_markup=SelectInbounds(
                inbounds=inbounds,
                selected_inbounds=selected_inbounds,
                server_id=callback_data.server_id,
            ).as_markup(),
        )
    return await query.message.edit_text(
        f"select inbounds and press save:\n\ninbounds: <code>{selected_inbounds}</code>",
        reply_markup=SelectInbounds(
            inbounds=inbounds,
            selected_inbounds=selected_inbounds,
            server_id=callback_data.server_id,
            for_edit=True,
            service_id=callback_data.service_id,
        ).as_markup(),
    )


@router.callback_query(
    AddServiceForm.inbounds,
    SuperUserAccess(),
    Services.Callback.filter(F.action == ServicesAction.save_new),
)
async def save_new_service(
    query: CallbackQuery,
    user: User,
    state: FSMContext,
    callback_data: SelectInbounds.Callback,
):
    data = await state.get_data()
    selected_inbounds: dict[str, list[str]] = data.get("inbounds")

    if not selected_inbounds:
        return await query.answer("No inbound protocol selected!", show_alert=True)

    if not any(
        [False if not inbounds else True for inbounds in selected_inbounds.values()]
    ):
        return await query.answer("No inbound selected!", show_alert=True)

    await state.clear()
    service = await Service.create(
        name=data.get("name"),
        data_limit=data.get("data_limit"),
        expire_duration=data.get("expire_duration"),
        price=data.get("price"),
        inbounds=selected_inbounds,
        server_id=data.get("server_id"),
    )
    await show_service(
        query,
        user,
        callback_data=Services.Callback(
            service_id=service.id, action=ServicesAction.show
        ),
        state=state,
    )


# Show Services
@router.callback_query(
    SuperUserAccess(),
    Services.Callback.filter(F.action == ServicesAction.show),
)
async def show_service(
    query: CallbackQuery,
    user: User,
    callback_data: Services.Callback,
    state: FSMContext | None = None,
):
    if (state is not None) and (await state.get_state() is not None):
        await state.clear()
    service = (
        await Service.filter(id=callback_data.service_id)
        .prefetch_related("server")
        .first()
    )
    if not service:
        await query.answer("Service not found!", show_alert=True)
        return await show_services(
            query,
            user,
        )

    text = f"""
service id: <b>{service.id}</b>
service name: <b>{service.name}</b>
service data_limit: <b>{helpers.hr_size(service.data_limit)}</b>
service expire_duration: <code>{helpers.hr_time(service.expire_duration)}</code>
service price: <b>{service.price}</b>
server: <b>{service.server.name}</b> ({service.server.id})
inbounds: {service.inbounds}
    """
    await query.message.edit_text(
        text, reply_markup=ServiceAct(service=service).as_markup()
    )


# Remove Services
@router.callback_query(
    ServiceAct.Callback.filter(F.action == ServiceActAction.rem),
    SuperUserAccess(),
)
async def remove_service(
    query: CallbackQuery, user: User, callback_data: ServiceAct.Callback
):
    service = await Service.filter(id=callback_data.service_id).first()
    if not service:
        await query.answer("Service not found!", show_alert=True)
        return await show_services(
            query,
            user,
        )

    if not callback_data.confirmed:
        await query.answer()
        text = """
Confirm removing service: 

❗️❗️<strong>be careful, this action is permenant and field of server_id for all the proxies will be set to null! you can also disable this service so no one could purchase from it.</strong>
"""
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmServiceAction(
                service=service, action=ServiceActAction.rem
            ).as_markup(),
        )
    await service.delete()
    await query.answer("Service Removed!", show_alert=True)
    return await show_services(
        query,
        user,
    )


# update Services
@router.callback_query(
    ServiceAct.Callback.filter(F.action == ServiceActAction.cycle_flow),
    SuperUserAccess(),
)
async def service_cycle_flow(
    query: CallbackQuery, user: User, callback_data: ServiceAct.Callback
):
    service = await Service.filter(id=callback_data.service_id).first()
    if not service:
        await query.answer("Service not found!", show_alert=True)
        return await show_services(
            query,
            user,
        )

    try:
        f = iter(Service.ServiceProxyFlow)
        while next(f) != service.flow:
            pass
        service.flow = next(f)
    except StopIteration:
        service.flow = next(iter(Service.ServiceProxyFlow))  # get first enum value

    await service.save()
    await query.answer(
        f"flow set to {service.flow}. it only affects protocols that support 'flow'!",
        show_alert=True,
    )
    await show_service(
        query,
        user,
        callback_data=Services.Callback(
            service_id=service.id, action=ServicesAction.show
        ),
    )


@router.callback_query(
    ServiceAct.Callback.filter(F.action == ServiceActAction.flip_purchase),
    SuperUserAccess(),
)
async def edit_service_purchase(
    query: CallbackQuery, user: User, callback_data: ServiceAct.Callback
):
    service = await Service.filter(id=callback_data.service_id).first()
    if not service:
        await query.answer("Service not found!", show_alert=True)
        return await show_services(
            query,
            user,
        )

    if not callback_data.confirmed:
        await query.answer()
        if service.purchaseable:
            text = """
Confirm disable purchasing: 

❗️❗️<strong>be careful, if you do this no one can purchase this service anymore.</strong>
            """
        else:
            text = """
Confirm enabling purchasing: 

❗️❗️<strong>be careful, if you do this users can purchase this service.</strong>
            """
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmServiceAction(
                service=service,
                action=ServiceActAction.flip_purchase,
            ).as_markup(),
        )
    if service.purchaseable:
        service.purchaseable = False
        text = "purchase disabled!"
    else:
        service.purchaseable = True
        text = "purchase enabled!"
    await service.save()
    await query.answer(text, show_alert=True)
    await show_service(
        query,
        user,
        callback_data=Services.Callback(
            service_id=service.id, action=ServicesAction.show
        ),
    )


@router.callback_query(
    ServiceAct.Callback.filter(F.action == ServiceActAction.flip_renew),
    SuperUserAccess(),
)
async def edit_service_renew(
    query: CallbackQuery, user: User, callback_data: ServiceAct.Callback
):
    service = await Service.filter(id=callback_data.service_id).first()
    if not service:
        await query.answer("Service not found!", show_alert=True)
        return await show_services(
            query,
            user,
        )

    if not callback_data.confirmed:
        await query.answer()
        if service.renewable:
            text = """
Confirm disable purchasing: 

❗️❗️<strong>be careful, if you do this no one can renew this service anymore.</strong>
            """
        else:
            text = """
Confirm enabling purchasing: 

❗️❗️<strong>be careful, if you do this users can renew this service.</strong>
            """
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmServiceAction(
                service=service,
                action=ServiceActAction.flip_renew,
            ).as_markup(),
        )
    if service.renewable:
        service.renewable = False
        text = "renew disabled!"
    else:
        service.renewable = True
        text = "renew enabled!"
    await service.save()
    await query.answer(text, show_alert=True)
    await show_service(
        query,
        user,
        callback_data=Services.Callback(
            service_id=service.id, action=ServicesAction.show
        ),
    )


@router.callback_query(
    ServiceAct.Callback.filter(F.action == ServiceActAction.flip_one_time_only),
    SuperUserAccess(),
)
async def edit_service_one_time_only(
    query: CallbackQuery, user: User, callback_data: ServiceAct.Callback
):
    service = await Service.filter(id=callback_data.service_id).first()
    if not service:
        await query.answer("Service not found!", show_alert=True)
        return await show_services(
            query,
            user,
        )

    if not callback_data.confirmed:
        await query.answer()
        if service.one_time_only:
            text = """
Confirm disabling one_time_only: 

❗️❗️<strong>be careful, if you do this users can activate this service more than once.</strong>
            """
        else:
            text = """
Confirm enabling one_time_only: 

❗️❗️<strong>be careful, if you do this users can activate this service only once.</strong>
            """
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmServiceAction(
                service=service,
                action=ServiceActAction.flip_one_time_only,
            ).as_markup(),
        )
    if service.one_time_only:
        service.one_time_only = False
        text = "one time only disabled!"
    else:
        service.one_time_only = True
        text = "one time only enabled!"
    await service.save()
    await query.answer(text, show_alert=True)
    await show_service(
        query,
        user,
        callback_data=Services.Callback(
            service_id=service.id, action=ServicesAction.show
        ),
    )


@router.callback_query(
    ServiceAct.Callback.filter(F.action == ServiceActAction.flip_is_test_service),
    SuperUserAccess(),
)
async def edit_service_is_test_service(
    query: CallbackQuery, user: User, callback_data: ServiceAct.Callback
):
    service = await Service.filter(id=callback_data.service_id).first()
    if not service:
        await query.answer("Service not found!", show_alert=True)
        return await show_services(
            query,
            user,
        )

    if not callback_data.confirmed:
        await query.answer()
        if service.is_test_service:
            text = """
Confirm disabling is_test_service: 

❗️❗️<strong>be careful, if you do this users can activate this service more than once.</strong>
            """
        else:
            text = """
Confirm enabling is_test_service: 

❗️❗️<strong>be careful, if you do this users can activate this service only once.</strong>
            """
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmServiceAction(
                service=service,
                action=ServiceActAction.flip_is_test_service,
            ).as_markup(),
        )
    if service.is_test_service:
        service.is_test_service = False
        text = "is test service disabled!"
    else:
        service.is_test_service = True
        text = "is test service enabled!"
    await service.save()
    await query.answer(text, show_alert=True)
    await show_service(
        query,
        user,
        callback_data=Services.Callback(
            service_id=service.id, action=ServicesAction.show
        ),
    )


@router.message(
    F.text.casefold() == "cancel", SuperUserAccess(), StateFilter(EditServiceForm)
)
@router.callback_query(
    ServiceAct.Callback.filter(F.action == ServiceActAction.edit),
    SuperUserAccess(),
)
async def edit_service(
    query: CallbackQuery | Message,
    user: User,
    state: FSMContext,
    callback_data: ServiceAct.Callback = None,
):
    if callback_data:
        service_id = callback_data.service_id
    else:
        service_id = (await state.get_data()).get("id")
    service = await Service.filter(id=service_id).first()
    if not service:
        if isinstance(query, CallbackQuery):
            await query.answer("Service not found!", show_alert=True)
            return await show_services(
                query,
                user,
            )
        else:
            return await query.answer("Service not found!")

    await state.set_state(EditServiceForm.id)
    data = await state.get_data()
    unsaved_changes = []
    for key, value in data.items():
        if service.__dict__.get(key) != value:
            unsaved_changes.append(key)
    await state.update_data(id=service.id)
    text = f"""
unsaved changes: {'-' if not unsaved_changes else ', '.join(unsaved_changes)}

service id: <b>{service.id}</b>
service name: <b>{data.get('name') or service.name}</b>
service data_limit: <b>{helpers.hr_size(data.get('data_limit') or service.data_limit)}</b>
service expire_duration: <code>{helpers.hr_time(data.get('expire_duration') or service.expire_duration)}</code>
service price: <b>{data.get('price') or service.price}</b>
inbounds: <code>{service.inbounds if data.get('inbounds') is None else data.get('inbounds')}</code>
    """
    if isinstance(query, Message):
        return await query.answer(
            text, reply_markup=EditService(service=service).as_markup()
        )
    return await query.message.edit_text(
        text, reply_markup=EditService(service=service).as_markup()
    )


@router.callback_query(
    EditService.Callback.filter(F.action == EditServiceAction.save),
    SuperUserAccess(),
    StateFilter(EditServiceForm),
)
async def edit_service_save(
    query: CallbackQuery,
    user: User,
    callback_data: EditService.Callback,
    state: FSMContext,
):
    service = await Service.filter(id=callback_data.service_id).first()
    if not service:
        await query.answer("service not found!", show_alert=True)
        return await show_services(
            query,
            user,
        )
    data = await state.get_data()
    del data["id"]
    if not data:
        return await query.answer(f"Nothing changed! press cancel.", show_alert=True)

    selected_inbounds: dict[str, list[str]] = data.get("inbounds") or service.inbounds
    if not selected_inbounds:
        return await query.answer("No inbound protocol selected!", show_alert=True)

    if not any(
        [False if not inbounds else True for inbounds in selected_inbounds.values()]
    ):
        return await query.answer("No inbound selected!", show_alert=True)

    await service.update_from_dict(data).save()
    await state.clear()
    await query.answer("Updated! fields: " + ", ".join(data), show_alert=True)
    await show_service(
        query,
        user,
        callback_data=Services.Callback(
            service_id=service.id, action=ServicesAction.show
        ),
        state=None,
    )


@router.callback_query(
    EditService.Callback.filter(
        (F.action.in_(EditServiceAction)) & ~(F.action == EditServiceAction.save)
    ),
    SuperUserAccess(),
)
async def edit_server_action(
    query: CallbackQuery,
    user: User,
    callback_data: EditService.Callback,
    state: FSMContext,
):
    service = await Service.filter(id=callback_data.service_id).first()
    if not service:
        await query.answer("service not found!", show_alert=True)
        return await show_services(
            query,
            user,
        )

    if callback_data.action == EditServiceAction.name:
        await state.set_state(EditServiceForm.name)
        await query.message.reply(
            "Enter new name for the Service:",
            reply_markup=cancel_form,
        )
    elif callback_data.action == EditServiceAction.data_limit:
        await state.set_state(EditServiceForm.data_limit)
        await query.message.reply(
            "Enter new data_limit for the service(in GB, 0 for unlimited):",
            reply_markup=cancel_form,
        )
    elif callback_data.action == EditServiceAction.expire_duration:
        await state.set_state(EditServiceForm.expire_duration)
        await query.message.reply(
            "'⬆️ Enter new Expire Duration You Can Use Regex Symbol: ^[0-9]{1,3}(D|M|Y) :\n⚠️ Send 0 for never expire.'",
            reply_markup=cancel_form,
        )
    elif callback_data.action == EditServiceAction.price:
        await state.set_state(EditServiceForm.price)
        await query.message.reply(
            "Enter new price for this service:", reply_markup=cancel_form
        )
    elif callback_data.action == EditServiceAction.inbounds:
        client = Marzban.get_server(service.server_id)
        inbounds: dict[str, list[str]] = {
            protocol: [inbound.tag for inbound in protocol_inbounds]
            for protocol, protocol_inbounds in (
                await get_inbounds_api_inbounds_get.asyncio(client=client)
            ).additional_properties.items()
        }

        await state.set_state(EditServiceForm.inbounds)
        await query.message.edit_text(
            "select inbounds and press save:",
            reply_markup=SelectInbounds(
                inbounds=inbounds,
                selected_inbounds=service.inbounds,
                server_id=service.server_id,
                for_edit=True,
                service_id=service.id,
            ).as_markup(),
        )


@router.message(EditServiceForm.name, SuperUserAccess())
async def get_service_name(message: Message, user: User, state: FSMContext):
    service_id = (await state.get_data()).get("id")
    service = await Service.filter(id=int(service_id)).first()
    if not service:
        await state.clear()
        return await message.answer(
            "An error occured! open a new panel with '/admin' and try again."
        )
    if service.name == message.text:
        return await message.answer(
            "the new name can't be the same as the old name! Enter again or press cancel."
        )

    if await Service.filter(name=message.text).exists():
        return message.answer(
            "a service with this name already exists! try again:",
            reply_markup=cancel_form,
        )

    await state.update_data(name=message.text)
    await edit_service(message, user, state)


@router.message(EditServiceForm.data_limit, SuperUserAccess())
async def get_service_data_limit(message: Message, user: User, state: FSMContext):
    service_id = (await state.get_data()).get("id")
    service = await Service.filter(id=int(service_id)).first()
    if not service:
        await state.clear()
        return await message.answer(
            "An error occured! open a new panel with '/admin' and try again."
        )
    try:
        if float(message.text) < 0:
            return await message.answer(
                message.chat.id,
                "❌ Data limit must be greater or equal to 0.",
                reply_markup=cancel_form(),
            )
        data_limit = float(message.text) * 1024 * 1024 * 1024
    except ValueError:
        return await message.answer(
            "data_limit must be an integer or float! try again:",
            reply_markup=cancel_form,
        )
    if service.data_limit == data_limit:
        return await message.answer(
            "the new data_limit can't be the same as the old data_limit! Enter again or press cancel."
        )
    await state.update_data(data_limit=data_limit)
    await edit_service(message, user, state)


@router.message(EditServiceForm.expire_duration, SuperUserAccess())
async def get_service_expire_duration(message: Message, user: User, state: FSMContext):
    service_id = (await state.get_data()).get("id")
    service = await Service.filter(id=int(service_id)).first()
    if not service:
        await state.clear()
        return await message.answer(
            "An error occured! open a new panel with '/admin' and try again."
        )
    try:
        if message.text.isnumeric() and int(message.text) == 0:
            expire_duration = None
        if re.match(r"^[0-9]{1,3}(M|m|Y|y|D|d|H|h)$", message.text):
            expire_duration = 0
            number_pattern = r"^[0-9]{1,3}"
            number = int(re.findall(number_pattern, message.text)[0])
            symbol_pattern = r"(M|m|Y|y|D|d|H|h)$"
            symbol = re.findall(symbol_pattern, message.text)[0].upper()
            if symbol == "H":
                expire_duration = 3600 * number
            elif symbol == "D":
                expire_duration += 86400 * number
            elif symbol == "M":
                expire_duration += 2592000 * number
            elif symbol == "Y":
                expire_duration = 31104000 * number
        else:
            raise ValueError("Could not parse expire_duration")
    except ValueError:
        return await message.answer(
            "❌ Expire duration must be in 1m or 2m or 1d, Regex Symbol: ^[0-9]{1,3}(D|M|Y|H)",
            reply_markup=cancel_form,
        )
    if service.expire_duration == expire_duration:
        return await message.answer(
            "the new expire_duration can't be the same as the old expire_duration! Enter again or press cancel."
        )
    await state.update_data(expire_duration=expire_duration)
    await edit_service(message, user, state)


@router.message(EditServiceForm.price, SuperUserAccess())
async def get_service_price(message: Message, user: User, state: FSMContext):
    service_id = (await state.get_data()).get("id")
    service = await Service.filter(id=int(service_id)).first()
    if not service:
        await state.clear()
        return await message.answer(
            "An error occured! open a new panel with '/admin' and try again."
        )
    try:
        price = int(message.text)
    except ValueError:
        return await message.answer("Price must be integer! enter again:")

    if service.price == price:
        return await message.answer(
            "the new price can't be the same as the old price! Enter again or press cancel."
        )
    await state.update_data(price=price)
    await edit_service(message, user, state)

app/handlers/admin/service.py
govfvck/Marzbot-free
from aiogram import F
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, Message, ReplyKeyboardRemove

from app.keyboards.admin.admin import AdminPanel, AdminPanelAction, CancelFormAdmin
from app.keyboards.admin.setting import (
    ConfirmSettings,
    SettingsActions,
    SettingsKeyboard,
)
from app.models.user import User
from app.utils.filters import SuperUserAccess
from app.utils.settings import Settings

from . import router

cancel_form = CancelFormAdmin().as_markup(resize_keyboard=True, one_time_only=True)


# @router.message(F.text.casefold() == "cancel", IsSuperUser(), StateFilter(AddCardForm))
# @router.message(Command("cancel"), IsSuperUser(), StateFilter(AddCardForm))
@router.callback_query(
    AdminPanel.Callback.filter(F.action == AdminPanelAction.settings), SuperUserAccess()
)
async def show_settings(
    query: CallbackQuery | Message, user: User, state: FSMContext | None = None
):
    if (state is not None) and (await state.get_state() is not None):
        await state.clear()
        await query.answer(text="Canceled!", reply_markup=ReplyKeyboardRemove())

    reply_markup = SettingsKeyboard(settings=await Settings.settings()).as_markup()
    if isinstance(query, CallbackQuery):
        return await query.message.edit_text("Settings:", reply_markup=reply_markup)
    return await query.answer("Settings:", reply_markup=reply_markup)


@router.callback_query(
    SettingsKeyboard.Callback.filter(F.action == SettingsActions.flip_access_only),
    SuperUserAccess(),
)
async def edit_settings(
    query: CallbackQuery, user: User, callback_data: SettingsKeyboard.Callback
):
    status = await Settings.bot_access_only()
    if not callback_data.confirmed:
        await query.answer()
        if not status:
            text = """
Confirm activating access only mode: 

❗️❗️<strong>be careful, if you do this only verified new users can use the bot.</strong>
            """
        else:
            text = """
Confirm disabling access only mode: 

❗️❗️<strong>be careful, every new user can use the bot.</strong>
            """
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmSettings(
                action=SettingsActions.flip_access_only,
            ).as_markup(),
        )
    if status:
        await Settings.set_bot_access_only(False)
        text = "access only disabled!"
    else:
        await Settings.set_bot_access_only(True)
        text = "access only enabled!"
    await query.answer(text, show_alert=True)
    await show_settings(
        query,
        user,
    )


@router.callback_query(
    SettingsKeyboard.Callback.filter(F.action == SettingsActions.flip_referral_system),
    SuperUserAccess(),
)
async def edit_settings(
    query: CallbackQuery, user: User, callback_data: SettingsKeyboard.Callback
):
    status = await Settings.bot_referral_system()
    if not callback_data.confirmed:
        await query.answer()
        if not status:
            text = """
Confirm activating referral system: 

❗️❗️<strong>be careful, if you do this users referral section will be disabled in bot.</strong>
            """
        else:
            text = """
Confirm disabling referral system: 

❗️❗️<strong>be careful, if you do this referral section will be enabled in bot.</strong>
            """
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmSettings(
                action=SettingsActions.flip_referral_system,
            ).as_markup(),
        )
    if status:
        await Settings.set_bot_referral_system(False)
        text = "referral system disabled!"
    else:
        await Settings.set_bot_referral_system(True)
        text = "referral system enabled!"
    await query.answer(text, show_alert=True)
    await show_settings(
        query,
        user,
    )


# payment methods statuses
@router.callback_query(
    SettingsKeyboard.Callback.filter(F.action == SettingsActions.flip_payment_crypto),
    SuperUserAccess(),
)
async def edit_settings(
    query: CallbackQuery, user: User, callback_data: SettingsKeyboard.Callback
):
    status = await Settings.payment_crypto()
    if not callback_data.confirmed:
        await query.answer()
        if not status:
            text = """
Confirm activating crypto payment: 

❗️❗️<strong>be careful, if you do this crypto payment button will be hidden.</strong>
            """
        else:
            text = """
Confirm disabling crypto payment: 

❗️❗️<strong>be careful, if you do this crypto payment button will be visible.</strong>
            """
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmSettings(
                action=SettingsActions.flip_payment_crypto,
            ).as_markup(),
        )
    if status:
        await Settings.set_payment_crypto(False)
        text = "crypto payment disabled!"
    else:
        await Settings.set_payment_crypto(True)
        text = "crypto payment enabled!"
    await query.answer(text, show_alert=True)
    await show_settings(
        query,
        user,
    )


@router.callback_query(
    SettingsKeyboard.Callback.filter(
        F.action == SettingsActions.flip_payment_card_to_card
    ),
    SuperUserAccess(),
)
async def edit_settings(
    query: CallbackQuery, user: User, callback_data: SettingsKeyboard.Callback
):
    status = await Settings.payment_card_to_card()
    if not callback_data.confirmed:
        await query.answer()
        if not status:
            text = """
Confirm activating card_to_card payment: 

❗️❗️<strong>be careful, if you do this card to card payment button will be hidden.</strong>
            """
        else:
            text = """
Confirm disabling card to card payment: 

❗️❗️<strong>be careful, if you do this card to card payment button will be visible.</strong>
            """
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmSettings(
                action=SettingsActions.flip_payment_card_to_card,
            ).as_markup(),
        )
    if status:
        await Settings.set_payment_card_to_card(False)
        text = "card to card payment disabled!"
    else:
        await Settings.set_payment_card_to_card(True)
        text = "card to card payment enabled!"
    await query.answer(text, show_alert=True)
    await show_settings(
        query,
        user,
    )


@router.callback_query(
    SettingsKeyboard.Callback.filter(
        F.action == SettingsActions.flip_payment_rial_gateway
    ),
    SuperUserAccess(),
)
async def edit_settings(
    query: CallbackQuery, user: User, callback_data: SettingsKeyboard.Callback
):
    status = await Settings.payment_rial_gateway()
    if not callback_data.confirmed:
        await query.answer()
        if not status:
            text = """
Confirm activating rial gateway payment: 

❗️❗️<strong>be careful, if you do this rial gateway payment button will be hidden.</strong>
            """
        else:
            text = """
Confirm disabling rial gateway payment: 

❗️❗️<strong>be careful, if you do this rial gateway payment button will be visible.</strong>
            """
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmSettings(
                action=SettingsActions.flip_payment_rial_gateway,
            ).as_markup(),
        )
    if status:
        await Settings.set_payment_rial_gateway(False)
        text = "rial gateway payment disabled!"
    else:
        await Settings.set_payment_rial_gateway(True)
        text = "rial gateway payment enabled!"
    await query.answer(text, show_alert=True)
    await show_settings(
        query,
        user,
    )


@router.callback_query(
    SettingsKeyboard.Callback.filter(
        F.action == SettingsActions.flip_payment_perfect_money
    ),
    SuperUserAccess(),
)
async def edit_settings(
    query: CallbackQuery, user: User, callback_data: SettingsKeyboard.Callback
):
    status = await Settings.payment_perfect_money()
    if not callback_data.confirmed:
        await query.answer()
        if not status:
            text = """
Confirm activating perfect money payment: 

❗️❗️<strong>be careful, if you do this perfect money payment button will be hidden.</strong>
            """
        else:
            text = """
Confirm disabling perfect money payment: 

❗️❗️<strong>be careful, if you do this perfect money payment button will be visible.</strong>
            """
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmSettings(
                action=SettingsActions.flip_payment_perfect_money,
            ).as_markup(),
        )
    if status:
        await Settings.set_payment_perfect_money(False)
        text = "perfect money payment disabled!"
    else:
        await Settings.set_payment_perfect_money(True)
        text = "perfect money payment enabled!"
    await query.answer(text, show_alert=True)
    await show_settings(
        query,
        user,
    )

app/handlers/admin/setting.py
govfvck/Marzbot-free
import inspect
import sys

from aiogram import F
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, Message
from tortoise.transactions import in_transaction

import config
from app.keyboards.admin.admin import AdminPanel, AdminPanelAction
from app.keyboards.admin.user import ManageUser, ManageUserAction, Users
from app.keyboards.base import CancelUserForm
from app.main import bot
from app.models.proxy import Proxy
from app.models.user import ByAdminPayment, Invoice, Transaction, User
from app.utils.filters import SuperUserAccess
from app.utils.settings import Settings

from . import router


class ManageUserForm(StatesGroup):
    user_id = State()
    amount = State()
    discount_percent = State()
    daily_test_services = State()
    proxy_prefix = State()


@router.callback_query(
    AdminPanel.Callback.filter(F.action == AdminPanelAction.users), SuperUserAccess()
)
async def show_users(
    query: CallbackQuery | Message, user: User, state: FSMContext | None = None
):
    text = f"""
User info: <code>/info [user_id]</code>
User Charge: <code>/charge [user_id] [amount]</code>
User Decharge: <code>/decharge [user_id] [amount]</code>
User Block: <code>/block [user_id]</code>
User Unblock: <code>/unblock [user_id]</code>

user commands: /usercmd
"""
    return await query.message.edit_text(text, reply_markup=Users().as_markup())


# get user info
@router.message(Command("info"), SuperUserAccess())
async def get_user_info_command(message: Message, user: User):
    """Get info of a user

    Args:
        user (int | str): user id or username of the user

    Example:
        <code>/info @username</code>
        <code>/info 123456789</code>
    """
    try:
        _, user_id = message.text.split()
    except ValueError:
        return await message.answer(
            "Could not parse the command! format: /info [user_id|username]"
        )
    if user_id.isnumeric():
        user_to_get = (
            await User.filter(id=int(user_id)).prefetch_related("setting").first()
        )
    else:
        user_to_get = (
            await User.filter(username__iexact=user_id.lstrip("@"))
            .prefetch_related("setting")
            .first()
        )

    if not user_to_get:
        return await message.answer(f"User {user_id} not found!")

    proxy_count = await Proxy.filter(user_id=user_to_get.id).count()
    balance = await user_to_get.get_balance()
    credit = await user_to_get.get_available_credit(balance=balance)

    text = f"""
id: <code>{user_to_get.id}</code>
username: <b>@{user_to_get.username}</b>
name: <b>{user_to_get.name}</b>
balance: <b>{balance}</b>
available credit: <b>{credit}</b>
is blocked: <b>{user_to_get.is_blocked}</b>
role: <b>{user_to_get.role.name}</b>
proxy counts: <b>{proxy_count}</b>
post paid / max credit: {'Yes' if user_to_get.is_postpaid else 'No'} / {user_to_get.max_post_paid_credit if user_to_get.is_postpaid else 0:,}

total spent: <b>{user_to_get.total_spent:,}</b>

referrer: <code>{user_to_get.referrer_id if user_to_get.referrer_id else '-'}</code>
referred count: <b>{await user_to_get.referred.all().count()}</b>

commands:
    <code>/block {user_to_get.id}</code> <b>Block user</b>
    <code>/unblock {user_to_get.id}</code> <b>Unblock User</b>
    <code>/charge {user_to_get.id}</code> <i>[amount]</i> <b>Create Transaction</b>
    <code>/decharge {user_to_get.id}</code> <i>[amount]</i> <b>Create Invoice</b>
"""
    await message.answer(text, reply_markup=ManageUser(user=user_to_get).as_markup())


@router.message(Command("role"), SuperUserAccess())
async def user_role_command(message: Message, user: User):
    """Change user role

    Args:
        user (int | str): user id or username of the user
        role (str): role of user, [user|reseller|admin|super_user]

    Example:
        <code>/role @username admin</code>
        <code>/role 123456789 admin</code>
    """
    try:
        _, user_id, role = message.text.split()
    except ValueError:
        return await message.answer(
            "Could not parse the command! format: /role [user_id|username] [role]"
        )
    if user_id.isnumeric():
        user_to_get = await User.filter(id=int(user_id)).first()
    else:
        user_to_get = await User.filter(username__iexact=user_id.lstrip("@")).first()

    if not user_to_get:
        return await message.answer(f"User {user_id} not found!")

    roles = {"user": 0, "reseller": 1, "admin": 2, "super_user": 3}
    if not role in roles:
        return await message.answer(f"Unknown role! must be one of " + "".join(roles))

    user_to_get.role = roles.get(role)
    await user_to_get.save()
    await user_to_get.refresh_from_db()
    text = f"""
Done!

User id: <code>{user_to_get.id}</code>
Role: <code>{user_to_get.role.name}</code>

Actions:

User info: <code>/info {user_id}</code>
"""
    await message.answer(text)


# charge and decharge user
@router.message(Command("charge"), SuperUserAccess())
async def charge_user_command(message: Message, user: User):
    """Charge user

    Args:
        user (int | str): user id or username of the user
        amount (int): amount

    Example:
        <code>/charge @username 500000</code>
        <code>/charge 123456789 500000</code>
    """
    try:
        _, user_id, amount = message.text.split()
        amount = int(amount)
    except ValueError:
        return await message.answer(
            "Could not parse the command! format: /charge [user_id|username] [amount]"
        )
    if user_id.isnumeric():
        user_to_get = await User.filter(id=int(user_id)).first()
    else:
        user_to_get = await User.filter(username__iexact=user_id.lstrip("@")).first()

    if not user_to_get:
        return await message.answer(f"User {user_id} not found!")

    async with in_transaction():
        transaction = await Transaction.create(
            type=Transaction.PaymentType.by_admin,
            status=Transaction.Status.finished,
            amount=amount,
            user=user_to_get,
        )
        await ByAdminPayment.create(
            by_admin=user,
            transaction=transaction,
        )
    text = f"""
Done!

Transaction id: <code>{transaction.id}</code>
Amount: <code>{transaction.amount:,}</code>
User id: <code>{transaction.user_id}</code>

Actions:

Undo: <code>/undotr {transaction.id}</code>
User info: <code>/info {transaction.user_id}</code>
"""
    await message.answer(text)
    await bot.send_message(
        user_to_get.id,
        f"✅ مبلغ {transaction.amount:,} تومان از طرف <code>{user.id}</code> به حساب شما اضافه شد!",
    )


@router.message(Command("decharge"), SuperUserAccess())
async def decharge_user_command(message: Message, user: User):
    """DeCharge user

    Args:
        user (int | str): user id or username of the user
        amount (int): amount

    Example:
        <code>/decharge @username 500000</code>
        <code>/decharge 123456789 500000</code>
    """
    try:
        _, user_id, amount = message.text.split()
        amount = int(amount)
    except ValueError:
        return await message.answer(
            "Could not parse the command! format: /decharge [user_id|username] [amount]"
        )
    if user_id.isnumeric():
        user_to_get = await User.filter(id=int(user_id)).first()
    else:
        user_to_get = await User.filter(username__iexact=user_id.lstrip("@")).first()

    if not user_to_get:
        return await message.answer(f"User {user_id} not found!")

    invoice = await Invoice.create(
        amount=amount,
        type=Invoice.Type.by_admin,
        user=user_to_get,
    )
    text = f"""
Done!

Invoice id: <code>{invoice.id}</code>
Amount: <code>{invoice.amount:,}</code>
User id: <code>{invoice.user_id}</code>

Actions:

Undo: <code>/undoiv {invoice.id}</code>
User info: <code>/info {invoice.user_id}</code>
"""
    await message.answer(text)


@router.message(Command("undotr"), SuperUserAccess())
async def undotr_command(message: Message, user: User):
    """Remove Transaction

    Args:
        id (int): transaction id

    Example:
        <code>/undotr 112233 </code>
    """
    try:
        _, transaction_id = message.text.split()
        transaction_id = int(transaction_id)
    except ValueError:
        return await message.answer("Could not parse the command! format: /undotr [id]")
    transaction = await Transaction.filter(id=transaction_id).first()

    if not transaction:
        return await message.answer(f"Transaction {transaction_id} not found!")

    await transaction.delete()
    text = f"""
Done!

Transaction id: <code>{transaction.id}</code>
Type: <code>{transaction.type.name}</code>
Amount: <code>{transaction.amount:,}</code>
User id: <code>{transaction.user_id}</code>
"""
    await message.answer(text)


@router.message(Command("undoiv"), SuperUserAccess())
async def undoiv_command(message: Message, user: User):
    """Remove Invoice

    Args:
        id (int): invoice id

    Example:
        <code>/undoiv 112233 </code>
    """
    try:
        _, invoice_id = message.text.split()
        invoice_id = int(invoice_id)
    except ValueError:
        return await message.answer("Could not parse the command! format: /undotr [id]")
    invoice = await Invoice.filter(id=invoice_id).first()

    if not invoice:
        return await message.answer(f"invoice {invoice_id} not found!")

    await invoice.delete()
    text = f"""
Done!

Invoice id: <code>{invoice.id}</code>
Type: <code>{invoice.type.name}</code>
Amount: <code>{invoice.amount:,}</code>
User id: <code>{invoice.user_id}</code>
"""
    await message.answer(text)


# block and unblock users
@router.message(Command("block"), SuperUserAccess())
async def block_user_command(message: Message, user: User):
    """Block user

    Args:
        user (int | str): user id or username of the user

    Example:
        <code>/block @username</code>
        <code>/block 123456789</code>
    """
    try:
        _, user_id = message.text.split()
    except ValueError:
        return await message.answer(
            "Could not parse the command! format: /block [user_id|username]"
        )
    if user_id.isnumeric():
        user_to_get = await User.filter(id=int(user_id)).first()
    else:
        user_to_get = await User.filter(username__iexact=user_id.lstrip("@")).first()

    if not user_to_get:
        return await message.answer(f"User {user_id} not found!")

    if (user_to_get.role == User.Role.super_user) or (user_to_get.id == user.id):
        return await message.answer("You cant do that!")

    if user_to_get.is_blocked:
        return await message.answer("User already blocked")

    user_to_get.is_blocked = True
    await user_to_get.save()
    await message.answer(
        f"User <a href='tg://user?id={user_to_get.id}'>{user_to_get.id}</a> blocked!"
    )


@router.message(Command("unblock"), SuperUserAccess())
async def unblock_user_command(message: Message, user: User):
    """Unblock user

    Args:
        user (int | str): user id or username of the user

    Example:
        <code>/unblock @username</code>
        <code>/unblock 123456789</code>
    """
    try:
        _, user_id = message.text.split()
    except ValueError:
        return await message.answer(
            "Could not parse the command! format: /unblock [user_id|username]"
        )
    if user_id.isnumeric():
        user_to_get = await User.filter(id=int(user_id)).first()
    else:
        user_to_get = await User.filter(username__iexact=user_id.lstrip("@")).first()

    if not user_to_get:
        return await message.answer(f"User {user_id} not found!")

    if not user_to_get.is_blocked:
        return await message.answer("User is not blocked")

    user_to_get.is_blocked = False
    await user_to_get.save()
    await message.answer(
        f"User <a href='tg://user?id={user_to_get.id}'>{user_to_get.id}</a> unblocked!"
    )


@router.message(Command("access"), SuperUserAccess())
async def access_user_command(message: Message, user: User):
    """Access user

    Args:
        user (int | str): user id of the user

    Example:
        <code>/access 123456789</code>
    """
    try:
        _, user_id = message.text.split()
    except ValueError:
        return await message.answer(
            "Could not parse the command! format: /access [user_id]"
        )
    if user_id.isnumeric():
        user_id = int(user_id)
    else:
        return await message.reply("user_id must be numeric!")

    await Settings.give_user_access(user_id)

    await message.answer(
        f"User <a href='tg://user?id={user_id}'>{user_id}</a> has been given access!"
    )


@router.message(Command("noaccess"), SuperUserAccess())
async def noaccess_user_command(message: Message, user: User):
    """Remove user access

    Args:
        user (int | str): user id of the user

    Example:
        <code>/noaccess 123456789</code>
    """
    try:
        _, user_id = message.text.split()
    except ValueError:
        return await message.answer(
            "Could not parse the command! format: /noaccess [user_id]"
        )
    if user_id.isnumeric():
        user_id = int(user_id)
    else:
        return await message.reply("user_id must be numeric!")

    await Settings.remove_user_access(user_id)

    await message.answer(
        f"User <a href='tg://user?id={user_id}'>{user_id}</a> access removed! "
        f"if user already started the bot, you have to block them! try: <code>/info {user_id}</code>"
    )


@router.callback_query(
    ManageUser.Callback.filter(),
    SuperUserAccess(),
)
async def manage_user_action(
    query: CallbackQuery,
    user: User,
    callback_data: ManageUser.Callback,
    state: FSMContext,
):
    managed_user = await User.filter(
        id=callback_data.user_id,
    ).first()
    if not managed_user:
        return await query.answer(f"❌ کاربر یافت نشد!")

    if callback_data.action == ManageUserAction.discount_percent:
        await user.fetch_related("setting")
        if user.role != User.Role.super_user:
            max_discount = user.setting.discount_percentage if user.setting else 0
            if not max_discount:
                return await query.answer(
                    "درصد تخفیف شما تنظیم نشده است، بنابراین امکان تنظیم برای کاربران خود را ندارید! لطفا با پشتیبانی تماس بگیرید.",
                    show_alert=True,
                )
        else:
            max_discount = 100
        text = f"""
درصد تخفیف جدید کاربر را وارد کنید:
(حداکثر {max_discount} درصد)
    """
        await state.set_state(ManageUserForm.discount_percent)

    elif callback_data.action == ManageUserAction.max_test_services:
        await user.fetch_related("setting")
        if user.role != User.Role.super_user:
            max_count = user.setting.daily_test_services if user.setting else 0
            if not max_count or max_count <= 1:
                return await query.answer(
                    "تعداد سرویس‌های تست شما تنظیم نشده است، بنابراین امکان تنظیم برای کاربران خود را ندارید! لطفا با پشتیبانی تماس بگیرید.",
                    show_alert=True,
                )
        else:
            max_count = "+inf"
        text = f"""
تعداد سرویس‌های تست که این کاربر در یک روز می‌تواند دریافت کند را وارد کنید:
(حداکثر {max_count})
    """
        await state.set_state(ManageUserForm.daily_test_services)

    elif callback_data.action == ManageUserAction.proxy_prefix:
        text = f"""
💡 این متن در ابتدای نام پروکسی‌های شما قرار می‌گیرد و فقط میتواند شامل حروف انگلیسی یا اعداد باشد!

💡 مقدار پیشفرض برای پروکسی‌ها <code>{config.DEFAULT_USERNAME_PREFIX}</code> می‌باشد

✍️ پیشوند پروکسی را برای تنظیم وارد کنید:
"""
        await state.set_state(ManageUserForm.proxy_prefix)
    else:
        return

    await state.set_data(
        {
            "user_id": managed_user.id,
        }
    )
    await query.message.delete()
    await query.message.answer(
        text,
        reply_markup=CancelUserForm(cancel=True).as_markup(
            one_time_keyboard=True, resize_keybaord=True
        ),
    )


@router.message(ManageUserForm.discount_percent, SuperUserAccess())
async def manage_users_discount_percent(
    message: Message, user: User, state: FSMContext
):
    try:
        amount = int(message.text)
    except ValueError:
        return await message.reply(
            f"درصد باید مقداری عددی باشد! لطفا دوباره ارسال کنید:"
        )
    if user.role != User.Role.super_user:
        max_discount = user.setting.discount_percentage if user.setting else 0
    else:
        max_discount = 100
    if amount > max_discount:
        return await message.reply(
            f"درصد باید مقداری کمتر از {max_discount} باشد! دوباره ارسال کنید:"
        )

    data = await state.get_data()
    q = UserSetting.filter(user_id=data.get("user_id"))
    if not await q.first():
        await UserSetting.create(
            user_id=data.get("user_id"), discount_percentage=amount
        )
    else:
        await q.update(discount_percentage=amount)

    await state.clear()
    await message.reply(f"درصد تخفیف کاربر به {amount} تنظیم شد!")


@router.message(ManageUserForm.daily_test_services, SuperUserAccess())
async def manage_users_daily_test_services(
    message: Message, user: User, state: FSMContext
):
    try:
        amount = int(message.text)
    except ValueError:
        return await message.reply(
            f"تعداد باید مقداری عددی باشد! لطفا دوباره ارسال کنید:"
        )
    if user.role != User.Role.super_user:
        max_count = user.setting.daily_test_services if user.setting else 0
        if amount > max_count:
            return await message.reply(
                f"تعداد باید مقداری کمتر از {max_count} باشد! دوباره ارسال کنید:"
            )

    data = await state.get_data()
    q = UserSetting.filter(user_id=data.get("user_id"))
    if not await q.first():
        await UserSetting.create(
            user_id=data.get("user_id"), daily_test_services=amount
        )
    else:
        await q.update(daily_test_services=amount)

    await state.clear()
    await message.reply(f"تعداد سرویس‌های تست روزانه کاربر به {amount} تنظیم شد!")


@router.message(ManageUserForm.proxy_prefix, SuperUserAccess())
async def manage_users_daily_test_services(
    message: Message, user: User, state: FSMContext
):
    username_prefix = message.text
    if not username_prefix.isalnum():
        return await message.answer(
            f"❌ پیشوند پروکسی‌ها فقط می‌تواند شامل اعداد و حروف انگلیسی باشد! دوباره ارسال کنید:",
            reply_markup=CancelUserForm(cancel=True).as_markup(
                one_time_keyboard=True, resize_keyboard=True
            ),
        )
    if not (3 < len(username_prefix) < 20):
        return await message.answer(
            f"❌ پیشوند پروکسی‌ها فقط می‌تواند بین ۴ تا ۲۰ کاراکتر باشد! دوباره ارسال کنید:",
            reply_markup=CancelUserForm(cancel=True).as_markup(
                one_time_keyboard=True, resize_keyboard=True
            ),
        )

    data = await state.get_data()
    q = UserSetting.filter(user_id=data.get("user_id"))
    if not await q.first():
        await UserSetting.create(
            user_id=data.get("user_id"), proxy_username_prefix=username_prefix
        )
    else:
        await q.update(proxy_username_prefix=username_prefix)

    await state.clear()
    await message.reply(
        f"پیشوند پروکسی‌های کاربر به <code>{username_prefix}</code> تنظیم شد!"
    )


def generate_commands_help() -> list[str]:
    def sort_by_line(obj: callable):
        return obj.__code__.co_firstlineno

    cmd_functions: list[callable] = [
        obj
        for name, obj in inspect.getmembers(sys.modules[__name__])
        if (
            inspect.isfunction(obj)
            and name.endswith("_command")
            and obj.__doc__ is not None
        )
    ]
    cmd_functions.sort(key=sort_by_line)
    spacer = f"\n{'*' * 30}\n"
    output = list()
    index = 0
    for obj in cmd_functions:
        try:
            if len(output[index]) >= 3500:
                index += 1
                output.insert(index, "")
        except IndexError:
            output.insert(0, "")

        output[index] += spacer
        output[index] += obj.__doc__

    return output


HELP_TEXT = generate_commands_help()


@router.message(Command("usercmd"), SuperUserAccess())
async def show_help_command(message: Message, user: User):
    """Show help message

    /usercmd

    Returns:
        Message: message of help text

    Example:
        /usercmd
    """
    for text in HELP_TEXT:
        await message.reply(text)

app/handlers/admin/user.py
govfvck/Marzbot-free
from aiogram import F, Router
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, Message

import config
from app.keyboards.base import ForceJoin, MainMenu
from app.models.user import User
from app.utils import helpers
from app.utils.filters import IsJoinedToChannel

from .start import main_menu_handler

router = Router(name="base")


@router.message((F.text == MainMenu.cancel) | (F.text == MainMenu.back))
@router.message(Command(commands=["cancel"]))
async def cancel_handler(message: Message, user: User, state: FSMContext):
    """
    Allow user to cancel any action
    """
    await main_menu_handler(message, user)


@router.message(F.text == MainMenu.support)
async def support(message: Message, user: User):
    await message.answer(config.SUPPORT_TEXT, disable_web_page_preview=True)


@router.message(Command("help"))
@router.message(F.text == MainMenu.help)
async def shelp(message: Message, user: User):
    await message.answer(config.HELP_TEXT, disable_web_page_preview=True)


@router.callback_query(ForceJoin.Callback.filter())
async def check_force_join(query: CallbackQuery, user: User):
    if await helpers.check_force_join(user):
        await query.message.edit_text("✅ عضویت شما در کانال تایید شد")
        return await main_menu_handler(
            query,
            user,
        )
    await query.answer("🚫 عضویت شما در کانال تایید نشد!", show_alert=True)


@router.message(~IsJoinedToChannel(send_alert=False))
async def force_join_ph(message: Message):
    return


@router.message()
async def command_not_found(message: Message):
    text = """
🤕 متوجه دستور ارسالی نشدم!
برای رفتن به منوی اصلی دستور /menu رو ارسال کنید😉
    """
    await message.reply(text)

app/handlers/base.py
govfvck/Marzbot-free
from aiogram import Router

from app.logger import get_logger

router = Router(name="erros")
logger = get_logger("handlers/errors")


# @router.errors()
# async def httpx_error_handler(exception: httpx.ConnectError | httpx.ConnectTimeout):
#     raise exception

app/handlers/errors.py
govfvck/Marzbot-free
from aiogram import F, Router
from aiogram.filters import Command, CommandObject, CommandStart
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, Message

import config
from app.keyboards.base import MainMenu
from app.main import bot
from app.models.user import User
from app.utils.settings import Settings

router = Router(name="start")


@router.message(CommandStart(deep_link=False, ignore_case=True))
async def start_handler(message: Message, user: User, command: CommandObject):
    await message.answer(config.START_TEXT)
    await main_menu_handler(message, user)


@router.message(F.text == MainMenu.main_menu)
@router.message(Command(commands="menu"))
async def main_menu_handler(
    qmsg: Message | CallbackQuery, user: User, state: FSMContext = None
):
    if (state is not None) and (await state.get_state() is not None):
        await state.clear()
    text = """
♻️ منوی اصلی ربات:
🤖 چه کاری میتونم براتون انجام بدم؟👇
    """
    if isinstance(qmsg, CallbackQuery):
        return await qmsg.message.answer(
            text,
            reply_markup=MainMenu().as_markup(resize_keyboard=True),
        )
    return await qmsg.answer(
        text,
        reply_markup=MainMenu().as_markup(resize_keyboard=True),
    )

app/handlers/start.py
govfvck/Marzbot-free
import importlib

from aiogram import Router

from app.logger import get_logger

router = Router(name="user")
logger = get_logger("handlers/user")

handlers = [
    # "user",
    "account",
    "payment",
    "purchase",
    "proxy",
]


def init_handler() -> None:
    for name in handlers:
        importlib.import_module(f".{name}", "app.handlers.user")

app/handlers/user/__init__.py
govfvck/Marzbot-free
from aiogram import F
from aiogram.types import CallbackQuery, Message

from app.keyboards.base import MainMenu
from app.keyboards.user.account import UserPanel, UserPanelAction
from app.models.user import User
from app.utils.filters import IsJoinedToChannel

from . import router

ACCOUNT_TYPE = {
    "user": "کاربر معمولی",
    "reseller": "فروشنده",
    "admin": "ادمین",
    "super_user": "ادمین اصلی",
}


@router.message(F.text == MainMenu.account, IsJoinedToChannel())
@router.callback_query(UserPanel.Callback.filter(F.action == UserPanelAction.show))
async def account(qmsg: Message | CallbackQuery, user: User):
    balance = await user.get_balance()
    text = f"""
✅ اطلاعات حساب شما:

💬 نام کاربری: {f'@{user.username}' if user.username else '➖'}
📲 شناسه کاربری: <code>{user.id}</code>
💲 اعتبار در دسترس: <b>{balance:,}</b> تومان
🔋 سرویس‌های فعال: <b>{await user.proxies.all().count()}</b>
"""

    if isinstance(qmsg, CallbackQuery):
        return await qmsg.message.edit_text(
            text + "‌‌",
            reply_markup=UserPanel(user=user).as_markup(),
        )
    await qmsg.answer(text + "‌‌", reply_markup=UserPanel(user=user).as_markup())

app/handlers/user/account.py
govfvck/Marzbot-free
import uuid

from aiogram import F
from aiogram.filters import StateFilter
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, Message, ReplyKeyboardRemove
from tortoise.transactions import in_transaction

import config
from app.keyboards.base import CancelUserForm, MainMenu
from app.keyboards.user.account import UserPanel, UserPanelAction
from app.keyboards.user.payment import (
    ChargeMethods,
    ChargePanel,
    PayCryptoUrl,
    SelectPayAmount,
)
from app.models.user import CryptoPayment, Transaction, User
from app.utils.filters import IsJoinedToChannel
from app.utils.settings import Settings
from payment_clients.nobitex import CouldNotGetUSDTPrice, NobitexMarketAPI
from payment_clients.nowpayments import NowPaymentsAPI, NowPaymentsError

from . import router


class SelectCustomAmountForm(StatesGroup):
    method = State()
    amount = State()


@router.message(
    (F.text == MainMenu.back) | (F.text == MainMenu.cancel),
    StateFilter(SelectCustomAmountForm),
)
@router.message(F.text == MainMenu.charge, IsJoinedToChannel())
@router.callback_query(UserPanel.Callback.filter(F.action == UserPanelAction.charge))
async def charge(qmsg: Message | CallbackQuery, user: User, state: FSMContext = None):
    if (state is not None) and (await state.get_state() is not None):
        text = "🌀 عملیات لغو شد!"
        await state.clear()
        if isinstance(qmsg, CallbackQuery):
            await qmsg.answer(text)
        else:
            await qmsg.answer(text=text, reply_markup=ReplyKeyboardRemove())
    settings = await Settings.payment_settings()
    if not any([True for v in settings.values() if v]):
        text = """
در حال حاضر درگاه پرداخت غیرفعال می‌باشد! برای شارژ حساب با مدیر سیستم تماس بگیرید.
"""
        if isinstance(qmsg, Message):
            return await qmsg.answer(text)
        return await qmsg.message.edit_text(text)
    else:
        text = """
    ♻️ شما میتونید به روش‌های مختلفی حسابتون رو شارژ کنید🙄

    ✔️ حداقل میزان پرداختی برای شارژ حساب 20,000 تومان می‌باشد

    برای ادامه مراحل شارژ حساب، یکی از روش‌های پرداخت زیر رو انتخاب کنید👇
        """
        if isinstance(qmsg, Message):
            return await qmsg.answer(
                text, reply_markup=ChargePanel(settings).as_markup()
            )
        return await qmsg.message.edit_text(
            text, reply_markup=ChargePanel(settings).as_markup()
        )


@router.callback_query(ChargePanel.Callback.filter(F.method == ChargeMethods.crypto))
async def crypto_select_amount(query: CallbackQuery, user: User):
    try:
        if not await Settings.payment_crypto() or not await NowPaymentsAPI.status():
            return await query.answer(
                "📍 درحال حاضر امکان پرداخت ارز دیجیتال وجود ندارد! لطفا با پشتیبانی تماس بگیرید.",
                show_alert=True,
            )
    except NowPaymentsError as exc:
        await query.answer(
            "📍 درحال حاضر امکان پرداخت ارز دیجیتال وجود ندارد! لطفا با پشتیبانی تماس بگیرید.",
            show_alert=True,
        )
        raise exc

    # fmt: off
    text = f"""
✔️ شما در حال افزایش اعتبار با ارز دیجیتال هستید!

❗️اگر اشتباه وارد این بخش شدید دکمه «برگشت» را کلیک کنید
{config.CRYPTO_PAYMENT_HELP}
{config.FREE_CREDIT_ON_TEXT}

✔️ برای ادامه، مبلغ مورد نظر برای افزایش اعتبار رو انتخاب کنید:
‌‌
    """
    # fmt: on
    await query.message.edit_text(
        text, reply_markup=SelectPayAmount(method=ChargeMethods.crypto).as_markup()
    )


@router.callback_query(SelectPayAmount.Callback.filter(F.amount == 0))
async def enter_custom_amount(
    query: CallbackQuery,
    user: User,
    callback_data: SelectPayAmount.Callback,
    state: FSMContext,
):
    text = """
💴 مبلغ مورد نظر برای افزایش اعتبار را وارد کنید:
"""
    await state.set_state(SelectCustomAmountForm.amount)
    await state.set_data({"method": callback_data.method})
    await query.message.answer(
        text,
        reply_markup=CancelUserForm(cancel=True).as_markup(
            resize_keyboard=True, one_time_keyboard=True
        ),
    )


@router.message(SelectCustomAmountForm.amount)
async def get_custom_amount(message: Message, user: User, state: FSMContext):
    try:
        amount = int(message.text)
    except ValueError:
        return await message.reply("❌ لطفا مقداری عددی وارد کنید:")

    if amount < 20000:
        return await message.reply(f"❌ لطفا مقداری بیشتر از 20000 وارد کنید:")

    method = (await state.get_data()).get("method")
    free = (
        0
        if (not config.PAYMENTS_DISCOUNT_ON) or (amount < config.PAYMENTS_DISCOUNT_ON)
        else amount * (config.PAYMENTS_DISCOUNT_ON_PERCENT / 100)
    )
    callback_data = SelectPayAmount.Callback(amount=amount, free=free, method=method)
    if method == ChargeMethods.crypto:
        return await crypto_select_amount(message, user, callback_data=callback_data)


@router.callback_query(
    SelectPayAmount.Callback.filter(F.method == ChargeMethods.crypto)
)
async def crypto_select_amount(
    qmsg: CallbackQuery | Message, user: User, callback_data: SelectPayAmount.Callback
):
    if not await Settings.payment_crypto():
        if isinstance(qmsg, CallbackQuery):
            return await qmsg.answer(
                "📍 درحال حاضر امکان پرداخت ارز دیجیتال وجود ندارد! لطفا با پشتیبانی تماس بگیرید.",
                show_alert=True,
            )
        return await qmsg.answer(
            "📍 درحال حاضر امکان پرداخت ارز دیجیتال وجود ندارد! لطفا با پشتیبانی تماس بگیرید.",
            show_alert=True,
        )
    try:
        async with in_transaction():
            usdt_rate = await NobitexMarketAPI.get_price()
            transaction = await Transaction.create(
                type=Transaction.PaymentType.crypto,
                status=Transaction.Status.waiting,
                amount=callback_data.amount + callback_data.free,
                amount_free_given=callback_data.free,
                user=user,
            )
            invoice = await NowPaymentsAPI.create_invoice(
                price_amount=round(callback_data.amount / usdt_rate, 3),
                order_id=transaction.id,
            )
            await CryptoPayment.create(
                transaction=transaction,
                usdt_rate=usdt_rate,
                invoice_id=invoice.id,
                order_id=invoice.order_id,
                price_amount=invoice.price_amount,
                price_currency=invoice.price_currency,
                nowpm_created_at=invoice.created_at,
                nowpm_updated_at=invoice.updated_at,
            )
        text = f"""
✅ فاکتور افزایش اعتبار شما ساخته شد!

💳 شماره فاکتور: {transaction.id}
💲مبلغ قابل پرداخت: <b>{transaction.amount - transaction.amount_free_given:,}</b> تومان (<b>{invoice.price_amount}</b> دلار)
~~~~~~~~~~~~~~~~~~~~~~~~
🔵 تأیید پرداخت به صورت کاملاً خودکار انجام می‌شود. بعد از پرداخت و تأیید تراکنش در بلاکچین، مبلغ مورد نظر به حساب شما اضافه می‌شود!

⚠️ فاکتور پرداخت شما تا ۲ ساعت دیگر معتبر می‌باشد.

🟩 برای پرداخت روی دکمه زیر کلیک کنید:
‌‌
"""
        if isinstance(qmsg, CallbackQuery):
            return await qmsg.message.edit_text(
                text=text,
                reply_markup=PayCryptoUrl(url=invoice.invoice_url).as_markup(),
            )
        return await qmsg.answer(
            text=text, reply_markup=PayCryptoUrl(url=invoice.invoice_url).as_markup()
        )
    except NowPaymentsError as err:
        if isinstance(qmsg, CallbackQuery):
            await qmsg.answer(
                "📍 درحال حاضر امکان پرداخت ارز دیجیتال وجود ندارد! لطفا با پشتیبانی تماس بگیرید.",
                show_alert=True,
            )
        else:
            await qmsg.answer(
                "📍 درحال حاضر امکان پرداخت ارز دیجیتال وجود ندارد! لطفا با پشتیبانی تماس بگیرید."
            )
        raise err
    except CouldNotGetUSDTPrice as err:
        if isinstance(qmsg, CallbackQuery):
            await qmsg.answer(
                "📍 خطایی در دریافت نرخ ارز رخ داد! لطفا با پشتیبانی تماس بگیرید.",
                show_alert=True,
            )
        else:
            await qmsg.answer(
                "📍 خطایی در دریافت نرخ ارز رخ داد! لطفا با پشتیبانی تماس بگیرید."
            )
        raise err

app/handlers/user/payment.py
govfvck/Marzbot-free
import io
from datetime import datetime as dt

import qrcode
from aiogram import F, exceptions
from aiogram.filters import Command, CommandObject
from aiogram.filters.state import StateFilter
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import (
    BufferedInputFile,
    CallbackQuery,
    InputMediaPhoto,
    Message,
    ReplyKeyboardRemove,
)
from tortoise.transactions import in_transaction

from app.keyboards.base import MainMenu
from app.keyboards.user.account import UserPanel, UserPanelAction
from app.keyboards.user.proxy import (
    ConfirmProxyPanel,
    ConfirmRenew,
    Proxies,
    ProxiesActions,
    ProxyLinks,
    ProxyPanel,
    ProxyPanelActions,
    RenewMethods,
    RenewSelectMethod,
    RenewSelectService,
    ResetPassword,
)
from app.marzban import Marzban
from app.models.proxy import Proxy, ProxyStatus
from app.models.service import Service
from app.models.user import Invoice, User
from app.utils import helpers
from app.utils.filters import IsJoinedToChannel, SuperUserAccess
from marzban_client.api.user import (
    get_user_api_user_username_get,
    modify_user_api_user_username_put,
    remove_user_api_user_username_delete,
    reset_user_data_usage_api_user_username_reset_post,
    revoke_user_subscription_api_user_username_revoke_sub_post,
)
from marzban_client.models.user_modify import UserModify
from marzban_client.models.user_modify_inbounds import UserModifyInbounds
from marzban_client.models.user_modify_proxies import UserModifyProxies
from marzban_client.models.user_status import UserStatus

from . import router

PROXY_STATUS = {
    UserStatus.ACTIVE: "فعال ✅",
    UserStatus.DISABLED: "غیرفعال ❌",
    UserStatus.LIMITED: "محدود شده 🔒",
    UserStatus.EXPIRED: "منقضی شده ⏳",
}


class SetCustomNameForm(StatesGroup):
    proxy_id = State()
    user_id = State()
    current_page = State()
    name = State()


class ApiUserError(Exception):
    pass


@router.message(F.text == MainMenu.proxies, IsJoinedToChannel())
@router.callback_query(UserPanel.Callback.filter(F.action == UserPanelAction.proxies))
@router.callback_query(Proxies.Callback.filter(F.action == ProxiesActions.show))
async def proxies(
    qmsg: Message | CallbackQuery,
    user: User,
    callback_data: Proxies.Callback | UserPanel.Callback = None,
):
    if isinstance(callback_data, Proxies.Callback):
        user_id = (
            callback_data.user_id
            if callback_data and callback_data.user_id
            else user.id
        )
        page = callback_data.current_page if callback_data else 0
    else:
        user_id = user.id
        page = 0

    q = Proxy.filter(user_id=user_id).limit(11).offset(0 if page == 0 else page * 10)

    count = await q.count()
    if count < 1:
        text = "در حال حاضر هیچ پروکسی فعالی ندارید😬"
        if isinstance(qmsg, CallbackQuery):
            return qmsg.answer(text, show_alert=True)
        return qmsg.answer(text)

    proxies = await q.prefetch_related("service").all()
    reply_markup = Proxies(
        proxies[:10],
        user_id=user_id,
        current_page=page,
        next_page=True if count > 10 else False,
        prev_page=True if page > 0 else False,
    ).as_markup()
    text = "🔵 لیست پروکسی‌های خریداری شده👇 (برای مدیریت هر پروکسی روی آن کلیک کنید)"
    try:
        if isinstance(qmsg, CallbackQuery):
            return await qmsg.message.edit_text(
                text,
                reply_markup=reply_markup,
            )
        return await qmsg.answer(
            text,
            reply_markup=reply_markup,
        )
    except exceptions.TelegramBadRequest as exc:
        await qmsg.answer("❌ خطایی رخ داد!")
        raise exc


@router.message(F.text == MainMenu.cancel, StateFilter(SetCustomNameForm))
@router.message(Command("proxy"), SuperUserAccess())
@router.callback_query(Proxies.Callback.filter(F.action == ProxiesActions.show_proxy))
async def show_proxy(
    qmsg: Message | CallbackQuery,
    user: User,
    callback_data: Proxies.Callback = None,
    state: FSMContext = None,
    command: CommandObject = None,
):
    if command:
        proxy_id, user_id, current_page = None, None, 0
        proxy = await Proxy.filter(username__iexact=command.args).first()
    else:
        proxy_id, user_id, current_page = None, None, None
        if (state is not None) and (await state.get_state() is not None):
            data = await state.get_data()
            proxy_id, user_id, current_page = data.values()
            text = "🌀 عملیات لغو شد!"
            await state.clear()
            if isinstance(qmsg, CallbackQuery):
                await qmsg.answer(text)
            else:
                await qmsg.answer(text=text, reply_markup=ReplyKeyboardRemove())
        if callback_data:
            proxy_id, user_id, current_page = (
                proxy_id or callback_data.proxy_id,
                user_id or callback_data.user_id,
                current_page or callback_data.current_page,
            )
        proxy = await Proxy.filter(id=proxy_id).first()
    if not proxy:
        return await qmsg.answer("❌ اشتراک مورد نظر یافت نشد!")

    if user_id:
        if (user.role < user.Role.admin) and (user.id != user_id):
            return
        elif (user.role == user.Role.admin) and (proxy.user_id != user_id):
            await proxy.fetch_related("user")
            if proxy.user.parent_id != user.id:
                return
    try:
        client = Marzban.get_server(proxy.server_id)
        sv_proxy = await get_user_api_user_username_get.asyncio(
            username=proxy.username, client=client
        )
    except Exception as err:
        await qmsg.answer(
            f"❌ خطایی در دریافت اطلاعات سرویس رخ داد! لطفا کمی بعد دوباره تلاش کنید."
        )
        raise err
    await proxy.fetch_related("service")
    if not sv_proxy:
        proxy.status = ProxyStatus.disabled
        await proxy.save()
        if user.role < user.Role.admin:
            return await qmsg.answer(
                f"❌ پروکسی مورد نظر در سرور یافت نشد! لطفا با پشتیبانی تماس بگیرید.",
                show_alert=True,
            )
        await proxy.refresh_from_db()
        await proxy.service.fetch_related("server")
        text = f"""
❌ پروکسی در سرور یافت نشد!

آیدی: {proxy.id}
نام تنظیم شده: {proxy.custom_name}
شناسه: {proxy.username}
هزینه: {proxy.cost:,}

سرویس: {proxy.service.display_name}
        """
        await proxy.fetch_related("reserve")
        reply_markup = ProxyPanel(
            proxy,
            user_id=user_id,
            current_page=current_page,
            renewable=False
            if proxy.service.one_time_only
            or proxy.service.is_test_service
            or not proxy.service.renewable
            else True,
        ).as_markup()
        if isinstance(qmsg, CallbackQuery):
            return await qmsg.message.edit_text(text, reply_markup=reply_markup)
        return await qmsg.answer(text, reply_markup=reply_markup)

    if proxy.status.value != sv_proxy.status.value:
        proxy.status = sv_proxy.status.value
        await proxy.save()
        await proxy.refresh_from_db()
    text = f"""
⭐️ شناسه: <code>{sv_proxy.username}</code> {f'({proxy.custom_name})' if proxy.custom_name else ''}
🌀 وضعیت: <b>{PROXY_STATUS.get(sv_proxy.status)}</b>
⏳ تاریخ انقضا: <b>{helpers.hr_date(sv_proxy.expire) if sv_proxy.expire else '♾'}</b> {f'<i>({helpers.hr_time(sv_proxy.expire - dt.now().timestamp(), lang="fa")})</i>' if sv_proxy.expire and sv_proxy.status != UserStatus.EXPIRED else ''}
📊 حجم مصرف شده: <b>{helpers.hr_size(sv_proxy.used_traffic, lang='fa')}</b>
{f'🔋 حجم باقی‌مانده: <b>{helpers.hr_size(sv_proxy.data_limit - sv_proxy.used_traffic ,lang="fa")}</b>' if sv_proxy.data_limit else ''}

🔑 پروکسی های فعال: {', '.join([f'<b>{t.upper()}</b>' for t in [protocol for protocol in sv_proxy.inbounds.additional_properties]])}

🔗 لینک اتصال هوشمند: 
<code>{sv_proxy.subscription_url}</code>

❕برای اطلاع یافتن از وضعیت پروکسی بدون وارد شدن به ربات، میتونید لینک اتصال هوشمند رو ذخیره کنید و در مروگر باز کنید، یا اینکه روی لینک زیر کلیک کنید:
<a href='{sv_proxy.subscription_url}'>🔺 اتصال هوشمند</a>

💡 برای دریافت راهنمای اتصال و استفاده دستور /help را ارسال کنید!
"""
    if sv_proxy.status == UserStatus.ACTIVE:
        text += """

💡 برای قطع اتصال افراد متصل می‌توانید از دکمه «تغییر پسوورد» استفاده کنید!

💡 برای دریافت لینک‌های اتصال و Qr Code میتوانید از دکمه زیر استفاده کنید👇
"""
    reply_markup = ProxyPanel(
        proxy,
        user_id=user_id,
        current_page=current_page,
        renewable=False
        if proxy.service.one_time_only
        or proxy.service.is_test_service
        or not proxy.service.renewable
        else True,
    ).as_markup()
    if isinstance(qmsg, CallbackQuery):
        return await qmsg.message.edit_text(text, reply_markup=reply_markup)
    return await qmsg.answer(text, reply_markup=reply_markup)


@router.callback_query(ProxyPanel.Callback.filter(F.action == ProxyPanelActions.remove))
async def remove_proxy(
    query: CallbackQuery, user: User, callback_data: ProxyPanel.Callback
):
    if not callback_data.confirmed:
        return await query.message.edit_text(
            "⚠️ مطمئن هستید که میخواهید سرویس مورد نظر را از لیست پروکسی‌های خود حذف کنید؟ پس از حذف امکان تمدید وجود نخواهد داشت!",
            reply_markup=ConfirmProxyPanel(
                action=ProxyPanelActions.remove,
                proxy_id=callback_data.proxy_id,
                user_id=callback_data.user_id or user.id,
                current_page=callback_data.current_page,
            ).as_markup(),
        )

    user_id = callback_data.user_id if callback_data.user_id else user.id
    proxy = await Proxy.filter(id=callback_data.proxy_id).first()
    if (user.role < user.Role.admin) and (user.id != user_id):
        return
    elif (user.role == user.Role.admin) and (proxy.user_id != user_id):
        await proxy.fetch_related("user")
        if proxy.user.parent_id != user.id:
            return

    try:
        client = Marzban.get_server(proxy.server_id)
        sv_proxy = await get_user_api_user_username_get.asyncio(
            username=proxy.username, client=client
        )
    except Exception as err:
        await query.answer(
            f"❌ خطایی در دریافت اطلاعات سرویس رخ داد! لطفا کمی بعد دوباره تلاش کنید."
        )
        raise err

    try:
        if sv_proxy:
            await remove_user_api_user_username_delete.asyncio(
                username=sv_proxy.username, client=client
            )
        await proxy.delete()

        await query.answer("✅ اشتراک از لیست پروکسی‌های شما حذف شد", show_alert=True)
        await proxies(
            query,
            user,
            callback_data=Proxies.Callback(
                user_id=callback_data.user_id,
                action=ProxiesActions.show,
                current_page=callback_data.current_page,
            ),
        )
    except Exception:
        await query.answer(
            "❌ خطایی در انجام عملیات رخ داد! لطفا با پشتیبانی تماس بگیرید."
        )


@router.callback_query(
    ProxyPanel.Callback.filter(F.action == ProxyPanelActions.reset_password)
)
async def reset_password(
    query: CallbackQuery, user: User, callback_data: ProxyPanel.Callback
):
    text = """
💡 در این بخش می‌توانید  دسترسی افراد متصل را قطع کنید!

برای انجام این کار دو روش دارید:
1️⃣ تغییر پسوورد: فقط پسوورد کانفیگ‌ها عوض شده و کاربر با استفاده از لینک اتصال هوشمند می‌تواند دوباره متصل شود.
2️⃣ تغییر اتصال هوشمند: لینک اتصال هوشمند کاربر را تغییر می‌دهد و کاربر توانایی آپدیت و استفاده از لینک اتصال هوشمند قدیمی را نخواهد داشت.

اگه میخواید دسترسی کاربر رو به صورت کامل قطع کنید، باید از هر دو روش استفاده کنید🫡
"""
    await query.message.edit_text(
        text,
        reply_markup=ResetPassword(
            proxy_id=callback_data.proxy_id,
            user_id=callback_data.user_id,
            current_page=callback_data.current_page,
        ).as_markup(),
    )


@router.callback_query(
    ProxyPanel.Callback.filter(F.action == ProxyPanelActions.reset_uuid)
)
async def reset_uuid(
    query: CallbackQuery, user: User, callback_data: ProxyPanel.Callback
):
    if not callback_data.confirmed:
        return await query.message.edit_text(
            "⚠️ مطمئن هستید که میخواهید پسوورد سرویس مورد نظر تغییر کند؟ تمام افراد متصل قطع خواهند شد!",
            reply_markup=ConfirmProxyPanel(
                action=ProxyPanelActions.reset_uuid,
                proxy_id=callback_data.proxy_id,
                user_id=callback_data.user_id or user.id,
                current_page=callback_data.current_page,
            ).as_markup(),
        )

    user_id = callback_data.user_id if callback_data.user_id else user.id
    proxy = await Proxy.filter(id=callback_data.proxy_id).first()
    if (user.role < user.Role.admin) and (user.id != user_id):
        return
    elif (user.role == user.Role.admin) and (proxy.user_id != user_id):
        await proxy.fetch_related("user")
        if proxy.user.parent_id != user.id:
            return

    try:
        client = Marzban.get_server(proxy.server_id)
        sv_proxy = await get_user_api_user_username_get.asyncio(
            username=proxy.username, client=client
        )
    except Exception as err:
        await query.answer(
            f"❌ خطایی در دریافت اطلاعات سرویس رخ داد! لطفا کمی بعد دوباره تلاش کنید."
        )
        raise err
    try:
        await proxy.fetch_related("service")
        sv_proxy = await modify_user_api_user_username_put.asyncio(
            username=sv_proxy.username,
            client=client,
            json_body=UserModify(
                proxies=UserModifyProxies.from_dict(
                    {
                        protocol: proxy.service.create_proxy_protocols(protocol)
                        for protocol in sv_proxy.proxies.additional_properties
                    }
                )
            ),
        )

        await query.answer("✅ پسوورد پروکسی تغییر یافت", show_alert=True)

        await show_proxy(
            query,
            user,
            callback_data=Proxies.Callback(
                proxy_id=proxy.id,
                user_id=user_id,
                action=ProxiesActions.show_proxy,
                current_page=callback_data.current_page,
            ),
        )
    except Exception:
        await query.answer(
            "❌ خطایی در انجام عملیات رخ داد! لطفا با پشتیبانی تماس بگیرید."
        )


@router.callback_query(
    ProxyPanel.Callback.filter(F.action == ProxyPanelActions.reset_subscription)
)
async def reset_subscription(
    query: CallbackQuery, user: User, callback_data: ProxyPanel.Callback
):
    if not callback_data.confirmed:
        return await query.message.edit_text(
            "⚠️ مطمئن هستید که میخواهید لینک اتصال هوشمند سرویس مورد نظر تغییر کند؟ امکان استفاده از لینک اتصال هوشمند قدیمی وجود نخواهد داشت!",
            reply_markup=ConfirmProxyPanel(
                action=ProxyPanelActions.reset_subscription,
                proxy_id=callback_data.proxy_id,
                user_id=callback_data.user_id or user.id,
                current_page=callback_data.current_page,
            ).as_markup(),
        )

    user_id = callback_data.user_id if callback_data.user_id else user.id
    proxy = await Proxy.filter(id=callback_data.proxy_id).first()
    if (user.role < user.Role.admin) and (user.id != user_id):
        return
    elif (user.role == user.Role.admin) and (proxy.user_id != user_id):
        await proxy.fetch_related("user")
        if proxy.user.parent_id != user.id:
            return

    try:
        client = Marzban.get_server(proxy.server_id)
        sv_proxy = await get_user_api_user_username_get.asyncio(
            username=proxy.username, client=client
        )
    except Exception as err:
        await query.answer(
            f"❌ خطایی در دریافت اطلاعات سرویس رخ داد! لطفا کمی بعد دوباره تلاش کنید."
        )
        raise err
    try:
        await revoke_user_subscription_api_user_username_revoke_sub_post.asyncio(
            username=sv_proxy.username,
            client=client,
        )

        await query.answer("✅ لینک اتصال هوشمند تغییر یافت", show_alert=True)

        await show_proxy(
            query,
            user,
            callback_data=Proxies.Callback(
                proxy_id=proxy.id,
                user_id=user_id,
                action=ProxiesActions.show_proxy,
                current_page=callback_data.current_page,
            ),
        )
    except Exception:
        await query.answer(
            "❌ خطایی در انجام عملیات رخ داد! لطفا با پشتیبانی تماس بگیرید."
        )


@router.callback_query(ProxyPanel.Callback.filter(F.action == ProxyPanelActions.links))
async def proxy_links(
    query: CallbackQuery, user: User, callback_data: ProxyPanel.Callback
):
    user_id = callback_data.user_id if callback_data.user_id else user.id
    proxy = await Proxy.filter(id=callback_data.proxy_id).first()
    if (user.role < user.Role.admin) and (user.id != user_id):
        return
    elif (user.role == user.Role.admin) and (proxy.user_id != user_id):
        await proxy.fetch_related("user")
        if proxy.user.parent_id != user.id:
            return

    try:
        client = Marzban.get_server(proxy.server_id)
        sv_proxy = await get_user_api_user_username_get.asyncio(
            username=proxy.username, client=client
        )
    except Exception as err:
        await query.answer(
            "❌ خطایی در انجام عملیات رخ داد! لطفا با پشتیبانی تماس بگیرید.",
            show_alert=True,
        )
        raise err
    if not sv_proxy:
        return await query.answer(
            "❌ خطایی در دریافت اطلاعات سرویس رخ داد! لطفا کمی بعد دوباره تلاش کنید.",
            show_alert=True,
        )
    links = "\n\n".join([f"<code>{link}</code>" for link in sv_proxy.links])
    text = f"""
🔑 پروکسی های فعال: {', '.join(f'<b>{protocol.upper()}</b>' for protocol in sv_proxy.inbounds.additional_properties)}:
    🔗 لینک‌های اتصال:
    
{links}

💡 برای کپی کردن هرکدام از لینک‌ها روی آن کلیک کنید👆

💡 برای دریافت راهنمای اتصال و استفاده دستور /help را ارسال کنید!

📷 برای دریافت <b>Qr code</b> از دکمه‌های زیر استفاده کنید👇
    """
    await query.message.edit_text(
        text,
        reply_markup=ProxyLinks(
            proxy=proxy, current_page=callback_data.current_page, user_id=user_id
        ).as_markup(),
    )


def gen_qr(text: str) -> qrcode.QRCode:
    qr = qrcode.QRCode(border=6)
    qr.add_data(text)
    return qr


async def generate_qr_code(
    message: Message, links: list[str], username: str
) -> BufferedInputFile:
    photos = list()
    for link in links:
        f = io.BytesIO()
        qr = gen_qr(link)
        qr.make_image().save(f)
        f.seek(0)
        photos.append(
            InputMediaPhoto(
                media=BufferedInputFile(
                    f.getvalue(), filename=f"generated_qr_code_{username}"
                ),
                caption=f"{link.split('://')[0].upper()} ({username})",
            )
        )
    return await message.answer_media_group(
        photos,
    )


async def generate_sub_qr_code(message: Message, link: str, username: str):
    f = io.BytesIO()
    qr = gen_qr(link)
    qr.make_image().save(f)
    f.seek(0)
    await message.answer_photo(
        photo=BufferedInputFile(f.getvalue(), filename=f"generated_qr_code_{username}"),
        caption=f"⛓ لینک Qr code اتصال هوشمند ({username})",
    )


@router.callback_query(
    ProxyPanel.Callback.filter(F.action == ProxyPanelActions.links_allqr)
)
async def generate_qrcode_all(
    query: CallbackQuery, user: User, callback_data: ProxyPanel.Callback
):
    user_id = callback_data.user_id if callback_data.user_id else user.id
    proxy = await Proxy.filter(id=callback_data.proxy_id).first()
    if (user.role < user.Role.admin) and (user.id != user_id):
        return
    elif (user.role == user.Role.admin) and (proxy.user_id != user_id):
        await proxy.fetch_related("user")
        if proxy.user.parent_id != user.id:
            return

    try:
        client = Marzban.get_server(proxy.server_id)
        sv_proxy = await get_user_api_user_username_get.asyncio(
            username=proxy.username, client=client
        )
    except Exception as err:
        await query.answer(
            "❌ خطایی در انجام عملیات رخ داد! لطفا با پشتیبانی تماس بگیرید.",
            show_alert=True,
        )
        raise err
    if not sv_proxy:
        return await query.answer(
            "❌ خطایی در دریافت اطلاعات سرویس رخ داد! لطفا کمی بعد دوباره تلاش کنید.",
            show_alert=True,
        )

    await query.answer("♻️ درحال ساخت و ارسال Qr code. چند لحظه منتظر بمانید...")

    await generate_qr_code(query.message, sv_proxy.links, username=proxy.username)


@router.callback_query(
    ProxyPanel.Callback.filter(F.action == ProxyPanelActions.links_subqr)
)
async def generate_qrcode_sub(
    query: CallbackQuery, user: User, callback_data: ProxyPanel.Callback
):
    user_id = callback_data.user_id if callback_data.user_id else user.id
    proxy = await Proxy.filter(id=callback_data.proxy_id).first()
    if (user.role < user.Role.admin) and (user.id != user_id):
        return
    elif (user.role == user.Role.admin) and (proxy.user_id != user_id):
        await proxy.fetch_related("user")
        if proxy.user.parent_id != user.id:
            return

    try:
        client = Marzban.get_server(proxy.server_id)
        sv_proxy = await get_user_api_user_username_get.asyncio(
            username=proxy.username, client=client
        )
    except Exception as err:
        await query.answer(
            "❌ خطایی در انجام عملیات رخ داد! لطفا با پشتیبانی تماس بگیرید.",
            show_alert=True,
        )
        raise err
    if not sv_proxy:
        return await query.answer(
            "❌ خطایی در دریافت اطلاعات سرویس رخ داد! لطفا کمی بعد دوباره تلاش کنید.",
            show_alert=True,
        )

    await query.answer("♻️ درحال ساخت و ارسال Qr code. چند لحظه منتظر بمانید...")
    await generate_sub_qr_code(
        query.message, sv_proxy.subscription_url, username=proxy.username
    )


@router.callback_query(ProxyPanel.Callback.filter(F.action == ProxyPanelActions.renew))
async def renew_proxy(
    query: CallbackQuery, user: User, callback_data: ProxyPanel.Callback
):
    user_id = callback_data.user_id if callback_data.user_id else user.id
    proxy = await Proxy.filter(id=callback_data.proxy_id).first()
    if (user.role < user.Role.admin) and (user.id != user_id):
        return
    elif (user.role == user.Role.admin) and (proxy.user_id != user_id):
        await proxy.fetch_related("user")
        if proxy.user.parent_id != user.id:
            return

    q = Service.filter(
        server_id=proxy.server_id,
        renewable=True,
        one_time_only=False,
        server__is_enabled=True,
        is_test_service=False,
    )
    if user.role == User.Role.reseller:
        q = q.filter(users_only=False)
    elif user.role == User.Role.user:
        q = q.filter(resellers_only=False)

    available_services = await q.all()
    if not available_services:
        text = """
❗️برای اشتراک مورد نظر امکان تمدید وجود ندارد!
لطفا با پشتیبانی تماس بگیرید.
    """
        return await query.answer(text, show_alert=True)

    text = """
♻️ از این بخش میتونید اشتراک خریداری‌شده خودتون رو تمدید کنید!

برای تمدید اشتراک میتونید یکی از سرویس‌های زیر رو انتخاب کنید:
    """
    await query.message.edit_text(
        text,
        reply_markup=RenewSelectService(
            proxy=proxy,
            services=available_services,
            user_id=callback_data.user_id,
            current_page=callback_data.current_page,
        ).as_markup(),
    )


@router.callback_query(RenewSelectService.Callback.filter())
async def renew_proxy_service(
    query: CallbackQuery, user: User, callback_data: RenewSelectService.Callback
):
    user_id = callback_data.user_id if callback_data.user_id else user.id
    proxy = await Proxy.filter(id=callback_data.proxy_id).first()
    if (user.role < user.Role.admin) and (user.id != user_id):
        return
    elif (user.role == user.Role.admin) and (proxy.user_id != user_id):
        await proxy.fetch_related("user")
        if proxy.user.parent_id != user.id:
            return

    text = """
✅ برای تمدید میتونید یکی از حالت‌های زیر رو انتخاب کنید👇

➖ تمدید آنی: دوره جدید اشتراک شما از همین لحظه محاسبه می‌شود و سرویس جدید برای شما فعال می‌شود.

➖ رزور پلن پشتیبان: پس از اتمام حجم یا دوره اشتراک فعلی، سرویس جدید به طور خودکار فعال می‌شود.

یکی از حالت‌های تمدید رو انتخاب کنید👇
    """
    await query.message.edit_text(
        text,
        reply_markup=RenewSelectMethod(
            proxy=proxy,
            service_id=callback_data.service_id,
            user_id=callback_data.user_id,
            current_page=callback_data.current_page,
        ).as_markup(),
    )


@router.callback_query(RenewSelectMethod.Callback.filter(F.method == RenewMethods.now))
async def renew_proxy_now(
    query: CallbackQuery, user: User, callback_data: RenewSelectMethod.Callback
):
    user_id = callback_data.user_id if callback_data.user_id else user.id
    proxy = await Proxy.filter(id=callback_data.proxy_id).first()
    if (user.role < user.Role.admin) and (user.id != user_id):
        return
    elif (user.role == user.Role.admin) and (proxy.user_id != user_id):
        await proxy.fetch_related("user")
        if proxy.user.parent_id != user.id:
            return

    service = await Service.filter(
        id=callback_data.service_id,
        renewable=True,
        server__is_enabled=True,
        is_test_service=False,
    ).first()
    if not service:
        return await query.answer(
            "❌ خطایی در انجام عملیات رخ داد! لطفا با پشتیبانی تماس بگیرید.",
            show_alert=True,
        )

    price = service.get_price()
    await user.fetch_related("setting")
    if user.setting and (discount_percentage := user.setting.discount_percentage):
        discounted_price = service.get_price(discount_percent=discount_percentage)
    else:
        discounted_price = price

    balance = await user.get_available_credit()

    if callback_data.confirmed:
        if balance < discounted_price:
            return await query.answer(
                "❌ موجودی حساب شما کافی نمی‌باشد!", show_alert=True
            )
        try:
            async with in_transaction():
                await Invoice.create(
                    amount=discounted_price,
                    type=Invoice.Type.renew_now,
                    is_paid=not user.is_postpaid,
                    proxy=proxy,
                    user=user,
                )
                client = Marzban.get_server(service.server_id)
                updated_user = UserModify(
                    expire=helpers.get_expire_timestamp(service.expire_duration),
                    data_limit=service.data_limit,
                )
                sv_proxy = (
                    await reset_user_data_usage_api_user_username_reset_post.asyncio(
                        username=proxy.username, client=client
                    )
                )
                if not sv_proxy:
                    raise ApiUserError("reset data usage didn't return anything!")
                updated_user = UserModify(
                    expire=helpers.get_expire_timestamp(service.expire_duration),
                    data_limit=service.data_limit,
                )
                if service.id != proxy.service_id:
                    proxy.service_id = service.id
                    updated_user.inbounds = UserModifyInbounds.from_dict(
                        service.inbounds
                    )
                    proxies = {}
                    for protocol in service.inbounds:
                        if protocol in sv_proxy.proxies:
                            proxies.update({protocol: sv_proxy.proxies.get(protocol)})
                        else:
                            proxies.update(
                                {protocol: service.create_proxy_protocols(protocol)}
                            )
                    updated_user.proxies = UserModifyProxies.from_dict(proxies)
                sv_proxy = await modify_user_api_user_username_put.asyncio(
                    username=proxy.username,
                    json_body=updated_user,
                    client=client,
                )
                proxy.status = sv_proxy.status.value
                await proxy.save()
                if not sv_proxy:
                    raise ApiUserError("modify user didn't return anything!")
                await query.answer("✅ سرویس شما با موفقیت تمدید شد!", show_alert=True)
                return await show_proxy(
                    query,
                    user,
                    callback_data=Proxies.Callback(
                        proxy_id=proxy.id,
                        user_id=callback_data.user_id,
                        action=ProxiesActions.show_proxy,
                        current_page=callback_data.current_page,
                    ),
                )
        except Exception as err:
            await query.answer(
                "❌ خطایی در انجام عملیات رخ داد! لطفا با پشتیبانی تماس بگیرید.",
                show_alert=True,
            )
            raise err

    text = f"""
🌀 آیا مایل به فعال سازی سرویس زیر برای این پروکسی هستید؟

💎 {service.name}
🕐 مدت زمان: {helpers.hr_time(service.expire_duration, lang="fa") if service.expire_duration else '♾'}
🖥 حجم: {helpers.hr_size(service.data_limit, lang="fa") if service.data_limit else '♾'}
💰 قیمت: {price:,} تومان
"""
    if discounted_price < price:
        text += f"""
~~~~~~~~~~~~~~~~~~~~~~~~
🔥 تخفیف ویژه شما: <code>{discount_percentage}</code> درصد
💰 قیمت با تخفیف: <code>{discounted_price:,}</code> تومان
~~~~~~~~~~~~~~~~~~~~~~~~
"""
    text += f"""
🏦 موجودی حساب شما: {balance:,} تومان
💵 مبلغ قابل پرداخت: {discounted_price:,} تومان
~~~~~~~~~~~~~~~~~~~~~~~~
    """
    if balance >= discounted_price:
        text += "🛍 برای تمدید آنی و فعالسازی سرویس، دکمه زیر را کلیک کنید👇"
        return await query.message.edit_text(
            text,
            reply_markup=ConfirmRenew(
                proxy=proxy,
                service_id=service.id,
                method=RenewMethods.now,
                user_id=callback_data.user_id,
                current_page=callback_data.current_page,
            ).as_markup(),
        )
    text += "😞 موجودی حساب شما برای فعالسازی این سرویس کافی نیست! برای افزایش اعتبار دکمه زیر را کلیک کنید👇"
    return await query.message.edit_text(
        text,
        reply_markup=ConfirmRenew(
            proxy=proxy,
            service_id=service.id,
            method=RenewMethods.now,
            user_id=callback_data.user_id,
            current_page=callback_data.current_page,
            has_balance=False,
        ).as_markup(),
    )

app/handlers/user/proxy.py
govfvck/Marzbot-free
from aiogram import F
from aiogram.types import CallbackQuery, Message
from tortoise.transactions import in_transaction

from app.keyboards.base import MainMenu
from app.keyboards.user.proxy import Proxies, ProxiesActions
from app.keyboards.user.purchase import PurchaseService, Services, ServicesActions
from app.marzban import Marzban
from app.models.proxy import Proxy
from app.models.service import Service
from app.models.user import Invoice, User
from app.utils import helpers
from app.utils.filters import IsJoinedToChannel
from marzban_client.api.user import add_user_api_user_post
from marzban_client.models.user_create import UserCreate
from marzban_client.models.user_create_inbounds import UserCreateInbounds
from marzban_client.models.user_create_proxies import UserCreateProxies

from . import router
from .proxy import show_proxy


async def can_get_test_service(
    user: User, service: Service, query: CallbackQuery
) -> bool:
    if await user.purchased_services.filter(id=service.id).exists():
        await query.answer(
            "❌ شما قبلا یک بار این سرویس را فعال کرده‌اید!", show_alert=True
        )
        return False


@router.message(F.text == MainMenu.purchase, IsJoinedToChannel())
@router.callback_query(Services.Callback.filter(F.action == ServicesActions.show))
async def purchase(qmsg: Message | CallbackQuery, user: User):
    q = Service.filter(server__is_enabled=True, purchaseable=True)
    services = await q.all()
    if not services:
        text = "😢 در حال حاضر سرویسی برای خرید موجود نمی‌باشد!"
        if isinstance(qmsg, CallbackQuery):
            return await qmsg.answer(text, show_alert=True)
        return await qmsg.answer(text)

    text = "📲 در حال حاضر سرویس‌های زیر برای خرید موجود هستند:👇"
    if isinstance(qmsg, CallbackQuery):
        return await qmsg.message.edit_text(
            text, reply_markup=Services(services=services).as_markup()
        )
    await qmsg.answer(
        text,
        reply_markup=Services(services=services).as_markup(),
    )


@router.callback_query(
    Services.Callback.filter(F.action == ServicesActions.show_service)
)
async def show_service(
    query: CallbackQuery, user: User, callback_data: Services.Callback
):
    q = Service.filter(
        server__is_enabled=True, purchaseable=True, id=callback_data.service_id
    )
    service = await q.first()
    if not service:
        await query.answer("❌ سرویس مورد نظر یافت نشد!", show_alert=True)
        return await purchase(query, user)
    if service.is_test_service and not (
        await can_get_test_service(user, service, query)
    ):
        return
    price = service.get_price()
    text = f"""
💎 {service.name}
🕐 مدت زمان: {helpers.hr_time(service.expire_duration, lang="fa") if service.expire_duration else '♾'}
🖥 حجم: {helpers.hr_size(service.data_limit, lang="fa") if service.data_limit else '♾'}
💰 قیمت: {price:,} تومان
"""
    balance = await user.get_balance()
    text += f"""
🏦 اعتبار حساب شما: {balance:,} تومان
💵 مبلغ قابل پرداخت: {price:,} تومان
~~~~~~~~~~~~~~~~~~~~~~~~
    """
    if balance >= price:
        text += "🛍 برای خرید و فعالسازی سرویس، دکمه زیر را کلیک کنید👇"
        return await query.message.edit_text(
            text, reply_markup=PurchaseService(service).as_markup()
        )
    text += "😞 موجودی حساب شما برای فعالسازی این سرویس کافی نیست! برای افزایش اعتبار دکمه زیر را کلیک کنید👇"
    return await query.message.edit_text(
        text, reply_markup=PurchaseService(service, has_balance=False).as_markup()
    )


@router.callback_query(PurchaseService.Callback.filter())
async def purchase_service(
    query: CallbackQuery, user: User, callback_data: PurchaseService.Callback
):
    q = Service.filter(
        server__is_enabled=True, purchaseable=True, id=callback_data.service_id
    )
    service = await q.first()

    if not service:
        await query.answer("❌ سرویس مورد نظر یافت نشد!", show_alert=True)
        return await purchase(query, user)

    if service.is_test_service and not (
        await can_get_test_service(user, service, query)
    ):
        return

    price = service.get_price()
    balance = await user.get_balance()
    if balance < price:
        return await query.answer(
            "⁉️ اعتبار حساب شما برای فعالسازی این سرویس کافی نیست!"
        )

    try:
        async with in_transaction():
            client = Marzban.get_server(service.server_id)
            user_inbounds = UserCreateInbounds.from_dict(service.inbounds)
            user_proxies = UserCreateProxies.from_dict(
                {
                    protocol: service.create_proxy_protocols(protocol)
                    for protocol in service.inbounds
                }
            )
            proxy_obj = UserCreate(
                username=await helpers.generate_proxy_username(user),
                proxies=user_proxies,
                inbounds=user_inbounds,
                data_limit=service.data_limit,
                expire=helpers.get_expire_timestamp(service.expire_duration),
            )
            sv_proxy = await add_user_api_user_post.asyncio(
                client=client, json_body=proxy_obj
            )
            if not sv_proxy:
                return await query.answer(
                    "❌ خطایی در خرید سرویس رخ داد! لطفا بعدا دوباره تلاش کنید.",
                    show_alert=True,
                )

            proxy = await Proxy.create(
                username=sv_proxy.username,
                service_id=service.id,
                user_id=user.id,
                cost=price,
                server_id=service.server_id,
            )
            await Invoice.create(
                amount=price,
                type=Invoice.Type.purchase,
                proxy=proxy,
                user=user,
            )

            await query.answer(
                f"✅ اشتراک مورد نظر برای شما فعال شد!",
                show_alert=True,
            )
            await show_proxy(
                query,
                user,
                callback_data=Proxies.Callback(
                    proxy_id=proxy.id, action=ProxiesActions.show_proxy
                ),
            )
    except Exception as err:
        await query.answer(
            "❌ خطایی در خرید سرویس رخ داد! لطفا بعدا دوباره تلاش کنید.", show_alert=True
        )
        raise err

app/handlers/user/purchase.py
govfvck/Marzbot-free
from app.logger import get_logger

logger = get_logger("jobs")


from app.jobs import del_unpaid_payments  # noqa

app/jobs/__init__.py
govfvck/Marzbot-free
from datetime import datetime as dt
from datetime import timedelta as td

from tortoise.expressions import Q

from app.jobs import logger
from app.main import scheduler
from app.models.user import Transaction


async def delete_unpaid_payments():
    unpaid_transactions = Transaction.filter(
        ~Q(status=Transaction.Status.finished | Transaction.Status.partially_paid),
        created_at__lt=dt.utcnow() - td(days=14),
    )
    if (count := await unpaid_transactions.count()) < 1:
        return
    logger.info(f"Deleting {count} unpaid transactions...")
    await unpaid_transactions.delete()


scheduler.add_job(
    delete_unpaid_payments,
    "interval",
    hours=24,
    id="delete_unpaid_payments",
    replace_existing=True,
    start_date=dt.utcnow() + td(seconds=10),
)

app/jobs/del_unpaid_payments.py
govfvck/Marzbot-free
from enum import Enum

from aiogram.filters.callback_data import CallbackData
from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder


class AdminPanelAction(str, Enum):
    servers = "servers"
    services = "services"
    users = "users"
    panel = "panel"
    settings = "settings"


class AdminPanel(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="admin"):
        action: AdminPanelAction

    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.button(
            text="Servers", callback_data=self.Callback(action=AdminPanelAction.servers)
        )
        self.button(
            text="Services",
            callback_data=self.Callback(action=AdminPanelAction.services),
        )
        self.button(
            text="Users", callback_data=self.Callback(action=AdminPanelAction.users)
        )
        self.button(
            text="Settings",
            callback_data=self.Callback(action=AdminPanelAction.settings),
        )
        self.adjust(2, 1, 1)


class CancelFormAdmin(ReplyKeyboardBuilder):
    cancel = "cancel"

    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.button(text=self.cancel)


class YesOrNoFormAdmin(ReplyKeyboardBuilder):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.button(text="Yes")
        self.button(text="No")
        self.button(text=CancelFormAdmin.cancel)
        self.adjust(2, 1)

app/keyboards/admin/admin.py
govfvck/Marzbot-free
from enum import Enum

from aiogram.filters.callback_data import CallbackData
from aiogram.utils.keyboard import InlineKeyboardBuilder

from app.models.server import Server

from .admin import AdminPanel, AdminPanelAction


class ServersAction(str, Enum):
    show = "show"
    add_server = "add_server"


class Servers(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="servers"):
        server_id: int = 0
        action: ServersAction

    def __init__(self, servers: list[Server], *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        for server in servers:
            self.button(
                text=f"{server.name} | {server.host}",
                callback_data=self.Callback(
                    server_id=server.id, action=ServersAction.show
                ),
            )
        self.button(
            text="Add Server",
            callback_data=self.Callback(action=ServersAction.add_server),
        )
        self.button(
            text="Back",
            callback_data=AdminPanel.Callback(action=AdminPanelAction.panel),
        )
        self.adjust(1, 1)


class ServerActAction(str, Enum):
    rem = "rem"
    disable = "disable"
    enable = "enable"
    edit = "edit"


class ServerAct(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="srvact"):
        server_id: int
        action: ServerActAction
        confirmed: bool = False

    def __init__(self, server: Server, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.button(
            text="Remove Server",
            callback_data=self.Callback(
                server_id=server.id, action=ServerActAction.rem
            ),
        )
        if server.is_enabled:
            self.button(
                text="Disable Server",
                callback_data=self.Callback(
                    server_id=server.id, action=ServerActAction.disable
                ),
            )
        else:
            self.button(
                text="Enable Server",
                callback_data=self.Callback(
                    server_id=server.id, action=ServerActAction.enable
                ),
            )

        self.button(
            text="Edit Server",
            callback_data=self.Callback(
                server_id=server.id, action=ServerActAction.edit
            ),
        )
        self.button(text="Back", callback_data=AdminPanel.Callback(action="servers"))
        self.adjust(1, 2, 2, 1)


class ConfirmServerAction(InlineKeyboardBuilder):
    def __init__(
        self, server: Server, action: ServerActAction, *args, **kwargs
    ) -> None:
        super().__init__(*args, **kwargs)

        self.button(
            text="confirm",
            callback_data=ServerAct.Callback(
                server_id=server.id, action=action, confirmed=True
            ),
        )
        self.button(
            text=f"Back",
            callback_data=Servers.Callback(
                server_id=server.id, action=ServersAction.show
            ),
        )


class EditServerAction(str, Enum):
    host = "edit_host"
    port = "edit_port"
    token = "edit_token"
    name = "edit_name"
    https = "https"
    save = "save"


class EditServer(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="editsrv"):
        server_id: int
        action: EditServerAction

    def __init__(self, server: Server, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        for action in EditServerAction:
            if not action.value.startswith("edit_"):
                continue
            self.button(
                text=f"Edit {action.name.capitalize()}",
                callback_data=self.Callback(server_id=server.id, action=action),
            )
        self.button(
            text=f"flip HTTPS",
            callback_data=self.Callback(
                server_id=server.id, action=EditServerAction.https
            ),
        )
        self.button(
            text="Save",
            callback_data=self.Callback(
                server_id=server.id, action=EditServerAction.save
            ),
        )
        self.button(
            text=f"Cancel",
            callback_data=Servers.Callback(
                server_id=server.id, action=ServersAction.show
            ),
        )
        self.adjust(2, 2, 1, 1)


# class TemplatesAction(str, Enum):
#     show = "show"
#     add = "add"


# class Templates(InlineKeyboardBuilder):
#     class Callback(CallbackData, prefix="addtmplt"):
#         server_id: int
#         template_id: int = 0
#         action: TemplatesAction

#     def __init__(
#         self, templates: list[UserTemplateResponse], server_id: int, *args, **kwargs
#     ) -> None:
#         super().__init__(*args, **kwargs)
#         for template in templates:
#             self.button(
#                 text=f"{template.id} | {template.name}",
#                 callback_data=self.Callback(
#                     server_id=server_id,
#                     template_id=template.id,
#                     action=TemplatesAction.show,
#                 ),
#             )
#         self.button(
#             text="Add Template",
#             callback_data=self.Callback(
#                 server_id=server_id, action=TemplatesAction.add
#             ),
#         )
#         self.button(
#             text="back",
#             callback_data=Servers.Callback(
#                 server_id=server_id, action=ServersAction.show
#             ),
#         )
#         self.adjust(1, 1, 1)

app/keyboards/admin/server.py
govfvck/Marzbot-free
from enum import Enum

from aiogram.filters.callback_data import CallbackData
from aiogram.utils.keyboard import InlineKeyboardBuilder

from app.models.server import Server
from app.models.service import Service

from .admin import AdminPanel, AdminPanelAction


class ServicesAction(str, Enum):
    show = "show"
    add = "add"
    save_new = "save_new"


class Services(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="services"):
        service_id: int = 0
        action: ServicesAction

    def __init__(self, services: list[Service], *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        for service in services:
            self.button(
                text=f"{service.name}",
                callback_data=self.Callback(
                    service_id=service.id, action=ServicesAction.show
                ),
            )
        self.button(
            text="Add Service",
            callback_data=self.Callback(action=ServicesAction.add),
        )
        self.button(
            text="Back",
            callback_data=AdminPanel.Callback(action=AdminPanelAction.panel),
        )
        self.adjust(1, 1)


class ServiceActAction(str, Enum):
    rem = "rem"
    edit = "edit"
    flip_purchase = "flip_purchase"
    flip_renew = "flip_renew"
    flip_one_time_only = "flip_one_time_only"
    flip_resellers_only = "flip_resellers_only"
    flip_users_only = "flip_users_only"
    flip_is_test_service = "flip_is_test_service"
    cycle_flow = "cycle_flow"


class ServiceAct(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="srviceact"):
        service_id: int
        action: ServiceActAction
        confirmed: bool = False

    def __init__(self, service: Service, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.button(
            text="Remove Service",
            callback_data=self.Callback(
                service_id=service.id, action=ServiceActAction.rem
            ),
        )
        self.button(
            text=f"Purchase: {'✅' if service.purchaseable else '❌'}",
            callback_data=self.Callback(
                service_id=service.id, action=ServiceActAction.flip_purchase
            ),
        )
        self.button(
            text=f"Renew: {'✅' if service.renewable else '❌'}",
            callback_data=self.Callback(
                service_id=service.id, action=ServiceActAction.flip_renew
            ),
        )
        self.button(
            text=f"One time only: {'✅' if service.one_time_only else '❌'}",
            callback_data=self.Callback(
                service_id=service.id, action=ServiceActAction.flip_one_time_only
            ),
        )
        self.button(
            text=f"Test service: {'✅' if service.is_test_service else '❌'}",
            callback_data=self.Callback(
                service_id=service.id, action=ServiceActAction.flip_is_test_service
            ),
        )
        self.button(
            text=f"flow: {service.flow}",
            callback_data=self.Callback(
                service_id=service.id, action=ServiceActAction.cycle_flow
            ),
        )
        self.button(
            text="Edit Service",
            callback_data=self.Callback(
                service_id=service.id, action=ServiceActAction.edit
            ),
        )
        self.button(
            text="Back",
            callback_data=AdminPanel.Callback(action=AdminPanelAction.services),
        )
        self.adjust(1, 2, 2, 1)


class ConfirmServiceAction(InlineKeyboardBuilder):
    def __init__(
        self, service: Service, action: ServiceActAction, *args, **kwargs
    ) -> None:
        super().__init__(*args, **kwargs)

        self.button(
            text="confirm",
            callback_data=ServiceAct.Callback(
                service_id=service.id, action=action, confirmed=True
            ),
        )
        self.button(
            text=f"Back",
            callback_data=Services.Callback(
                service_id=service.id, action=ServicesAction.show
            ),
        )


class SelectServer(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="slctsrv"):
        server_id: int

    def __init__(self, servers: list[Server], *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        for server in servers:
            self.button(
                text=f"{server.name} | {server.host}",
                callback_data=self.Callback(server_id=server.id),
            )
        self.button(
            text="cancel",
            callback_data=AdminPanel.Callback(action=AdminPanelAction.services),
        )
        self.adjust(1, 1)


class SelectInbounds(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="slctinbnd"):
        server_id: int
        protocol: str
        inbound: str | None = None
        for_edit: bool = False
        service_id: int | None = None

    def __init__(
        self,
        inbounds: dict[str, list[str]],
        selected_inbounds: dict[str, list[str]],
        server_id: int,
        for_edit: bool = False,
        service_id: int = None,
        *args,
        **kwargs,
    ) -> None:
        super().__init__(*args, **kwargs)
        for protocol, protocol_inbounds in inbounds.items():
            if protocol in selected_inbounds:
                self.button(
                    text=f"✅ {protocol.upper()}",
                    callback_data=self.Callback(
                        server_id=server_id,
                        protocol=protocol,
                        for_edit=for_edit,
                        service_id=service_id,
                    ),
                )
                for inbound in protocol_inbounds:
                    self.button(
                        text=f"{'✅' if inbound in selected_inbounds[protocol] else '❌'} {inbound}",
                        callback_data=self.Callback(
                            server_id=server_id,
                            protocol=protocol,
                            inbound=inbound,
                            for_edit=for_edit,
                            service_id=service_id,
                        ),
                    )
            else:
                self.button(
                    text=f"❌ {protocol}",
                    callback_data=self.Callback(
                        server_id=server_id,
                        protocol=protocol,
                        for_edit=for_edit,
                        service_id=service_id,
                    ),
                )
        self.button(
            text="Save",
            callback_data=Services.Callback(
                server_id=server_id, action=ServicesAction.save_new
            )
            if not for_edit
            else ServiceAct.Callback(
                service_id=service_id, action=ServiceActAction.edit
            ),
        )
        self.button(
            text="cancel",
            callback_data=AdminPanel.Callback(action=AdminPanelAction.services),
        )
        self.adjust(1, 1, 1)


class EditServiceAction(str, Enum):
    data_limit = "edit_data_lmit"
    expire_duration = "edit_expire_duration"
    price = "edit_price"
    name = "edit_name"
    inbounds = "edit_inbounds"
    save_inbounds = "save_inbounds"
    save = "save"


class EditService(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="editsrvic"):
        service_id: int
        action: EditServiceAction

    def __init__(self, service: Service, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        for action in EditServiceAction:
            if not action.value.startswith("edit_"):
                continue
            self.button(
                text=f"Edit {action.name.capitalize()}",
                callback_data=self.Callback(service_id=service.id, action=action),
            )
        self.button(
            text="Save",
            callback_data=self.Callback(
                service_id=service.id, action=EditServiceAction.save
            ),
        )
        self.button(
            text=f"Cancel",
            callback_data=Services.Callback(
                service_id=service.id, action=ServicesAction.show
            ),
        )
        self.adjust(1, 1, 2, 1, 1)

app/keyboards/admin/service.py
govfvck/Marzbot-free
from enum import Enum

from aiogram.filters.callback_data import CallbackData
from aiogram.utils.keyboard import InlineKeyboardBuilder

from .admin import AdminPanel, AdminPanelAction


class SettingsActions(str, Enum):
    flip_access_only = "access_only"
    flip_referral_system = "referral_system"
    flip_payment_crypto = "payment_crypto"
    flip_payment_card_to_card = "payment_card_to_card"
    flip_payment_perfect_money = "payment_perfect_money"
    flip_payment_rial_gateway = "payment_rial_gateway"


class SettingsKeyboard(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="setngs"):
        action: SettingsActions
        confirmed: bool = False

    def __init__(self, settings: dict[str, bool], *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.button(
            text=f"Access Only: {'✅' if settings.get('BOT:ACCESS_ONLY') else '❌'}",
            callback_data=self.Callback(action=SettingsActions.flip_access_only),
        )
        self.button(
            text=f"Crypto Payment: {'✅' if settings.get('PAYMENT:CRYPTO') else '❌'}",
            callback_data=self.Callback(action=SettingsActions.flip_payment_crypto),
        )
        self.button(
            text="Back",
            callback_data=AdminPanel.Callback(action=AdminPanelAction.panel),
        )
        self.adjust(1, 1)


class ConfirmSettings(InlineKeyboardBuilder):
    def __init__(self, action: SettingsActions, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.button(
            text="Confirm",
            callback_data=SettingsKeyboard.Callback(action=action, confirmed=True),
        )

        self.button(
            text="Cancel",
            callback_data=AdminPanel.Callback(action=AdminPanelAction.settings),
        )
        self.adjust(1, 1)

app/keyboards/admin/setting.py
govfvck/Marzbot-free
from enum import Enum

from aiogram.filters.callback_data import CallbackData
from aiogram.utils.keyboard import InlineKeyboardBuilder

from app.models.user import User

from ..user import proxy
from .admin import AdminPanel, AdminPanelAction


class Users(InlineKeyboardBuilder):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.button(
            text="Back",
            callback_data=AdminPanel.Callback(action=AdminPanelAction.panel),
        )
        self.adjust(1, 1)


class ManageUserAction(str, Enum):
    discount_percent = "discount_percent"


class ManageUser(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="admmngusr"):
        user_id: int
        action: ManageUserAction

    def __init__(
        self,
        user: User,
        *args,
        **kwargs,
    ) -> None:
        super().__init__(*args, **kwargs)
        self.button(
            text=f"پروکسی‌ها",
            callback_data=proxy.Proxies.Callback(
                user_id=user.id,
                action=proxy.ProxiesActions.show,
                current_page=0,
            ),
        )
        self.adjust(1, 1)

app/keyboards/admin/user.py
govfvck/Marzbot-free
from aiogram.filters.callback_data import CallbackData
from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder

import config


class MainMenu(ReplyKeyboardBuilder):
    proxies = "📍 اشتراک‌های من"
    purchase = "🚀 خرید اشتراک"
    account = "💎 حساب من"
    charge = "💰 شارژ حساب"
    help = "🗒 راهنما"
    support = "☑️ پشتیبانی"
    faq = "❓ سوالات متداول"
    back = "🔙 برگشت"
    cancel = "🚫 لغو"
    main_menu = "📱 منوی اصلی"

    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.button(text=self.purchase)
        self.button(text=self.proxies)
        self.button(text=self.account)
        self.button(text=self.charge)
        self.button(text=self.help)
        self.button(text=self.support)
        self.adjust(1, 3, 2)


class CancelUserForm(ReplyKeyboardBuilder):
    def __init__(self, cancel: bool = False, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        if cancel:
            self.button(text=MainMenu.cancel)
        else:
            self.button(text=MainMenu.back)
        self.button(text=MainMenu.main_menu)
        self.adjust(1, 1)


class ForceJoin(InlineKeyboardBuilder):
    check = "✅ بررسی عضویت"

    class Callback(CallbackData, prefix="check_force_join"):
        pass

    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        for _, username in config.FORCE_JOIN_CHATS.items():
            self.button(text=f"🆔 @{username}", url=f"https://t.me/{username}")
        self.button(text=self.check, callback_data=self.Callback())
        self.adjust(1, 1)

app/keyboards/base.py
govfvck/Marzbot-free
from enum import Enum

from aiogram.filters.callback_data import CallbackData
from aiogram.utils.keyboard import InlineKeyboardBuilder

from app.keyboards.user import proxy
from app.models.user import User


class UserPanelAction(str, Enum):
    show = "show"
    charge = "charge"
    proxies = "proxies"
    settings = "settings"


class UserPanel(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="account"):
        action: UserPanelAction

    def __init__(self, user: User, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.button(
            text="💳 شارژ حساب",
            callback_data=self.Callback(action=UserPanelAction.charge),
        )
        self.button(
            text="📍 اشتراک‌های من",
            callback_data=self.Callback(action=UserPanelAction.proxies),
        )
        self.adjust(1, 1)

app/keyboards/user/account.py
govfvck/Marzbot-free
from enum import Enum

from aiogram.filters.callback_data import CallbackData
from aiogram.utils.keyboard import InlineKeyboardBuilder

import config
from app.keyboards.user.account import UserPanel, UserPanelAction

# from app.models.user import TrxSwapPayment


class ChargeMethods(str, Enum):
    crypto = "crypto"
    perfectmoney = "perfectmoney"
    card_to_card = "card_to_card"
    rial_gateway = "rial_gateway"


class ChargePanel(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="payment"):
        method: ChargeMethods

    def __init__(self, settings: dict[str, bool], *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        if settings.get("PAYMENT:CRYPTO"):
            self.button(
                text="💸 ارز دیجیتال",
                callback_data=self.Callback(method=ChargeMethods.crypto),
            )
        self.adjust(1, 1, 1)


class SelectPayAmount(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="payslctam"):
        amount: int
        free: int = 0
        method: ChargeMethods

    def __init__(self, method: ChargeMethods, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        amount_list = [
            20_000,
            50_000,
            75_000,
            95_000,
            130_000,
            195_000,
            275_000,
            330_000,
            400_000,
            600_000,
        ]
        for amount in amount_list:
            free = int(
                0
                if (not config.PAYMENTS_DISCOUNT_ON)
                or (amount < config.PAYMENTS_DISCOUNT_ON)
                else amount * (config.PAYMENTS_DISCOUNT_ON_PERCENT / 100)
            )
            self.button(
                text=f"{amount:,} تومان"
                if not free
                else f"{free:,} 🔥 + {amount:,} تومان",
                callback_data=self.Callback(amount=amount, free=free, method=method),
            )
        self.button(
            text="✍️ مبلغ دلخواه",
            callback_data=self.Callback(amount=0, method=method),
        )

        self.button(
            text="🔙 برگشت",
            callback_data=UserPanel.Callback(action=UserPanelAction.charge),
        )
        self.adjust(2, 2, 2, 2, 1, 1, 1)


class PayCryptoUrl(InlineKeyboardBuilder):
    def __init__(self, url: str, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.button(text="💳 پرداخت", url=url)

app/keyboards/user/payment.py
govfvck/Marzbot-free
from enum import Enum

from aiogram.filters.callback_data import CallbackData
from aiogram.utils.keyboard import InlineKeyboardBuilder

from app.keyboards.user import account
from app.models.proxy import Proxy, ProxyStatus
from app.models.service import Service

PROXY_STATUS = {
    ProxyStatus.active: "✅",
    ProxyStatus.disabled: "❌",
    ProxyStatus.limited: "🔒",
    ProxyStatus.expired: "⏳",
}


class ProxiesActions(str, Enum):
    show = "show"
    show_proxy = "show_proxy"
    cycle_sort = "cycle_sort"


class Proxies(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="prxss"):
        proxy_id: int = 0
        user_id: int | None = None
        parent_id: int | None = None
        action: ProxiesActions
        current_page: int = 0

    def __init__(
        self,
        proxies: list[Proxy],
        user_id: int | None = None,
        parent_id: int | None = None,
        current_page: int = 0,
        next_page: bool = False,
        prev_page: bool = False,
        *args,
        **kwargs,
    ) -> None:
        """proxies should have 'proxy.server' prefetched"""
        super().__init__(*args, **kwargs)
        for proxy in proxies:
            self.button(
                text=f"{PROXY_STATUS.get(proxy.status)} {proxy.custom_name or proxy.service.display_name} ({proxy.username})",
                callback_data=self.Callback(
                    proxy_id=proxy.id,
                    user_id=user_id,
                    action=ProxiesActions.show_proxy,
                ),
            )
        if prev_page:
            self.button(
                text="⬅️ صفحه قبل",
                callback_data=self.Callback(
                    user_id=user_id,
                    parent_id=parent_id,
                    action=ProxiesActions.show,
                    current_page=current_page - 1,
                ),
            )
        if next_page:
            self.button(
                text="➡️ صفحه بعد",
                callback_data=self.Callback(
                    user_id=user_id,
                    parent_id=parent_id,
                    action=ProxiesActions.show,
                    current_page=current_page + 1,
                ),
            )
        self.adjust(*[1 for _ in range(11)], 2)


class ProxyPanelActions(str, Enum):
    links = "links"
    reset_password = "reset_password"
    reset_uuid = "reset_uuid"
    reset_subscription = "reset_subscription"
    renew = "renew"
    set_name = "set_name"
    remove = "remove"
    links_allqr = "allqr"
    links_subqr = "subqr"


class ProxyPanel(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="prxpnl"):
        proxy_id: int
        user_id: int | None = None
        current_page: int = 0
        action: ProxyPanelActions
        confirmed: bool = False

    def __init__(
        self,
        proxy: Proxy,
        user_id: int | None = None,
        current_page: int = 0,
        renewable: bool = True,
        *args,
        **kwargs,
    ) -> None:
        super().__init__(*args, **kwargs)
        if proxy.status == ProxyStatus.active:
            self.button(
                text="🔗 دریافت لینک‌های اتصال",
                callback_data=self.Callback(
                    proxy_id=proxy.id,
                    user_id=user_id,
                    current_page=current_page,
                    action=ProxyPanelActions.links,
                ),
            )
            self.button(
                text="🔑 تغییر پسوورد",
                callback_data=self.Callback(
                    proxy_id=proxy.id,
                    user_id=user_id,
                    current_page=current_page,
                    action=ProxyPanelActions.reset_password,
                ),
            )
        else:
            self.button(
                text="🗑 حذف از لیست اشتراک‌های من",
                callback_data=self.Callback(
                    proxy_id=proxy.id,
                    user_id=user_id,
                    current_page=current_page,
                    action=ProxyPanelActions.remove,
                ),
            )
        if renewable:
            self.button(
                text="♻️ تمدید سرویس",
                callback_data=self.Callback(
                    proxy_id=proxy.id,
                    user_id=user_id,
                    current_page=current_page,
                    action=ProxyPanelActions.renew,
                ),
            )
        self.button(
            text="🔙 برگشت",
            callback_data=Proxies.Callback(
                user_id=user_id,
                action=ProxiesActions.show,
                current_page=current_page,
            ),
        )
        if proxy.status == ProxyStatus.active:
            self.adjust(1, 2, 1, 1)
        else:
            self.adjust(1, 1, 1)


class ResetPassword(InlineKeyboardBuilder):
    def __init__(
        self,
        proxy_id: int,
        user_id: int | None = None,
        current_page: int = 0,
        *args,
        **kwargs,
    ) -> None:
        super().__init__(*args, **kwargs)
        self.button(
            text="🔑 تغییر پسوورد",
            callback_data=ProxyPanel.Callback(
                proxy_id=proxy_id,
                user_id=user_id,
                current_page=current_page,
                action=ProxyPanelActions.reset_uuid,
            ),
        )
        self.button(
            text="🔑 تغییر اتصال هوشمند",
            callback_data=ProxyPanel.Callback(
                proxy_id=proxy_id,
                user_id=user_id,
                current_page=current_page,
                action=ProxyPanelActions.reset_subscription,
            ),
        )
        self.button(
            text=f"🔙 لغو",
            callback_data=Proxies.Callback(
                proxy_id=proxy_id,
                user_id=user_id,
                action=ProxiesActions.show_proxy,
                current_page=current_page,
            ),
        )
        self.adjust(1, 1)


class ConfirmProxyPanel(InlineKeyboardBuilder):
    def __init__(
        self,
        action: ProxyPanelActions,
        proxy_id: int,
        user_id: int = None,
        current_page: int = 0,
    ) -> None:
        super().__init__()
        self.button(
            text="⚠️ تأیید",
            callback_data=ProxyPanel.Callback(
                proxy_id=proxy_id,
                user_id=user_id,
                current_page=current_page,
                action=action,
                confirmed=True,
            ),
        )

        self.button(
            text=f"🔙 لغو",
            callback_data=Proxies.Callback(
                proxy_id=proxy_id,
                user_id=user_id,
                action=ProxiesActions.show_proxy,
                current_page=current_page,
            ),
        )
        self.adjust(1, 1)


class ProxyLinks(InlineKeyboardBuilder):
    def __init__(
        self,
        proxy: Proxy,
        user_id: int | None = None,
        current_page: int = 0,
        *args,
        **kwargs,
    ) -> None:
        super().__init__(*args, **kwargs)
        self.button(
            text="📱 Qr Code",
            callback_data=ProxyPanel.Callback(
                proxy_id=proxy.id,
                user_id=user_id,
                current_page=current_page,
                action=ProxyPanelActions.links_allqr,
            ),
        )
        self.button(
            text="📱 Qr Code اتصال هوشمند",
            callback_data=ProxyPanel.Callback(
                proxy_id=proxy.id,
                user_id=user_id,
                current_page=current_page,
                action=ProxyPanelActions.links_subqr,
            ),
        )
        self.button(
            text=f"🔙 برگشت",
            callback_data=Proxies.Callback(
                proxy_id=proxy.id,
                user_id=user_id,
                action=ProxiesActions.show_proxy,
                current_page=current_page,
            ),
        )
        self.adjust(1, 1, 1)


class RenewSelectService(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="rnwsrvs"):
        proxy_id: int
        service_id: int
        user_id: int | None = None
        current_page: int = 0

    def __init__(
        self,
        proxy: Proxy,
        services: list[Service],
        user_id: int | None = None,
        current_page: int = 0,
        *args,
        **kwargs,
    ) -> None:
        super().__init__(*args, **kwargs)
        for service in services:
            self.button(
                text=service.display_name,
                callback_data=self.Callback(
                    proxy_id=proxy.id,
                    service_id=service.id,
                    user_id=user_id,
                    current_page=current_page,
                ),
            )
        self.button(
            text=f"🔙 برگشت",
            callback_data=Proxies.Callback(
                proxy_id=proxy.id,
                user_id=user_id,
                action=ProxiesActions.show_proxy,
                current_page=current_page,
            ),
        )
        self.adjust(1, 1, 1, 1)


class RenewMethods(str, Enum):
    now = "now"


class RenewSelectMethod(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="rnwmethod"):
        proxy_id: int
        service_id: int
        user_id: int | None = None
        current_page: int = 0
        method: RenewMethods
        confirmed: bool = False

    def __init__(
        self,
        proxy: Proxy,
        service_id: int,
        user_id: int | None = None,
        current_page: int = 0,
        *args,
        **kwargs,
    ) -> None:
        super().__init__(*args, **kwargs)
        self.button(
            text="♻️ تمدید آنی اشتراک",
            callback_data=self.Callback(
                proxy_id=proxy.id,
                service_id=service_id,
                user_id=user_id,
                current_page=current_page,
                method=RenewMethods.now,
            ),
        )
        self.button(
            text=f"🔙 برگشت",
            callback_data=Proxies.Callback(
                proxy_id=proxy.id,
                user_id=user_id,
                action=ProxiesActions.show_proxy,
                current_page=current_page,
            ),
        )
        self.adjust(1, 1, 1)


class ConfirmRenew(InlineKeyboardBuilder):
    def __init__(
        self,
        proxy: Proxy,
        service_id: int,
        method: RenewMethods,
        user_id: int | None = None,
        current_page: int = 0,
        has_balance: bool = True,
        *args,
        **kwargs,
    ) -> None:
        super().__init__(*args, **kwargs)
        if has_balance:
            self.button(
                text="✅ فعالسازی",
                callback_data=RenewSelectMethod.Callback(
                    proxy_id=proxy.id,
                    service_id=service_id,
                    user_id=user_id,
                    current_page=current_page,
                    method=method,
                    confirmed=True,
                ),
            )
        else:
            self.button(
                text="💳 افزایش موجودی",
                callback_data=account.UserPanel.Callback(
                    action=account.UserPanelAction.charge
                ),
            )
        self.button(
            text="🔙 برگشت",
            callback_data=RenewSelectService.Callback(
                proxy_id=proxy.id,
                service_id=service_id,
                user_id=user_id,
                current_page=current_page,
            ),
        )
        self.adjust(1, 1)

app/keyboards/user/proxy.py
govfvck/Marzbot-free
from enum import Enum

from aiogram.filters.callback_data import CallbackData
from aiogram.utils.keyboard import InlineKeyboardBuilder

from app.keyboards.user.account import UserPanel, UserPanelAction
from app.models.service import Service


class ServicesActions(str, Enum):
    show = "show"
    show_service = "show_service"
    purchase = "purchase"


class Services(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="servicss"):
        service_id: int = 0
        action: ServicesActions

    def __init__(self, services: list[Service], *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        for service in services:
            self.button(
                text=service.display_name,
                callback_data=self.Callback(
                    service_id=service.id, action=ServicesActions.show_service
                ),
            )
        self.adjust(1, 1, 1)


class PurchaseService(InlineKeyboardBuilder):
    class Callback(CallbackData, prefix="prchssrv"):
        service_id: int = 0

    def __init__(
        self, service: Service, has_balance: bool = True, *args, **kwargs
    ) -> None:
        super().__init__(*args, **kwargs)
        if has_balance:
            self.button(
                text="🛒 خرید سرویس", callback_data=self.Callback(service_id=service.id)
            )
        else:
            self.button(
                text="💳 افزایش موجودی",
                callback_data=UserPanel.Callback(action=UserPanelAction.charge),
            )
        self.button(
            text="🔙 برگشت", callback_data=Services.Callback(action=ServicesActions.show)
        )
        self.adjust(1, 1)

app/keyboards/user/purchase.py
govfvck/Marzbot-free
import logging
import os

LOG_LEVEL = os.getenv("LOG_LEVEL", "info").upper()
print(LOG_LEVEL)
handler = logging.StreamHandler()
handler.setLevel(LOG_LEVEL)
formatter = logging.Formatter(fmt="%(levelname)s:%(name)s:%(message)s")
handler.setFormatter(formatter)


def get_logger(name: str) -> logging.Logger:
    logger = logging.getLogger(name)
    logger.setLevel(LOG_LEVEL)
    logger.addHandler(handler)
    logger.propagate = False
    return logger


logger_db_client = logging.getLogger("db_client")
logger_db_client.setLevel(LOG_LEVEL)
logger_db_client.addHandler(handler)

logger_tortoise = logging.getLogger("tortoise")
logger_tortoise.setLevel(LOG_LEVEL)
logger_tortoise.addHandler(handler)

app/logger.py
govfvck/Marzbot-free
from aiogram import Bot, Dispatcher
from aiogram.client.session.aiohttp import AiohttpSession
from aiogram.fsm.storage.redis import RedisStorage
from apscheduler.executors.asyncio import AsyncIOExecutor
from apscheduler.jobstores.redis import RedisJobStore
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from redis.asyncio.client import Redis

import config
from app.logger import get_logger

redis = Redis(
    host=config.REDIS_HOST,
    port=config.REDIS_PORT,
    db=config.REDIS_DB,
    decode_responses=True,
)  # because it is used as the fsm_storage, it will be closed automatically on shutdown

storage = RedisStorage(
    redis=redis,
    state_ttl=600,
    data_ttl=600,
)

dp = Dispatcher(storage=storage)
aiohttp_session = AiohttpSession(proxy=config.PROXY)
bot = Bot(token=config.BOT_TOKEN, session=aiohttp_session, parse_mode=config.PARSE_MODE)
bot_username = config.BOT_USERNAME

scheduler = AsyncIOScheduler(
    jobstores={
        "default": RedisJobStore(
            db=config.REDIS_DB, host=config.REDIS_HOST, port=config.REDIS_PORT
        )
    },
    executors={"default": AsyncIOExecutor()},
    job_defaults={
        "coalesce": True,  # Trigger only one job to make up for missed jobs.
        "max_instances": 5,
    },
    timezone="UTC",
)

logger = get_logger("marzbot")


def get_bot_username() -> str:
    return bot_username


async def on_startup():
    global bot_username
    bot_username = (await bot.get_me()).username
    scheduler.start()


async def on_shutdown():
    scheduler.shutdown()


def main() -> None:
    logger.info("Configuring Database...")
    from app.models import setup_database

    setup_database(dp)
    logger.info("DataBase configuration Done!")

    logger.info("Configuring Routers...")
    from app.handlers import include_routers

    include_routers(dp)
    logger.info("Routers included successfully!")

    logger.info("Setting up middlewares...")
    from app.middlewares import setup_middlewares

    setup_middlewares(dp)
    logger.info("Middlewares setup successfully!")

    logger.info("Setting up API servers...")
    from app.marzban import setup_api

    setup_api(dp)
    logger.info("Setup API servers successfully!")

    logger.info("Setting up webapp...")
    from app.views import setup_webapp

    setup_webapp(dp)
    logger.info("Setup webapp successfully!")

    logger.info("Setting up scheduled jobs...")

    dp.startup.register(on_startup)
    dp.shutdown.register(on_shutdown)
    logger.info("Setup scheduled jobs successfully!")

    logger.info("Starting polling for updates...")
    dp.run_polling(bot)

app/main.py
govfvck/Marzbot-free
from aiogram import Dispatcher

from app.models.server import Server
from marzban_client import AuthenticatedClient


class Marzban:
    servers: dict[str, AuthenticatedClient] = dict()

    @classmethod
    def init_servers(cls, servers: list[Server]) -> None:
        for server in servers:
            cls.servers.update(
                {
                    server.id: AuthenticatedClient(
                        base_url=server.url,
                        token=server.token,
                    )
                }
            )

    @classmethod
    async def refresh_servers(cls) -> None:
        """refresh servers from database"""
        servers = await Server.all()
        cls.servers.clear()
        cls.init_servers(servers)

    @classmethod
    async def get_servers(cls) -> list["Marzban"]:
        """get Marzban server instances"""
        return cls.servers

    @classmethod
    def get_server(cls, id: int = None) -> "Marzban":
        if (server := cls.servers.get(id, None)) is None:
            raise KeyError(f"Server with id of '{id}' not found!")
        return server


def setup_api(dp: Dispatcher) -> None:
    dp.startup.register(Marzban.refresh_servers)

app/marzban.py
govfvck/Marzbot-free
from aiogram import Dispatcher

from .acl import ACLMiddleware


def setup_middlewares(dp: Dispatcher) -> None:
    dp.update.outer_middleware(ACLMiddleware())

app/middlewares/__init__.py
govfvck/Marzbot-free
from contextlib import contextmanager
from contextvars import ContextVar
from typing import Any, Awaitable, Callable, Iterator

from aiogram import BaseMiddleware, types

from app.logger import get_logger
from app.models.user import User
from app.utils.settings import Settings

logger = get_logger(__name__)


current_user: ContextVar[User] = ContextVar("current_user", default=None)


class ACLMiddleware(BaseMiddleware):
    """ACL middleware for user setup"""

    async def __call__(
        self,
        handler: Callable[[types.TelegramObject, dict[str, Any]], Awaitable[Any]],
        event: types.TelegramObject,
        data: dict[str, Any],
    ) -> Any:
        logger.debug(f"New event: {event}")
        logger.debug(f"New event data: {data}")
        user: types.User = data["event_from_user"]
        if await self.setup_chat(data, user):
            with self.context(user=data["user"]):
                return await handler(event, data)

    @contextmanager
    def context(self, user: User) -> Iterator[None]:
        """Set current_user context"""
        ctx_token = current_user.set(user)
        logger.debug(f"Setting up user with {user.id=} and {ctx_token=}")
        try:
            yield
        finally:
            logger.debug(f"Resetting user with {user.id=} and {ctx_token=}")
            current_user.reset(ctx_token)

    async def setup_chat(self, data: dict[str, Any], user: types.User) -> User | None:
        db_user = await User.filter(id=user.id).first()
        if not db_user:
            if await Settings.bot_access_only() and not (
                await Settings.user_has_access(user_id=user.id)
            ):
                return
            db_user = await User.create(
                id=user.id, username=user.username, full_name=user.full_name
            )

        update = dict()
        if user.username is not None and user.username != db_user.username:
            update.update({"username": user.username})
        if user.full_name is not None and user.full_name != db_user.name:
            update.update({"name": user.full_name})
        if update:
            await db_user.update_from_dict(update).save()
            await db_user.refresh_from_db()

        data["user"] = db_user
        return db_user

app/middlewares/acl.py
govfvck/Marzbot-free
from aiogram import Dispatcher
from tortoise import Tortoise
from tortoise.fields import DatetimeField
from tortoise.models import Model

import config

db = Tortoise()


class Base(Model):
    class Meta:
        abstract = True


class TimedBase(Base):
    class Meta:
        abstract = True

    created_at = DatetimeField(null=True, auto_now_add=True)
    updated_at = DatetimeField(null=True, auto_now=True)


class CreatedTimeBase(Base):
    class Meta:
        abstract = True

    created_at = DatetimeField(null=True, auto_now_add=True)


async def on_startup():
    await db.init(config=config.TORTOISE_ORM)


async def on_shutdown():
    await db.close_connections()


def setup_database(dp: Dispatcher):
    dp.startup.register(on_startup)
    dp.shutdown.register(on_shutdown)

app/models/__init__.py
govfvck/Marzbot-free
from enum import Enum
from typing import TYPE_CHECKING

from tortoise import fields

from . import TimedBase

if TYPE_CHECKING:
    from .server import Server
    from .service import Service
    from .user import Invoice, User


class ProxyStatus(Enum):
    active = "active"
    disabled = "disabled"
    limited = "limited"
    expired = "expired"


class Proxy(TimedBase):
    class Meta:
        table = "proxies"

    id = fields.IntField(pk=True)
    custom_name = fields.CharField(max_length=64, null=True)
    username = fields.CharField(max_length=32, null=False, index=True, unique=True)
    cost = fields.IntField(null=True)
    status = fields.CharEnumField(
        ProxyStatus, max_length=12, default=ProxyStatus.active
    )
    renewed_at = fields.DatetimeField(null=True)

    service: fields.ForeignKeyNullableRelation["Service"] = fields.ForeignKeyField(
        "models.Service",
        "proxies",
        on_delete=fields.SET_NULL,
        null=True,
    )
    user: fields.ForeignKeyRelation["User"] = fields.ForeignKeyField(
        "models.User",
        "proxies",
        on_delete=fields.CASCADE,
        null=False,
    )
    server: fields.ForeignKeyRelation["Server"] = fields.ForeignKeyField(
        "models.Server",
        "proxies",
        on_delete=fields.CASCADE,
        null=False,
    )

    @property
    def display_name(self):
        if self.custom_name:
            return f"{self.username} ({self.custom_name})"

        if self.service:
            return f"{self.service.name} ({self.username})"
        return f"({self.username})"

app/models/proxy.py
govfvck/Marzbot-free
from tortoise import fields

from . import TimedBase


class Server(TimedBase):
    class Meta:
        table = "servers"

    id = fields.BigIntField(pk=True)
    host = fields.CharField(max_length=64, null=False)  # ip or domain
    port = fields.IntField(null=True)
    token = fields.CharField(max_length=512, null=False)
    https = fields.BooleanField(default=False)

    name = fields.CharField(max_length=200, null=True)

    is_enabled = fields.BooleanField(default=True)

    @property
    def url(self) -> str:
        url = self.host.rstrip("/")
        if self.port:
            url = f"{url}:{self.port}"
        if self.https:
            return f"https://{url}"
        return f"http://{url}"

    @property
    def identifier(self) -> str:
        return self.name if self.name else self.host

app/models/server.py
govfvck/Marzbot-free
from enum import Enum
from typing import TYPE_CHECKING

from tortoise import fields

from app.models import TimedBase

if TYPE_CHECKING:
    from .server import Server
    from .user import User


class Service(TimedBase):
    class Meta:
        table = "services"

    class ServiceProxyFlow(str, Enum):
        none = None
        xtls_rprx_vision = "xtls-rprx-vision"

    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=64, null=False)
    data_limit = fields.BigIntField(null=False)  # in bytes
    expire_duration = fields.IntField(null=False)  # in seconds
    inbounds = fields.JSONField(null=False)
    flow = fields.CharEnumField(
        ServiceProxyFlow, max_length=20, null=True, default=ServiceProxyFlow.none
    )
    price = fields.IntField(null=False)  # in Tomans

    one_time_only = fields.BooleanField(
        default=False
    )  # each user can only buy this once
    is_test_service = fields.BooleanField(
        default=False,  # normal users can get it only once, resellers can get it for config.DEFAULT_DAILY_TEST_SERVICES or user.setting.daily_test_services
    )

    purchaseable = fields.BooleanField(default=False)
    renewable = fields.BooleanField(default=False)

    server: fields.ForeignKeyRelation["Server"] = fields.ForeignKeyField(
        "models.Server",
        "services",
        on_delete=fields.CASCADE,
        null=False,
    )

    purchased_by: fields.ManyToManyRelation["User"] = fields.ManyToManyField(
        "models.User",
        through="user_purchased",
        related_name="purchased_services",
    )

    @property
    def display_name(self):
        if not self.price:
            return self.name
        return f"{self.name} | {self.price:,} تومان"

    def get_price(self) -> int:
        return self.price

    def create_proxy_protocols(self, protocol: str) -> dict[str, str]:
        if protocol == "vless" and self.flow is not None:
            return {"flow": self.flow}
        return {}

app/models/service.py
govfvck/Marzbot-free
from enum import IntEnum
from typing import TYPE_CHECKING

from tortoise import fields
from tortoise.expressions import Subquery
from tortoise.functions import Sum

from . import TimedBase

if TYPE_CHECKING:
    from .proxy import Proxy
    from .service import Service


class User(TimedBase):
    class Meta:
        table = "users"

    id = fields.BigIntField(pk=True)
    username = fields.CharField(max_length=200, null=True)
    name = fields.CharField(max_length=200, null=True)
    is_blocked = fields.BooleanField(default=False)

    super_user = fields.BooleanField(default=False)

    force_join_check = fields.DatetimeField(null=True)

    proxies: fields.ReverseRelation["Proxy"]
    invoices: fields.ReverseRelation["Invoice"]
    transactions: fields.ReverseRelation["Transaction"]
    purchased_services: fields.ManyToManyRelation["Service"]

    async def get_balance(self) -> int:
        q = (  # query to fetch sum of transactions and invoices amount of user
            await self.transactions.filter(status=Transaction.Status.finished)
            .annotate(trx_sum=Sum("amount"))
            .annotate(
                inv_sum=Subquery(
                    self.invoices.filter()
                    .annotate(inv=Sum("amount"))
                    .all()
                    .values_list("inv", flat=True)
                )
            )
            .all()
            .values("trx_sum", "inv_sum")
        )[0]

        return (q.get("trx_sum") or 0) - (q.get("inv_sum") or 0)


class Invoice(TimedBase):
    class Meta:
        table = "invoices"

    class Type(IntEnum):
        purchase = 1
        renew = 2

    id = fields.IntField(pk=True)
    amount = fields.IntField(null=False)
    type = fields.IntEnumField(Type, default=Type.purchase)
    proxy: fields.ForeignKeyNullableRelation["Proxy"] = fields.ForeignKeyField(
        "models.Proxy",
        "invoices",
        on_delete=fields.SET_NULL,
        null=True,
    )
    user: fields.ForeignKeyRelation[User] = fields.ForeignKeyField(
        "models.User",
        "invoices",
        on_delete=fields.CASCADE,
    )
    transaction: fields.ForeignKeyNullableRelation[
        "Transaction"
    ] = fields.ForeignKeyField(
        "models.Transaction",
        "invoices",
        on_delete=fields.SET_NULL,
        null=True,
    )


class Transaction(TimedBase):
    class Meta:
        table = "transactions"

    class PaymentType(IntEnum):
        crypto = 1
        by_admin = 2

    class Status(IntEnum):
        waiting = 1
        failed = 2
        canceled = 3
        partially_paid = 4
        finished = 5

    id = fields.BigIntField(pk=True)
    type = fields.IntEnumField(PaymentType, null=False)
    status = fields.IntEnumField(Status, default=Status.waiting)

    finished_at = fields.DatetimeField(null=True)
    amount = fields.IntField(null=False)
    amount_paid = fields.IntField(null=True)

    user: fields.ForeignKeyRelation["User"] = fields.ForeignKeyField(
        "models.User",
        "transactions",
        on_delete=fields.CASCADE,
        null=False,
    )
    crypto_payment: fields.ReverseRelation["CryptoPayment"]
    byadmin_payment: fields.ReverseRelation["ByAdminPayment"]


class CryptoPayment(TimedBase):
    class Meta:
        table = "crypto_payments"

    class PaymentStatus(IntEnum):
        waiting = 0
        confirming = 1
        confirmed = 2
        sending = 3
        partially_paid = 4
        finished = 5
        failed = 6
        refunded = 7
        expired = 8

    type = fields.IntEnumField(
        Transaction.PaymentType, default=Transaction.PaymentType.crypto
    )
    usdt_rate = fields.IntField()
    invoice_id = fields.CharField(max_length=64)
    order_id = fields.CharField(max_length=64, null=True)
    price_amount = fields.FloatField()
    price_currency = fields.CharField(max_length=20)
    nowpm_created_at = fields.DatetimeField(null=True)

    pay_currency = fields.CharField(max_length=32, null=True)
    pay_amount = fields.FloatField(null=True)
    order_description = fields.CharField(max_length=64, null=True)
    nowpm_updated_at = fields.DatetimeField(null=True)
    payment_status = fields.IntEnumField(PaymentStatus, default=PaymentStatus.waiting)
    outcome_amount = fields.FloatField(null=True)
    outcome_currency = fields.CharField(max_length=20, null=True)
    purchase_id = fields.CharField(max_length=64, null=True)
    pay_address = fields.CharField(max_length=128, null=True)

    transaction: fields.OneToOneRelation[Transaction] = fields.OneToOneField(
        "models.Transaction",
        "crypto_payment",
        on_delete=fields.CASCADE,
        null=False,
    )


class ByAdminPayment(TimedBase):
    class Meta:
        table = "byadmin_payments"

    type = fields.IntEnumField(
        Transaction.PaymentType, default=Transaction.PaymentType.by_admin
    )
    by_admin: fields.ForeignKeyNullableRelation[User] = fields.ForeignKeyField(
        "models.User",
        "balance_transactions",
        on_delete=fields.SET_NULL,
        null=True,
    )

    transaction: fields.OneToOneRelation[Transaction] = fields.OneToOneField(
        "models.Transaction",
        "byadmin_payment",
        on_delete=fields.CASCADE,
        null=False,
    )

app/models/user.py
govfvck/Marzbot-free
from datetime import datetime as dt
from datetime import timedelta as td
from typing import Any

from aiogram.filters import Filter
from aiogram.types import Message

import config
from app.keyboards.base import ForceJoin
from app.main import bot
from app.middlewares.acl import current_user
from app.models.user import User
from app.utils import helpers


class SuperUserAccess(Filter):
    async def __call__(self, message: Message) -> bool:
        return current_user.get().super_user


class IsJoinedToChannel(Filter):
    def __init__(self, send_alert: bool = True) -> None:
        self.send_alert = send_alert

    async def __call__(self, message: Message) -> bool:
        user = current_user.get()
        if user.force_join_check and (
            dt.now() - user.force_join_check.replace(tzinfo=None)
        ) < td(hours=24):
            return True
        if await helpers.check_force_join(user=user):
            return True
        if self.send_alert:
            await bot.send_message(
                user.id, config.FORCE_JOIN_TEXT, reply_markup=ForceJoin().as_markup()
            )
        return False

app/utils/filters.py
govfvck/Marzbot-free
import math
import random
import uuid
from datetime import datetime as dt
from datetime import timedelta as td
from typing import Literal

from jdatetime import datetime as jdt
from pytz import timezone

import config
from app.logger import get_logger
from app.main import bot
from app.models.user import User

logger = get_logger("utils/helpers")

intervals_en = (
    ("months", 2592000),  # 60 * 60 * 24 * 30
    ("days", 86400),  # 60 * 60 * 24
    ("hours", 3600),  # 60 * 60
    ("minutes", 60),
    ("seconds", 1),
)


intervals_fa = (
    ("ماه", 2592000),  # 60 * 60 * 24 * 30
    ("روز", 86400),  # 60 * 60 * 24
    ("ساعت", 3600),  # 60 * 60
    ("دقیقه", 60),
    ("ثانیه", 1),
)


def hr_time(seconds: int, lang: Literal["en", "fa"] = "en", granularity: int = 2):
    """turns seconds into human readable time"""
    if seconds < 0:
        seconds = 0
    result = []

    intervals = intervals_fa if lang == "fa" else intervals_en
    for name, count in intervals:
        value = seconds // count
        if value:
            seconds -= value * count
            if value == 1 and lang == "en":
                name = name.rstrip("s")
            result.append(f"{int(value)} {name}")
    return " و ".join(result[:granularity])


def hr_date(timestamp: int, format: str = "%Y/%m/%d %H:%M") -> str:
    return jdt.fromtimestamp(timestamp, tz=timezone("Asia/Tehran")).strftime(format)


def get_until_expires(expire_timestamp: int, lang: Literal["en", "fa"] = "en") -> str:
    return hr_time(expire_timestamp - dt.now().timestamp(), lang=lang)


size_names_en = (
    "B",
    "KB",
    "MB",
    "GB",
    "TB",
    "PB",
    "EB",
    "ZB",
    "YB",
)
size_names_fa = (
    "بایت",
    "کیلوبایت",
    "مگابایت",
    "گیگابایت",
    "ترابایت",
    "پتابایت",
    "اگزابایت",
    "زتابایت",
    "یوتابایت",
)


def hr_size(size_bytes: int, lang: Literal["en", "fa"] = "en"):
    size_names = size_names_fa if lang == "fa" else size_names_en
    if size_bytes <= 0:
        return "0"
    size_index = int(math.floor(math.log(size_bytes, 1024)))
    size = round(size_bytes / math.pow(1024, size_index), 2)
    return f"{size:g} {size_names[size_index]}"


async def check_username_exists(username: str) -> bool:
    return await User.filter(username=username).exists()


def generate_random_text(min_length: int = 4, max_length: int = 8) -> str:
    return (str(uuid.uuid4())[: random.randint(min_length, max_length)]).replace(
        "-", ""
    )


async def generate_proxy_username(user: User, max_length: int = 32) -> str:
    username = config.DEFAULT_USERNAME_PREFIX
    if not username.endswith("_"):
        username += "_"
    username += generate_random_text()

    if username.endswith("_"):
        return username[:-1]

    if await check_username_exists(username):
        return await generate_proxy_username(user, max_length)
    return username


def get_expire_timestamp(expire_duration: int) -> int:
    return int((dt.today() + td(seconds=expire_duration)).timestamp())


async def check_force_join(user: User) -> bool:
    for channel_id in config.FORCE_JOIN_CHATS:
        try:
            if (await bot.get_chat_member(channel_id, user.id)).status == "left":
                return False
        except Exception as err:
            logger.error(f"Error checking force_join: {err}")

    user.force_join_check = dt.now()
    await user.save()
    return True

app/utils/helpers.py
govfvck/Marzbot-free
import config
from app.logger import get_logger
from app.main import bot
from app.models.user import CryptoPayment

logger = get_logger("payment_logs")


async def send_perfect_money_log(
    user_id: int,
    ev_number: int,
    ev_code: int,
    ev_amount: int,
    ev_amount_currency: str,
    payee_account: str,
    payment_batch_number: str,
    toman_amount: int,
    user_balance_before: int,
    user_balance_after: int,
) -> None:
    logger.info(
        f"Perfectmoney Payment Log [{user_id}]: {ev_number=}, "
        f"{ev_code=}, "
        f"{ev_amount=}, "
        f"{ev_amount_currency=}, "
        f"{payee_account=}, "
        f"{payment_batch_number=}, "
        f"{toman_amount=}"
        f"{user_balance_before=}, "
        f"{user_balance_after=}"
    )
    text = f"""
#perfectmoney #payment


user_id: <code>{user_id}</code>
ev number: <code>{ev_number}</code>
ev code: <code>{ev_code}</code>
ev currency: <b>{ev_amount_currency}</b>
payee account: <code>{payee_account}</code>
payment batch number: <code>{payment_batch_number}</code>
amound in tomans: <b>{toman_amount}</b>
user balance before: <b>{user_balance_before}</b>
user balance after: <b>{user_balance_after}</b>
    """
    await bot.send_message(config.TRANSACTION_LOGS, text)


async def send_crypto_payment_log(db_payment: CryptoPayment) -> None:
    text = f"""
#crypto #payment #{db_payment.coin}

user_id: <code>{db_payment.user_id}</code>
id: <code>{db_payment.id}</code>
usd rate: <code>{db_payment.usd_rate}</code>
payment_id: <code>{db_payment.usd_rate}</code>
payment_status: <code>{db_payment.payment_status}</code>
pay_address: <code>{db_payment.pay_address}</code>
price_amount: <code>{db_payment.price_amount}</code>
pay_amount: <code>{db_payment.pay_amount}</code>
purchase_id: <code>{db_payment.purchase_id}</code>
amount_received: <code>{db_payment.amount_received}</code>
outcome_amount: <code>{db_payment.outcome_amount}</code>
outcome_currency: <code>{db_payment.outcome_currency}</code>
    """
    await bot.send_message(config.TRANSACTION_LOGS, text)

app/utils/logs.py
govfvck/Marzbot-free
from typing import Iterable

import config
from app.main import redis


class Settings:
    @classmethod
    async def _get(cls, key: str) -> tuple[bool, bool]:
        """Returns value of a settings field

        Args:
            key (str): settings key

        Returns:
            tuple[bool, bool]: first value is the result and second one is the True if it's fetched from redis
        """
        if (res := await redis.get(f"SETTINGS:{key}")) is not None:
            return bool(int(res)), True
        return config.SETTINGS.get(key), False

    @classmethod
    async def _set(cls, key: str, value: bool) -> bool | None:
        """Sets value of a settings field

        Args:
            key (str): settings key

        Returns:
            bool | None:  result of redis.set
        """
        return await redis.set(f"SETTINGS:{key}", int(value))

    @classmethod
    async def bot_access_only(cls) -> bool:
        return (await cls._get("BOT:ACCESS_ONLY"))[0]

    @classmethod
    async def set_bot_access_only(cls, value: bool) -> None:
        await cls._set("BOT:ACCESS_ONLY", value)

    @classmethod
    async def user_has_access(cls, user_id: int | str) -> bool:
        return bool((await redis.smismember("SETTINGS:HAS_ACCESS_USERS", [user_id]))[0])

    @classmethod
    async def give_user_access(cls, user_id: int | str) -> int:
        return await redis.sadd("SETTINGS:HAS_ACCESS_USERS", user_id)

    @classmethod
    async def remove_user_access(cls, user_id: int | str) -> int:
        return await redis.srem("SETTINGS:HAS_ACCESS_USERS", user_id)

    @classmethod
    async def bot_referral_system(cls) -> bool:
        return (await cls._get("BOT:REFERRAL_SYSTEM"))[0]

    @classmethod
    async def set_bot_referral_system(cls, value: bool) -> None:
        await cls._set("BOT:REFERRAL_SYSTEM", value)

    # payment settings
    @classmethod
    async def payment_crypto(cls) -> bool:
        return (await cls._get("PAYMENT:CRYPTO"))[0]

    @classmethod
    async def set_payment_crypto(cls, value: bool) -> None:
        await cls._set("PAYMENT:CRYPTO", value)

    @classmethod
    async def payment_card_to_card(cls) -> bool:
        return (await cls._get("PAYMENT:CARD_TO_CARD"))[0]

    @classmethod
    async def set_payment_card_to_card(cls, value: bool) -> None:
        await cls._set("PAYMENT:CARD_TO_CARD", value)

    @classmethod
    async def payment_rial_gateway(cls) -> bool:
        return (await cls._get("PAYMENT:RIAL_GATEWAY"))[0]

    @classmethod
    async def set_payment_rial_gateway(cls, value: bool) -> None:
        await cls._set("PAYMENT:RIAL_GATEWAY", value)

    @classmethod
    async def payment_perfect_money(cls) -> bool:
        return (await cls._get("PAYMENT:PERFECT_MONEY"))[0]

    @classmethod
    async def set_payment_perfect_money(cls, value: bool) -> None:
        await cls._set("PAYMENT:PERFECT_MONEY", value)

    @classmethod
    async def _get_settings(cls, keys: Iterable[str]) -> dict[str, bool]:
        """Update Settings values and return

        Returns:
            dict[str, bool]: returns a copy of settings dict in config.SETTINGS with updated values from redis db
        """
        setts = dict()
        for key in keys:
            setts[key], _ = await cls._get(key)
        return setts

    @classmethod
    async def settings(cls) -> dict[str, bool]:
        return await cls._get_settings(keys=config.SETTINGS.keys())

    @classmethod
    async def payment_settings(cls) -> dict[str, bool]:
        return await cls._get_settings(
            keys=[key for key in config.SETTINGS.keys() if key.startswith("PAYMENT:")]
        )

    @classmethod
    async def reset_to_default_settings(cls) -> None:
        """Deletes all saved settings from redis db"""
        await redis.delete(*[f"SETTINGS:{key}" for key in config.SETTINGS])

app/utils/settings.py
govfvck/Marzbot-free
from aiogram import Dispatcher
from aiohttp import web

import config
from app.logger import get_logger

logger = get_logger("webapp")
webapp = web.Application()
webapp_runner: web.TCPSite = None


async def on_startup() -> web.TCPSite:
    from . import payment

    webapp.add_routes(payment.routes)
    runner = web.AppRunner(webapp)
    await runner.setup()
    global webapp_runner
    webapp_runner = web.TCPSite(
        runner, host=config.WEBAPP_HOST, port=config.WEBAPP_PORT
    )
    await webapp_runner.start()


async def on_shutdown() -> None:
    await webapp_runner.stop()


def setup_webapp(dp: Dispatcher) -> None:
    dp.startup.register(on_startup)
    dp.shutdown.register(on_shutdown)

app/views/__init__.py
govfvck/Marzbot-free
import hashlib
import hmac
import json
from datetime import datetime as dt

from aiohttp import web
from tortoise.transactions import in_transaction

import config
from app.main import bot
from app.models.user import CryptoPayment, Transaction
from payment_clients.nowpayments import PaymentResponse

from . import logger

routes = web.RouteTableDef()


def hmac_sign(key: str, data: dict) -> str:
    """
    sort the post data from nowpayments and sign it with the secret key and sha512
    """
    return hmac.new(
        key.encode(),
        json.dumps(dict(sorted(data.items())), separators=(",", ":")).encode(),
        hashlib.sha512,
    ).hexdigest()


def verify_signature(sig: str, key: str, data: dict) -> bool:
    if sig == hmac_sign(key, data):
        return True
    return False


@routes.post("/npipn/")
async def verify_payment(request: web.Request):
    if not request.can_read_body:
        return
    data = await request.json()
    logger.info(f"got ipn from nowpayments: {data}")
    if config.NP_IPN_SECRET_KEY:
        nowpayments_sig = request.headers.get("x-nowpayments-sig")
        if not verify_signature(nowpayments_sig, config.NP_IPN_SECRET_KEY, data):
            return

    payment = PaymentResponse(**data)
    async with in_transaction():
        transaction = (
            await Transaction.filter(id=payment.order_id)
            .prefetch_related("crypto_payment")
            .first()
        )
        if not transaction:
            return

        if payment.payment_status == "finished" and (
            transaction.status
            not in [Transaction.Status.finished, Transaction.Status.partially_paid]
        ):
            transaction.status = Transaction.Status.finished
            transaction.finished_at = dt.now()
            transaction.amount_paid = (
                transaction.crypto_payment.usdt_rate * payment.price_amount
            )
            await transaction.save()
            await transaction.refresh_from_db()
            await transaction.crypto_payment.update_from_dict(
                {
                    "pay_currency": payment.pay_currency,
                    "pay_amount": payment.pay_amount,
                    "nowpm_updated_at": payment.updated_at,
                    "payment_status": CryptoPayment.PaymentStatus.finished,
                    "outcome_amount": payment.outcome_amount,
                    "outcome_currency": payment.outcome_currency,
                    "purchase_id": payment.purchase_id,
                    "pay_address": payment.pay_address,
                }
            ).save()
            text = f"""
✅ پرداخت شما از طریق ارز دیجیتال با موفقیت تأیید شد و مبلغ <b>{transaction.amount:,}</b> تومان به حساب شما اضافه شد!

💳 شماره فاکتور: <b>{transaction.id}</b>
💴 مبلغ پرداختی: <b>{transaction.amount_paid:,}</b> تومان
‌‌
"""
            await bot.send_message(transaction.user_id, text)

    return web.Response(status=200)

app/views/payment.py
govfvck/Marzbot-free
import os
import re

from dotenv import load_dotenv

if DOTENV_PATH := os.getenv("PYTHON_DOTENV_FILE"):
    from decouple import Config, RepositoryEnv

    load_dotenv(DOTENV_PATH)
    config = Config(RepositoryEnv(DOTENV_PATH))
else:
    from decouple import config

    load_dotenv()

from app.logger import get_logger

log = get_logger(__name__)


LOG_LEVEL = config("LOG_LEVEL", default="info")

BOT_TOKEN = config("BOT_TOKEN")

SETTINGS = {
    "BOT:ACCESS_ONLY": config("SETTINGS:BOT:ACCESS_ONLY", default=False, cast=bool),
    "PAYMENT:CRYPTO": config("SETTINGS:PAYMENT:CRYPTO", default=True, cast=bool),
}

# socks5h://127.0.0.1:2080
PROXY = config("PROXY", None)


PARSE_MODE = config("PARSE_MODE", default="HTML")
DATABASE_URL = config(
    "DATABASE_URL", default="sqlite://db.sqlite3"
)  # example: 'mysql://user:pass@localhost:3306/db'
# exmaple: 'sqlite:///marzbot.db'

if DATABASE_URL is None:
    raise ValueError("'DATABASE_URL' environment variable has to be set!")

BOT_USERNAME = config("BOT_USERNAME", default="marzdemobot")

DEFAULT_USERNAME_PREFIX = config("DEFAULT_USERNAME_PREFIX", default="Marzdemo")

if not re.match(r"^(?!_)[A-Za-z0-9_]+$", DEFAULT_USERNAME_PREFIX):
    raise ValueError(
        "DEFAULT_USERNAME_PREFIX must be less than 20 characters and [0-9A-Za-z] and underscores in between"
    )

PAYMENTS_DISCOUNT_ON = config(
    "PAYMENTS_DISCOUNT_ON", default=400000, cast=int
)  # payments higher than this amount will have a discount, set 0 for no discount
PAYMENTS_DISCOUNT_ON_PERCENT = config(
    "PAYMENTS_DISCOUNT_ON_PERCENT", default=6, cast=int
)  # default: 6 percent free credit for payments more than 400,000t


if PAYMENTS_DISCOUNT_ON:
    FREE_CREDIT_ON_TEXT = f"🔥 تمامی پرداخت‌های بیشتر از {PAYMENTS_DISCOUNT_ON:,} تومان شامل {PAYMENTS_DISCOUNT_ON_PERCENT} درصد اعتبار هدیه می‌شوند😉"
else:
    FREE_CREDIT_ON_TEXT = ""

NP_API_URL = config("NP_API_URL", default="https://api.nowpayments.io/v1")
NP_API_KEY = config("NP_API_KEY", default=None)

NP_IPN_CALLBACK_URL = config(
    "NP_IPN_CALLBACK_URL", default="https://rayapardazapi.ir/cryptogw"
)

NP_IPN_SECRET_KEY = config("NP_IPN_SECRET_KEY", default=None)
NP_SUCCESS_URL = config("NP_SUCCESS_URL", default=None)
NP_CANCEL_URL = config("NP_CANCEL_URL", default=None)

TORTOISE_ORM = {
    "connections": {"default": DATABASE_URL},
    "apps": {
        "models": {
            "models": [  # put rest of the models as so in the list
                "app.models.user",
                "app.models.server",
                "app.models.service",
                "app.models.proxy",
                "aerich.models",
            ],
            "default_connection": "default",
        },
    },
}

REDIS_HOST = config("REDIS_HOST", default="redis")
REDIS_PORT = config("REDIS_PORT", default=6379)
REDIS_DB = config("REDIS_DB", default=0)


WEBAPP_HOST = config("WEBAPP_HOST", default="127.0.0.1")
WEBAPP_PORT = config("WEBAPP_PORT", default=3333)


FORCE_JOIN_CHATS = {
    chat.split("@")[0]: chat.split("@")[1]
    for chat in config("FORCE_JOIN_CHATS", default="-1001892840605@marzdemo").split(
        "\n"
    )
    if chat
}


def generate_help(text: str) -> str:
    if not text:
        return ""
    return f"~~~~~~~~~~~~~~~~~~~~~~~~{text}~~~~~~~~~~~~~~~~~~~~~~~~"


_START_TEXT = f"""
👋 سلااااام
به ربات خوش اومدی😉

با سرویس‌های ما میتونی همیشه و هر لحظه و با هر دستگاهی به اینترنت متصل بمونی🌝

💡 برای دریافت اخبار، وضعیت سرویس‌ها و دریافت کدهای هدیه روزانه در کانال ما عضو بشید
🆔 @marzdemo

🔍 اگه میخوای بیشتر در مورد ربات بدونی میتونی دکمه <b>«راهنما»</b> رو بزنی
"""


_FORCE_JOIN_TEXT = f"""
♻️ برای استفاده از ربات باید در کانال ما عضو بشید

توی کانالی که پایین مشخص شده عضو بشید و سپس دکمه «تأیید عضویت» رو بزنید👇

🆔 @marzdemo
"""

_SUPPORT_TEXT = """
✋ به بخش پشتیبانی خوش اومدی

قبل از اینکه به پشتیبانی پیام بدید، حواستون باشه که بخش‌ «راهنما» رو مطالعه کرده باشید، احتمالا جواب سوالتون رو پیدا می‌کنید😉

⁉️ جواب سوالتون اونجا نبود؟ اشکالی نداره، میتونید از طریق آیدی زیر با پشتیبانی ارتباط برقرار کنید👇

🆔 @govfvck1

💡 بعد از پیام دادن به پشتیبانی، لطفا صبور باشید. به همه پیام‌ها در اسرع وقت جواب داده میشه🙏
"""

_HELP_TEXT = """
به بخش راهنمای استفاده از ربات خوش اومدید

شما می‌تونید برای خرید اشتراک به چند روش پرداخت رو انجام بدید که می‌تونید با کلیک رو دکمه «شارژ حساب» اون‌ها رو ببینید. 
😃 آموزش استفاده از هرکدوم از روش‌ها رو هم اونجا براتون گذاشتیم! 

بعد از اینکه حسابتون رو شارژ کردید، میتونید روی دکمه «خرید اشتراک» کلیک کنید و پلن مناسب خودتون رو خریداری کنید و به صورت آنی تحویل بگیرید. به همین سادگی😇

برای دیدن اشتراک‌هایی که قبلا خریداری کردید کافیه روی دکمه «اشتراک‌های من» کلیک کنید🙃
توی این قسمت لیست تمام اشتراک‌های شما بهتون نشون داده میشه. برای دیدن اطلاعات و مدیریت هر کدوم از اون‌ها میتونید روش کلیک کنید و وارد بخش تنظیماتش بشید😉

برای اینکه بدونی چقدر موجودی داری میتونی روی دکمه «اطلاعات حساب» کلیک کنی و اطلاعات بیشتر رو اونجا ببینی🤓

همچنین میتونید با استفاده از دعوت بقیه به ربات، اعتبار هدیه بگیرید😋

💡یک سری سوالات متوالی که ممکنه براتون پیش بیاد رو هم توی کانالمون قرار دادیم که میتونید از این لینک مطلاعه کنید🙋:
<a href='https://t.me'>❔ سوالات متدوال</a>

اگه جواب سوالتون رو در این بخش یا بخش سوالات متداول پیدا نکردید، میتونید از طریق دکمه «پشتیبانی» با پشتیبانی ربات تماس بگیرید. خوشحال میشیم سوالاتتون رو جواب بدیم و مشکلاتتون رو حل کنیم🤗

📞 اگر فروشنده هستید و قصد خرید تعداد بالا دارید، با پشتیبانی تماس بگیرید تا سطح اکانت شما ارتقا پیدا کنه و قابلیت‌های مخصوص فروشندگان براتون فعال بشه🤫
‌‌
"""

_CRYPTO_PAYMENT_HELP = """
❗️ اگر با نحوه پرداخت به وسیله ارز دیجیتال آشنایی ندارید، حتما روی لینک زیر کلیک کنید و آموزش رو مشاهده کنید:
<a href='https://t.me/'>❔ آموزش شارژ حساب با ارز دیجیتال</a>
"""


START_TEXT = config("START_TEXT", default=_START_TEXT)
FORCE_JOIN_TEXT = config("FORCE_JOIN_TEXT", default=_FORCE_JOIN_TEXT)
SUPPORT_TEXT = config("SUPPORT_TEXT", default=_SUPPORT_TEXT)
HELP_TEXT = config("HELP_TEXT", default=_HELP_TEXT)

CRYPTO_PAYMENT_HELP = generate_help(
    config("CRYPTO_PAYMENT_HELP", default=_CRYPTO_PAYMENT_HELP)
)

config.py
govfvck/Marzbot-free
""" A client library for accessing MarzbanAPI """
from .client import AuthenticatedClient, Client

__all__ = (
    "AuthenticatedClient",
    "Client",
)

marzban_client/__init__.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.admin import Admin
from ...models.admin_create import AdminCreate
from ...models.http_validation_error import HTTPValidationError
from ...types import Response


def _get_kwargs(
    *,
    json_body: AdminCreate,
) -> Dict[str, Any]:
    pass

    json_json_body = json_body.to_dict()

    return {
        "method": "post",
        "url": "/api/admin",
        "json": json_json_body,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Admin, Any, HTTPValidationError]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = Admin.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if response.status_code == HTTPStatus.CONFLICT:
        response_409 = cast(Any, None)
        return response_409
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Admin, Any, HTTPValidationError]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
    json_body: AdminCreate,
) -> Response[Union[Admin, Any, HTTPValidationError]]:
    """Create Admin

    Args:
        json_body (AdminCreate):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Admin, Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        json_body=json_body,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
    json_body: AdminCreate,
) -> Optional[Union[Admin, Any, HTTPValidationError]]:
    """Create Admin

    Args:
        json_body (AdminCreate):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Admin, Any, HTTPValidationError]
    """

    return sync_detailed(
        client=client,
        json_body=json_body,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
    json_body: AdminCreate,
) -> Response[Union[Admin, Any, HTTPValidationError]]:
    """Create Admin

    Args:
        json_body (AdminCreate):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Admin, Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        json_body=json_body,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
    json_body: AdminCreate,
) -> Optional[Union[Admin, Any, HTTPValidationError]]:
    """Create Admin

    Args:
        json_body (AdminCreate):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Admin, Any, HTTPValidationError]
    """

    return (
        await asyncio_detailed(
            client=client,
            json_body=json_body,
        )
    ).parsed

marzban_client/api/admin/create_admin_api_admin_post.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, List, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.admin import Admin
from ...models.http_validation_error import HTTPValidationError
from ...types import UNSET, Response, Unset


def _get_kwargs(
    *,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
    username: Union[Unset, None, str] = UNSET,
) -> Dict[str, Any]:
    pass

    params: Dict[str, Any] = {}
    params["offset"] = offset

    params["limit"] = limit

    params["username"] = username

    params = {k: v for k, v in params.items() if v is not UNSET and v is not None}

    return {
        "method": "get",
        "url": "/api/admins",
        "params": params,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, List["Admin"]]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = []
        _response_200 = response.json()
        for response_200_item_data in _response_200:
            response_200_item = Admin.from_dict(response_200_item_data)

            response_200.append(response_200_item)

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, List["Admin"]]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
    username: Union[Unset, None, str] = UNSET,
) -> Response[Union[Any, HTTPValidationError, List["Admin"]]]:
    """Get Admins

    Args:
        offset (Union[Unset, None, int]):
        limit (Union[Unset, None, int]):
        username (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, List['Admin']]]
    """

    kwargs = _get_kwargs(
        offset=offset,
        limit=limit,
        username=username,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
    username: Union[Unset, None, str] = UNSET,
) -> Optional[Union[Any, HTTPValidationError, List["Admin"]]]:
    """Get Admins

    Args:
        offset (Union[Unset, None, int]):
        limit (Union[Unset, None, int]):
        username (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, List['Admin']]
    """

    return sync_detailed(
        client=client,
        offset=offset,
        limit=limit,
        username=username,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
    username: Union[Unset, None, str] = UNSET,
) -> Response[Union[Any, HTTPValidationError, List["Admin"]]]:
    """Get Admins

    Args:
        offset (Union[Unset, None, int]):
        limit (Union[Unset, None, int]):
        username (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, List['Admin']]]
    """

    kwargs = _get_kwargs(
        offset=offset,
        limit=limit,
        username=username,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
    username: Union[Unset, None, str] = UNSET,
) -> Optional[Union[Any, HTTPValidationError, List["Admin"]]]:
    """Get Admins

    Args:
        offset (Union[Unset, None, int]):
        limit (Union[Unset, None, int]):
        username (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, List['Admin']]
    """

    return (
        await asyncio_detailed(
            client=client,
            offset=offset,
            limit=limit,
            username=username,
        )
    ).parsed

marzban_client/api/admin/get_admins_api_admins_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.admin import Admin
from ...types import Response


def _get_kwargs() -> Dict[str, Any]:
    pass

    return {
        "method": "get",
        "url": "/api/admin",
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Admin]:
    if response.status_code == HTTPStatus.OK:
        response_200 = Admin.from_dict(response.json())

        return response_200
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Admin]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[Admin]:
    """Get Current Admin

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Admin]
    """

    kwargs = _get_kwargs()

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
) -> Optional[Admin]:
    """Get Current Admin

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Admin
    """

    return sync_detailed(
        client=client,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[Admin]:
    """Get Current Admin

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Admin]
    """

    kwargs = _get_kwargs()

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
) -> Optional[Admin]:
    """Get Current Admin

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Admin
    """

    return (
        await asyncio_detailed(
            client=client,
        )
    ).parsed

marzban_client/api/admin/get_current_admin_api_admin_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.body_login_for_acess_token import BodyLoginForAcessToken
from ...models.http_validation_error import HTTPValidationError
from ...models.token import Token
from ...types import Response


def _get_kwargs(
    form_data: BodyLoginForAcessToken,
) -> Dict[str, Any]:
    pass

    return {
        "method": "post",
        "url": "/api/admin/token",
        "data": form_data.to_dict(),
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[HTTPValidationError, Token]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = Token.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[HTTPValidationError, Token]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: Union[AuthenticatedClient, Client],
    form_data: BodyLoginForAcessToken,
) -> Response[Union[HTTPValidationError, Token]]:
    """Login For Access Token

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[HTTPValidationError, Token]]
    """

    kwargs = _get_kwargs(
        form_data=form_data,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: Union[AuthenticatedClient, Client],
    form_data: BodyLoginForAcessToken,
) -> Optional[Union[HTTPValidationError, Token]]:
    """Login For Access Token

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[HTTPValidationError, Token]
    """

    return sync_detailed(
        client=client,
        form_data=form_data,
    ).parsed


async def asyncio_detailed(
    *,
    client: Union[AuthenticatedClient, Client],
    form_data: BodyLoginForAcessToken,
) -> Response[Union[HTTPValidationError, Token]]:
    """Login For Access Token

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[HTTPValidationError, Token]]
    """

    kwargs = _get_kwargs(
        form_data=form_data,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: Union[AuthenticatedClient, Client],
    form_data: BodyLoginForAcessToken,
) -> Optional[Union[HTTPValidationError, Token]]:
    """Login For Access Token

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[HTTPValidationError, Token]
    """

    return (
        await asyncio_detailed(
            client=client,
            form_data=form_data,
        )
    ).parsed

marzban_client/api/admin/login_for_access_token_api_admin_token_post.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.admin import Admin
from ...models.admin_modify import AdminModify
from ...models.http_validation_error import HTTPValidationError
from ...types import Response


def _get_kwargs(
    username: str,
    *,
    json_body: AdminModify,
) -> Dict[str, Any]:
    pass

    json_json_body = json_body.to_dict()

    return {
        "method": "put",
        "url": "/api/admin/{username}".format(
            username=username,
        ),
        "json": json_json_body,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Admin, Any, HTTPValidationError]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = Admin.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Admin, Any, HTTPValidationError]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
    json_body: AdminModify,
) -> Response[Union[Admin, Any, HTTPValidationError]]:
    """Modify Admin

    Args:
        username (str):
        json_body (AdminModify):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Admin, Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        username=username,
        json_body=json_body,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    username: str,
    *,
    client: AuthenticatedClient,
    json_body: AdminModify,
) -> Optional[Union[Admin, Any, HTTPValidationError]]:
    """Modify Admin

    Args:
        username (str):
        json_body (AdminModify):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Admin, Any, HTTPValidationError]
    """

    return sync_detailed(
        username=username,
        client=client,
        json_body=json_body,
    ).parsed


async def asyncio_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
    json_body: AdminModify,
) -> Response[Union[Admin, Any, HTTPValidationError]]:
    """Modify Admin

    Args:
        username (str):
        json_body (AdminModify):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Admin, Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        username=username,
        json_body=json_body,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    username: str,
    *,
    client: AuthenticatedClient,
    json_body: AdminModify,
) -> Optional[Union[Admin, Any, HTTPValidationError]]:
    """Modify Admin

    Args:
        username (str):
        json_body (AdminModify):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Admin, Any, HTTPValidationError]
    """

    return (
        await asyncio_detailed(
            username=username,
            client=client,
            json_body=json_body,
        )
    ).parsed

marzban_client/api/admin/modify_admin_api_admin_username_put.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...types import Response


def _get_kwargs(
    username: str,
) -> Dict[str, Any]:
    pass

    return {
        "method": "delete",
        "url": "/api/admin/{username}".format(
            username=username,
        ),
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = cast(Any, response.json())
        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError]]:
    """Remove Admin

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        username=username,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError]]:
    """Remove Admin

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError]
    """

    return sync_detailed(
        username=username,
        client=client,
    ).parsed


async def asyncio_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError]]:
    """Remove Admin

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        username=username,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError]]:
    """Remove Admin

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError]
    """

    return (
        await asyncio_detailed(
            username=username,
            client=client,
        )
    ).parsed

marzban_client/api/admin/remove_admin_api_admin_username_delete.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.get_core_config_api_core_config_get_response_get_core_config_api_core_config_get import (
    GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet,
)
from ...types import Response


def _get_kwargs() -> Dict[str, Any]:
    pass

    return {
        "method": "get",
        "url": "/api/core/config",
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[
    Union[Any, GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet]
]:
    if response.status_code == HTTPStatus.OK:
        response_200 = GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet.from_dict(
            response.json()
        )

        return response_200
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[
    Union[Any, GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet]
]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[
    Union[Any, GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet]
]:
    """Get Core Config

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet]]
    """

    kwargs = _get_kwargs()

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
) -> Optional[
    Union[Any, GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet]
]:
    """Get Core Config

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet]
    """

    return sync_detailed(
        client=client,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[
    Union[Any, GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet]
]:
    """Get Core Config

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet]]
    """

    kwargs = _get_kwargs()

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
) -> Optional[
    Union[Any, GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet]
]:
    """Get Core Config

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet]
    """

    return (
        await asyncio_detailed(
            client=client,
        )
    ).parsed

marzban_client/api/core/get_core_config_api_core_config_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.get_core_config_api_core_config_put_payload import (
    GetCoreConfigApiCoreConfigPutPayload,
)
from ...models.get_core_config_api_core_config_put_response_get_core_config_api_core_config_put import (
    GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut,
)
from ...models.http_validation_error import HTTPValidationError
from ...types import Response


def _get_kwargs(
    *,
    json_body: GetCoreConfigApiCoreConfigPutPayload,
) -> Dict[str, Any]:
    pass

    json_json_body = json_body.to_dict()

    return {
        "method": "put",
        "url": "/api/core/config",
        "json": json_json_body,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[
    Union[
        Any,
        GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut,
        HTTPValidationError,
    ]
]:
    if response.status_code == HTTPStatus.OK:
        response_200 = GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut.from_dict(
            response.json()
        )

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[
    Union[
        Any,
        GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut,
        HTTPValidationError,
    ]
]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
    json_body: GetCoreConfigApiCoreConfigPutPayload,
) -> Response[
    Union[
        Any,
        GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut,
        HTTPValidationError,
    ]
]:
    """Get Core Config

    Args:
        json_body (GetCoreConfigApiCoreConfigPutPayload):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        json_body=json_body,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
    json_body: GetCoreConfigApiCoreConfigPutPayload,
) -> Optional[
    Union[
        Any,
        GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut,
        HTTPValidationError,
    ]
]:
    """Get Core Config

    Args:
        json_body (GetCoreConfigApiCoreConfigPutPayload):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut, HTTPValidationError]
    """

    return sync_detailed(
        client=client,
        json_body=json_body,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
    json_body: GetCoreConfigApiCoreConfigPutPayload,
) -> Response[
    Union[
        Any,
        GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut,
        HTTPValidationError,
    ]
]:
    """Get Core Config

    Args:
        json_body (GetCoreConfigApiCoreConfigPutPayload):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        json_body=json_body,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
    json_body: GetCoreConfigApiCoreConfigPutPayload,
) -> Optional[
    Union[
        Any,
        GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut,
        HTTPValidationError,
    ]
]:
    """Get Core Config

    Args:
        json_body (GetCoreConfigApiCoreConfigPutPayload):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut, HTTPValidationError]
    """

    return (
        await asyncio_detailed(
            client=client,
            json_body=json_body,
        )
    ).parsed

marzban_client/api/core/get_core_config_api_core_config_put.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.core_stats import CoreStats
from ...types import Response


def _get_kwargs() -> Dict[str, Any]:
    pass

    return {
        "method": "get",
        "url": "/api/core",
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[CoreStats]:
    if response.status_code == HTTPStatus.OK:
        response_200 = CoreStats.from_dict(response.json())

        return response_200
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[CoreStats]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[CoreStats]:
    """Get Core Stats

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[CoreStats]
    """

    kwargs = _get_kwargs()

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
) -> Optional[CoreStats]:
    """Get Core Stats

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        CoreStats
    """

    return sync_detailed(
        client=client,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[CoreStats]:
    """Get Core Stats

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[CoreStats]
    """

    kwargs = _get_kwargs()

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
) -> Optional[CoreStats]:
    """Get Core Stats

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        CoreStats
    """

    return (
        await asyncio_detailed(
            client=client,
        )
    ).parsed

marzban_client/api/core/get_core_stats_api_core_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...types import Response


def _get_kwargs() -> Dict[str, Any]:
    pass

    return {
        "method": "post",
        "url": "/api/core/restart",
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Any]:
    if response.status_code == HTTPStatus.OK:
        return None
    if response.status_code == HTTPStatus.FORBIDDEN:
        return None
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Any]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[Any]:
    """Restart Core

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Any]
    """

    kwargs = _get_kwargs()

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[Any]:
    """Restart Core

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Any]
    """

    kwargs = _get_kwargs()

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)

marzban_client/api/core/restart_core_api_core_restart_post.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...types import Response


def _get_kwargs() -> Dict[str, Any]:
    pass

    return {
        "method": "get",
        "url": "/",
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[str]:
    if response.status_code == HTTPStatus.OK:
        response_200 = cast(str, response.text)
        return response_200
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[str]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: Union[AuthenticatedClient, Client],
) -> Response[str]:
    """Base

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[str]
    """

    kwargs = _get_kwargs()

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: Union[AuthenticatedClient, Client],
) -> Optional[str]:
    """Base

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        str
    """

    return sync_detailed(
        client=client,
    ).parsed


async def asyncio_detailed(
    *,
    client: Union[AuthenticatedClient, Client],
) -> Response[str]:
    """Base

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[str]
    """

    kwargs = _get_kwargs()

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: Union[AuthenticatedClient, Client],
) -> Optional[str]:
    """Base

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        str
    """

    return (
        await asyncio_detailed(
            client=client,
        )
    ).parsed

marzban_client/api/default/base_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.node_create import NodeCreate
from ...models.node_response import NodeResponse
from ...types import Response


def _get_kwargs(
    *,
    json_body: NodeCreate,
) -> Dict[str, Any]:
    pass

    json_json_body = json_body.to_dict()

    return {
        "method": "post",
        "url": "/api/node",
        "json": json_json_body,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, NodeResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = NodeResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, NodeResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
    json_body: NodeCreate,
) -> Response[Union[Any, HTTPValidationError, NodeResponse]]:
    r"""Add Node

    Args:
        json_body (NodeCreate):  Example: {'name': 'DE node', 'address': '192.168.1.1', 'port':
            62050, 'api_port': 62051, 'add_as_new_host': True, 'certificate': '-----BEGIN CERTIFICATE-
            ----\nMIIEnDCCAoQCAQAwDQYJKoZIhvcNAQENBQAwEzERMA8GA1UEAwwIR296YXJnYWgw\nIBcNMjMwMjE5MjMwOT
            MyWhgPMjEyMzAxMjYyMzA5MzJaMBMxETAPBgNVBAMMCEdv\nemFyZ2FoMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMI
            ICCgKCAgEA0BvDh0eU78EJ\n+xzBWUjjMrWf/0rWV5fDl7b4RU8AjeviG1RmEc64ueZ3s6q1LI6DJX1+qGuqDEvp\n
            mRc09HihO07DyQgQqF38/E4CXshZ2L3UOzsa80lf74dhEqAR/EJQXXMwGSb3T9J9\nseCqCyiEn/JLEGsilDz64cTv
            8MXMAcjjpdefkFyQP+4hAKQgHbtfJ9KPSu4/lkZR\n/orsjoWGJv4LS0MsXV1t7LB/bNC7qOzlmzrfTMH4EmtmKH8H
            whMkL1nUG+vXEfwm\nQg3Ly+yrwKNw9+L7DxbKnoy2Zqp9dN+rzKDgcpHsoIYf0feInUHHlRUu303kAFQN\nGlnzZg
            D8ulHI1sQLNS3teYpj817G3EXKOhu56MvBehBR9GfvfS1D5D/QvwRfcaZI\nCULBPoGqovhrknbUXt9TEfzc9YnfSz
            lcJYcH54/aUBVJNs74EK38OQ+JciLnw4qe\ngbXEshaeLgGM3bhXwUhctcmZf5ASWDsAVtEeCXGNK+ua6wlFXKVd0j
            Ot2ZZYG42X\nwrpHCErAWY7AoxHmXlfPcPM0Uu7FuEBP27f8U3N+glG1lWrogNn54j1ZrzQVUVVv\ngog78DrjjzrR
            0puQ9x9q6FvEUTAaaA06lvi2/6BuwO0jKrHQCP7fFUmRXg5B5lrJ\n9czSDHT9WH9Sc1qdxQTevhc9C/h6MuMCAwEA
            ATANBgkqhkiG9w0BAQ0FAAOCAgEA\nI7aXhLejp53NyuwzmdfeycY373TI4sD3WfPdEB6+FSCX38YghyQl8tkeaHPg
            PKY5\n+vA+eVxE7E961UNPtJtJg/dzBvoWUroTnpvKjVdDImFaZa/PvUMgSEe8tC3FtB6i\nAp7f0yYOGsFf6oaOxM
            fs/F0sGflsaVWuiATTsV8Er+uzge77Q8AXzy6spuXg3ALF\n56tqzZY5x/04g1KUQB4JN+7JzipnfSIUof0eAKf9gQ
            bumUU+Q2b32HMC2MOlUjv+\nIl8rJ9cs0zwC1BOmqoS3Ez22dgtT7FucvIJ1MGP8oUAudMmrXDxx/d7CmnD5q1v4\n
            XFSa6Zv8LPLCz5iMbo0FjNlKyZo3699PtyBFXt3zyfTPmiy19RVGTziHqJ9NR9kW\nkBwvFzIy+qPc/dJAk435hVaV
            3pRBC7Pl2Y7k/pJxxlC07PkACXuhwtUGhQrHYWkK\niLlV21kNnWuvjS1orTwvuW3aagb6tvEEEmlMhw5a2B8sl71s
            Q6sxWidgRaOSGW7l\ng1gctfdLMARuV6LkLiGy5k2FGAW/tfepEyySA/N9WhcHg+rZ4/x1thP0eYJPQ2YJ\nAjimHy
            Bb+3tFs7KaOPu9G5xgbQWUWccukMDXqybqiUDSfU/T5/+XM8CKq/Fu0DBu\n3lg0NYigkZFs99lZJ1H4BkMWgL65ay
            bO4XwfZJTGLe0=\n-----END CERTIFICATE-----'}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, NodeResponse]]
    """

    kwargs = _get_kwargs(
        json_body=json_body,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
    json_body: NodeCreate,
) -> Optional[Union[Any, HTTPValidationError, NodeResponse]]:
    r"""Add Node

    Args:
        json_body (NodeCreate):  Example: {'name': 'DE node', 'address': '192.168.1.1', 'port':
            62050, 'api_port': 62051, 'add_as_new_host': True, 'certificate': '-----BEGIN CERTIFICATE-
            ----\nMIIEnDCCAoQCAQAwDQYJKoZIhvcNAQENBQAwEzERMA8GA1UEAwwIR296YXJnYWgw\nIBcNMjMwMjE5MjMwOT
            MyWhgPMjEyMzAxMjYyMzA5MzJaMBMxETAPBgNVBAMMCEdv\nemFyZ2FoMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMI
            ICCgKCAgEA0BvDh0eU78EJ\n+xzBWUjjMrWf/0rWV5fDl7b4RU8AjeviG1RmEc64ueZ3s6q1LI6DJX1+qGuqDEvp\n
            mRc09HihO07DyQgQqF38/E4CXshZ2L3UOzsa80lf74dhEqAR/EJQXXMwGSb3T9J9\nseCqCyiEn/JLEGsilDz64cTv
            8MXMAcjjpdefkFyQP+4hAKQgHbtfJ9KPSu4/lkZR\n/orsjoWGJv4LS0MsXV1t7LB/bNC7qOzlmzrfTMH4EmtmKH8H
            whMkL1nUG+vXEfwm\nQg3Ly+yrwKNw9+L7DxbKnoy2Zqp9dN+rzKDgcpHsoIYf0feInUHHlRUu303kAFQN\nGlnzZg
            D8ulHI1sQLNS3teYpj817G3EXKOhu56MvBehBR9GfvfS1D5D/QvwRfcaZI\nCULBPoGqovhrknbUXt9TEfzc9YnfSz
            lcJYcH54/aUBVJNs74EK38OQ+JciLnw4qe\ngbXEshaeLgGM3bhXwUhctcmZf5ASWDsAVtEeCXGNK+ua6wlFXKVd0j
            Ot2ZZYG42X\nwrpHCErAWY7AoxHmXlfPcPM0Uu7FuEBP27f8U3N+glG1lWrogNn54j1ZrzQVUVVv\ngog78DrjjzrR
            0puQ9x9q6FvEUTAaaA06lvi2/6BuwO0jKrHQCP7fFUmRXg5B5lrJ\n9czSDHT9WH9Sc1qdxQTevhc9C/h6MuMCAwEA
            ATANBgkqhkiG9w0BAQ0FAAOCAgEA\nI7aXhLejp53NyuwzmdfeycY373TI4sD3WfPdEB6+FSCX38YghyQl8tkeaHPg
            PKY5\n+vA+eVxE7E961UNPtJtJg/dzBvoWUroTnpvKjVdDImFaZa/PvUMgSEe8tC3FtB6i\nAp7f0yYOGsFf6oaOxM
            fs/F0sGflsaVWuiATTsV8Er+uzge77Q8AXzy6spuXg3ALF\n56tqzZY5x/04g1KUQB4JN+7JzipnfSIUof0eAKf9gQ
            bumUU+Q2b32HMC2MOlUjv+\nIl8rJ9cs0zwC1BOmqoS3Ez22dgtT7FucvIJ1MGP8oUAudMmrXDxx/d7CmnD5q1v4\n
            XFSa6Zv8LPLCz5iMbo0FjNlKyZo3699PtyBFXt3zyfTPmiy19RVGTziHqJ9NR9kW\nkBwvFzIy+qPc/dJAk435hVaV
            3pRBC7Pl2Y7k/pJxxlC07PkACXuhwtUGhQrHYWkK\niLlV21kNnWuvjS1orTwvuW3aagb6tvEEEmlMhw5a2B8sl71s
            Q6sxWidgRaOSGW7l\ng1gctfdLMARuV6LkLiGy5k2FGAW/tfepEyySA/N9WhcHg+rZ4/x1thP0eYJPQ2YJ\nAjimHy
            Bb+3tFs7KaOPu9G5xgbQWUWccukMDXqybqiUDSfU/T5/+XM8CKq/Fu0DBu\n3lg0NYigkZFs99lZJ1H4BkMWgL65ay
            bO4XwfZJTGLe0=\n-----END CERTIFICATE-----'}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, NodeResponse]
    """

    return sync_detailed(
        client=client,
        json_body=json_body,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
    json_body: NodeCreate,
) -> Response[Union[Any, HTTPValidationError, NodeResponse]]:
    r"""Add Node

    Args:
        json_body (NodeCreate):  Example: {'name': 'DE node', 'address': '192.168.1.1', 'port':
            62050, 'api_port': 62051, 'add_as_new_host': True, 'certificate': '-----BEGIN CERTIFICATE-
            ----\nMIIEnDCCAoQCAQAwDQYJKoZIhvcNAQENBQAwEzERMA8GA1UEAwwIR296YXJnYWgw\nIBcNMjMwMjE5MjMwOT
            MyWhgPMjEyMzAxMjYyMzA5MzJaMBMxETAPBgNVBAMMCEdv\nemFyZ2FoMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMI
            ICCgKCAgEA0BvDh0eU78EJ\n+xzBWUjjMrWf/0rWV5fDl7b4RU8AjeviG1RmEc64ueZ3s6q1LI6DJX1+qGuqDEvp\n
            mRc09HihO07DyQgQqF38/E4CXshZ2L3UOzsa80lf74dhEqAR/EJQXXMwGSb3T9J9\nseCqCyiEn/JLEGsilDz64cTv
            8MXMAcjjpdefkFyQP+4hAKQgHbtfJ9KPSu4/lkZR\n/orsjoWGJv4LS0MsXV1t7LB/bNC7qOzlmzrfTMH4EmtmKH8H
            whMkL1nUG+vXEfwm\nQg3Ly+yrwKNw9+L7DxbKnoy2Zqp9dN+rzKDgcpHsoIYf0feInUHHlRUu303kAFQN\nGlnzZg
            D8ulHI1sQLNS3teYpj817G3EXKOhu56MvBehBR9GfvfS1D5D/QvwRfcaZI\nCULBPoGqovhrknbUXt9TEfzc9YnfSz
            lcJYcH54/aUBVJNs74EK38OQ+JciLnw4qe\ngbXEshaeLgGM3bhXwUhctcmZf5ASWDsAVtEeCXGNK+ua6wlFXKVd0j
            Ot2ZZYG42X\nwrpHCErAWY7AoxHmXlfPcPM0Uu7FuEBP27f8U3N+glG1lWrogNn54j1ZrzQVUVVv\ngog78DrjjzrR
            0puQ9x9q6FvEUTAaaA06lvi2/6BuwO0jKrHQCP7fFUmRXg5B5lrJ\n9czSDHT9WH9Sc1qdxQTevhc9C/h6MuMCAwEA
            ATANBgkqhkiG9w0BAQ0FAAOCAgEA\nI7aXhLejp53NyuwzmdfeycY373TI4sD3WfPdEB6+FSCX38YghyQl8tkeaHPg
            PKY5\n+vA+eVxE7E961UNPtJtJg/dzBvoWUroTnpvKjVdDImFaZa/PvUMgSEe8tC3FtB6i\nAp7f0yYOGsFf6oaOxM
            fs/F0sGflsaVWuiATTsV8Er+uzge77Q8AXzy6spuXg3ALF\n56tqzZY5x/04g1KUQB4JN+7JzipnfSIUof0eAKf9gQ
            bumUU+Q2b32HMC2MOlUjv+\nIl8rJ9cs0zwC1BOmqoS3Ez22dgtT7FucvIJ1MGP8oUAudMmrXDxx/d7CmnD5q1v4\n
            XFSa6Zv8LPLCz5iMbo0FjNlKyZo3699PtyBFXt3zyfTPmiy19RVGTziHqJ9NR9kW\nkBwvFzIy+qPc/dJAk435hVaV
            3pRBC7Pl2Y7k/pJxxlC07PkACXuhwtUGhQrHYWkK\niLlV21kNnWuvjS1orTwvuW3aagb6tvEEEmlMhw5a2B8sl71s
            Q6sxWidgRaOSGW7l\ng1gctfdLMARuV6LkLiGy5k2FGAW/tfepEyySA/N9WhcHg+rZ4/x1thP0eYJPQ2YJ\nAjimHy
            Bb+3tFs7KaOPu9G5xgbQWUWccukMDXqybqiUDSfU/T5/+XM8CKq/Fu0DBu\n3lg0NYigkZFs99lZJ1H4BkMWgL65ay
            bO4XwfZJTGLe0=\n-----END CERTIFICATE-----'}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, NodeResponse]]
    """

    kwargs = _get_kwargs(
        json_body=json_body,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
    json_body: NodeCreate,
) -> Optional[Union[Any, HTTPValidationError, NodeResponse]]:
    r"""Add Node

    Args:
        json_body (NodeCreate):  Example: {'name': 'DE node', 'address': '192.168.1.1', 'port':
            62050, 'api_port': 62051, 'add_as_new_host': True, 'certificate': '-----BEGIN CERTIFICATE-
            ----\nMIIEnDCCAoQCAQAwDQYJKoZIhvcNAQENBQAwEzERMA8GA1UEAwwIR296YXJnYWgw\nIBcNMjMwMjE5MjMwOT
            MyWhgPMjEyMzAxMjYyMzA5MzJaMBMxETAPBgNVBAMMCEdv\nemFyZ2FoMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMI
            ICCgKCAgEA0BvDh0eU78EJ\n+xzBWUjjMrWf/0rWV5fDl7b4RU8AjeviG1RmEc64ueZ3s6q1LI6DJX1+qGuqDEvp\n
            mRc09HihO07DyQgQqF38/E4CXshZ2L3UOzsa80lf74dhEqAR/EJQXXMwGSb3T9J9\nseCqCyiEn/JLEGsilDz64cTv
            8MXMAcjjpdefkFyQP+4hAKQgHbtfJ9KPSu4/lkZR\n/orsjoWGJv4LS0MsXV1t7LB/bNC7qOzlmzrfTMH4EmtmKH8H
            whMkL1nUG+vXEfwm\nQg3Ly+yrwKNw9+L7DxbKnoy2Zqp9dN+rzKDgcpHsoIYf0feInUHHlRUu303kAFQN\nGlnzZg
            D8ulHI1sQLNS3teYpj817G3EXKOhu56MvBehBR9GfvfS1D5D/QvwRfcaZI\nCULBPoGqovhrknbUXt9TEfzc9YnfSz
            lcJYcH54/aUBVJNs74EK38OQ+JciLnw4qe\ngbXEshaeLgGM3bhXwUhctcmZf5ASWDsAVtEeCXGNK+ua6wlFXKVd0j
            Ot2ZZYG42X\nwrpHCErAWY7AoxHmXlfPcPM0Uu7FuEBP27f8U3N+glG1lWrogNn54j1ZrzQVUVVv\ngog78DrjjzrR
            0puQ9x9q6FvEUTAaaA06lvi2/6BuwO0jKrHQCP7fFUmRXg5B5lrJ\n9czSDHT9WH9Sc1qdxQTevhc9C/h6MuMCAwEA
            ATANBgkqhkiG9w0BAQ0FAAOCAgEA\nI7aXhLejp53NyuwzmdfeycY373TI4sD3WfPdEB6+FSCX38YghyQl8tkeaHPg
            PKY5\n+vA+eVxE7E961UNPtJtJg/dzBvoWUroTnpvKjVdDImFaZa/PvUMgSEe8tC3FtB6i\nAp7f0yYOGsFf6oaOxM
            fs/F0sGflsaVWuiATTsV8Er+uzge77Q8AXzy6spuXg3ALF\n56tqzZY5x/04g1KUQB4JN+7JzipnfSIUof0eAKf9gQ
            bumUU+Q2b32HMC2MOlUjv+\nIl8rJ9cs0zwC1BOmqoS3Ez22dgtT7FucvIJ1MGP8oUAudMmrXDxx/d7CmnD5q1v4\n
            XFSa6Zv8LPLCz5iMbo0FjNlKyZo3699PtyBFXt3zyfTPmiy19RVGTziHqJ9NR9kW\nkBwvFzIy+qPc/dJAk435hVaV
            3pRBC7Pl2Y7k/pJxxlC07PkACXuhwtUGhQrHYWkK\niLlV21kNnWuvjS1orTwvuW3aagb6tvEEEmlMhw5a2B8sl71s
            Q6sxWidgRaOSGW7l\ng1gctfdLMARuV6LkLiGy5k2FGAW/tfepEyySA/N9WhcHg+rZ4/x1thP0eYJPQ2YJ\nAjimHy
            Bb+3tFs7KaOPu9G5xgbQWUWccukMDXqybqiUDSfU/T5/+XM8CKq/Fu0DBu\n3lg0NYigkZFs99lZJ1H4BkMWgL65ay
            bO4XwfZJTGLe0=\n-----END CERTIFICATE-----'}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, NodeResponse]
    """

    return (
        await asyncio_detailed(
            client=client,
            json_body=json_body,
        )
    ).parsed

marzban_client/api/node/add_node_api_node_post.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.node_response import NodeResponse
from ...types import Response


def _get_kwargs(
    node_id: int,
) -> Dict[str, Any]:
    pass

    return {
        "method": "get",
        "url": "/api/node/{node_id}".format(
            node_id=node_id,
        ),
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, NodeResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = NodeResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, NodeResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    node_id: int,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError, NodeResponse]]:
    """Get Node

    Args:
        node_id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, NodeResponse]]
    """

    kwargs = _get_kwargs(
        node_id=node_id,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    node_id: int,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError, NodeResponse]]:
    """Get Node

    Args:
        node_id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, NodeResponse]
    """

    return sync_detailed(
        node_id=node_id,
        client=client,
    ).parsed


async def asyncio_detailed(
    node_id: int,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError, NodeResponse]]:
    """Get Node

    Args:
        node_id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, NodeResponse]]
    """

    kwargs = _get_kwargs(
        node_id=node_id,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    node_id: int,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError, NodeResponse]]:
    """Get Node

    Args:
        node_id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, NodeResponse]
    """

    return (
        await asyncio_detailed(
            node_id=node_id,
            client=client,
        )
    ).parsed

marzban_client/api/node/get_node_api_node_node_id_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, List, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.node_response import NodeResponse
from ...types import Response


def _get_kwargs() -> Dict[str, Any]:
    pass

    return {
        "method": "get",
        "url": "/api/nodes",
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, List["NodeResponse"]]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = []
        _response_200 = response.json()
        for response_200_item_data in _response_200:
            response_200_item = NodeResponse.from_dict(response_200_item_data)

            response_200.append(response_200_item)

        return response_200
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, List["NodeResponse"]]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, List["NodeResponse"]]]:
    """Get Nodes

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, List['NodeResponse']]]
    """

    kwargs = _get_kwargs()

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, List["NodeResponse"]]]:
    """Get Nodes

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, List['NodeResponse']]
    """

    return sync_detailed(
        client=client,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, List["NodeResponse"]]]:
    """Get Nodes

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, List['NodeResponse']]]
    """

    kwargs = _get_kwargs()

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, List["NodeResponse"]]]:
    """Get Nodes

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, List['NodeResponse']]
    """

    return (
        await asyncio_detailed(
            client=client,
        )
    ).parsed

marzban_client/api/node/get_nodes_api_nodes_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.nodes_usage_response import NodesUsageResponse
from ...types import UNSET, Response, Unset


def _get_kwargs(
    *,
    start: Union[Unset, None, str] = UNSET,
    end: Union[Unset, None, str] = UNSET,
) -> Dict[str, Any]:
    pass

    params: Dict[str, Any] = {}
    params["start"] = start

    params["end"] = end

    params = {k: v for k, v in params.items() if v is not UNSET and v is not None}

    return {
        "method": "get",
        "url": "/api/nodes/usage",
        "params": params,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[HTTPValidationError, NodesUsageResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = NodesUsageResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[HTTPValidationError, NodesUsageResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
    start: Union[Unset, None, str] = UNSET,
    end: Union[Unset, None, str] = UNSET,
) -> Response[Union[HTTPValidationError, NodesUsageResponse]]:
    """Get Usage

     Get nodes usage

    Args:
        start (Union[Unset, None, str]):
        end (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[HTTPValidationError, NodesUsageResponse]]
    """

    kwargs = _get_kwargs(
        start=start,
        end=end,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
    start: Union[Unset, None, str] = UNSET,
    end: Union[Unset, None, str] = UNSET,
) -> Optional[Union[HTTPValidationError, NodesUsageResponse]]:
    """Get Usage

     Get nodes usage

    Args:
        start (Union[Unset, None, str]):
        end (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[HTTPValidationError, NodesUsageResponse]
    """

    return sync_detailed(
        client=client,
        start=start,
        end=end,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
    start: Union[Unset, None, str] = UNSET,
    end: Union[Unset, None, str] = UNSET,
) -> Response[Union[HTTPValidationError, NodesUsageResponse]]:
    """Get Usage

     Get nodes usage

    Args:
        start (Union[Unset, None, str]):
        end (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[HTTPValidationError, NodesUsageResponse]]
    """

    kwargs = _get_kwargs(
        start=start,
        end=end,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
    start: Union[Unset, None, str] = UNSET,
    end: Union[Unset, None, str] = UNSET,
) -> Optional[Union[HTTPValidationError, NodesUsageResponse]]:
    """Get Usage

     Get nodes usage

    Args:
        start (Union[Unset, None, str]):
        end (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[HTTPValidationError, NodesUsageResponse]
    """

    return (
        await asyncio_detailed(
            client=client,
            start=start,
            end=end,
        )
    ).parsed

marzban_client/api/node/get_usage_api_nodes_usage_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.node_modify import NodeModify
from ...models.node_response import NodeResponse
from ...types import Response


def _get_kwargs(
    node_id: int,
    *,
    json_body: NodeModify,
) -> Dict[str, Any]:
    pass

    json_json_body = json_body.to_dict()

    return {
        "method": "put",
        "url": "/api/node/{node_id}".format(
            node_id=node_id,
        ),
        "json": json_json_body,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, NodeResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = NodeResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, NodeResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    node_id: int,
    *,
    client: AuthenticatedClient,
    json_body: NodeModify,
) -> Response[Union[Any, HTTPValidationError, NodeResponse]]:
    r"""Modify Node

    Args:
        node_id (int):
        json_body (NodeModify):  Example: {'name': 'DE node', 'address': '192.168.1.1', 'port':
            62050, 'api_port': 62051, 'certificate': '-----BEGIN CERTIFICATE-----
            \nMIIEnDCCAoQCAQAwDQYJKoZIhvcNAQENBQAwEzERMA8GA1UEAwwIR296YXJnYWgw\nIBcNMjMwMjE5MjMwOTMyWh
            gPMjEyMzAxMjYyMzA5MzJaMBMxETAPBgNVBAMMCEdv\nemFyZ2FoMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCg
            KCAgEA0BvDh0eU78EJ\n+xzBWUjjMrWf/0rWV5fDl7b4RU8AjeviG1RmEc64ueZ3s6q1LI6DJX1+qGuqDEvp\nmRc0
            9HihO07DyQgQqF38/E4CXshZ2L3UOzsa80lf74dhEqAR/EJQXXMwGSb3T9J9\nseCqCyiEn/JLEGsilDz64cTv8MXM
            AcjjpdefkFyQP+4hAKQgHbtfJ9KPSu4/lkZR\n/orsjoWGJv4LS0MsXV1t7LB/bNC7qOzlmzrfTMH4EmtmKH8HwhMk
            L1nUG+vXEfwm\nQg3Ly+yrwKNw9+L7DxbKnoy2Zqp9dN+rzKDgcpHsoIYf0feInUHHlRUu303kAFQN\nGlnzZgD8ul
            HI1sQLNS3teYpj817G3EXKOhu56MvBehBR9GfvfS1D5D/QvwRfcaZI\nCULBPoGqovhrknbUXt9TEfzc9YnfSzlcJY
            cH54/aUBVJNs74EK38OQ+JciLnw4qe\ngbXEshaeLgGM3bhXwUhctcmZf5ASWDsAVtEeCXGNK+ua6wlFXKVd0jOt2Z
            ZYG42X\nwrpHCErAWY7AoxHmXlfPcPM0Uu7FuEBP27f8U3N+glG1lWrogNn54j1ZrzQVUVVv\ngog78DrjjzrR0puQ
            9x9q6FvEUTAaaA06lvi2/6BuwO0jKrHQCP7fFUmRXg5B5lrJ\n9czSDHT9WH9Sc1qdxQTevhc9C/h6MuMCAwEAATAN
            BgkqhkiG9w0BAQ0FAAOCAgEA\nI7aXhLejp53NyuwzmdfeycY373TI4sD3WfPdEB6+FSCX38YghyQl8tkeaHPgPKY5
            \n+vA+eVxE7E961UNPtJtJg/dzBvoWUroTnpvKjVdDImFaZa/PvUMgSEe8tC3FtB6i\nAp7f0yYOGsFf6oaOxMfs/F
            0sGflsaVWuiATTsV8Er+uzge77Q8AXzy6spuXg3ALF\n56tqzZY5x/04g1KUQB4JN+7JzipnfSIUof0eAKf9gQbumU
            U+Q2b32HMC2MOlUjv+\nIl8rJ9cs0zwC1BOmqoS3Ez22dgtT7FucvIJ1MGP8oUAudMmrXDxx/d7CmnD5q1v4\nXFSa
            6Zv8LPLCz5iMbo0FjNlKyZo3699PtyBFXt3zyfTPmiy19RVGTziHqJ9NR9kW\nkBwvFzIy+qPc/dJAk435hVaV3pRB
            C7Pl2Y7k/pJxxlC07PkACXuhwtUGhQrHYWkK\niLlV21kNnWuvjS1orTwvuW3aagb6tvEEEmlMhw5a2B8sl71sQ6sx
            WidgRaOSGW7l\ng1gctfdLMARuV6LkLiGy5k2FGAW/tfepEyySA/N9WhcHg+rZ4/x1thP0eYJPQ2YJ\nAjimHyBb+3
            tFs7KaOPu9G5xgbQWUWccukMDXqybqiUDSfU/T5/+XM8CKq/Fu0DBu\n3lg0NYigkZFs99lZJ1H4BkMWgL65aybO4X
            wfZJTGLe0=\n-----END CERTIFICATE-----'}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, NodeResponse]]
    """

    kwargs = _get_kwargs(
        node_id=node_id,
        json_body=json_body,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    node_id: int,
    *,
    client: AuthenticatedClient,
    json_body: NodeModify,
) -> Optional[Union[Any, HTTPValidationError, NodeResponse]]:
    r"""Modify Node

    Args:
        node_id (int):
        json_body (NodeModify):  Example: {'name': 'DE node', 'address': '192.168.1.1', 'port':
            62050, 'api_port': 62051, 'certificate': '-----BEGIN CERTIFICATE-----
            \nMIIEnDCCAoQCAQAwDQYJKoZIhvcNAQENBQAwEzERMA8GA1UEAwwIR296YXJnYWgw\nIBcNMjMwMjE5MjMwOTMyWh
            gPMjEyMzAxMjYyMzA5MzJaMBMxETAPBgNVBAMMCEdv\nemFyZ2FoMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCg
            KCAgEA0BvDh0eU78EJ\n+xzBWUjjMrWf/0rWV5fDl7b4RU8AjeviG1RmEc64ueZ3s6q1LI6DJX1+qGuqDEvp\nmRc0
            9HihO07DyQgQqF38/E4CXshZ2L3UOzsa80lf74dhEqAR/EJQXXMwGSb3T9J9\nseCqCyiEn/JLEGsilDz64cTv8MXM
            AcjjpdefkFyQP+4hAKQgHbtfJ9KPSu4/lkZR\n/orsjoWGJv4LS0MsXV1t7LB/bNC7qOzlmzrfTMH4EmtmKH8HwhMk
            L1nUG+vXEfwm\nQg3Ly+yrwKNw9+L7DxbKnoy2Zqp9dN+rzKDgcpHsoIYf0feInUHHlRUu303kAFQN\nGlnzZgD8ul
            HI1sQLNS3teYpj817G3EXKOhu56MvBehBR9GfvfS1D5D/QvwRfcaZI\nCULBPoGqovhrknbUXt9TEfzc9YnfSzlcJY
            cH54/aUBVJNs74EK38OQ+JciLnw4qe\ngbXEshaeLgGM3bhXwUhctcmZf5ASWDsAVtEeCXGNK+ua6wlFXKVd0jOt2Z
            ZYG42X\nwrpHCErAWY7AoxHmXlfPcPM0Uu7FuEBP27f8U3N+glG1lWrogNn54j1ZrzQVUVVv\ngog78DrjjzrR0puQ
            9x9q6FvEUTAaaA06lvi2/6BuwO0jKrHQCP7fFUmRXg5B5lrJ\n9czSDHT9WH9Sc1qdxQTevhc9C/h6MuMCAwEAATAN
            BgkqhkiG9w0BAQ0FAAOCAgEA\nI7aXhLejp53NyuwzmdfeycY373TI4sD3WfPdEB6+FSCX38YghyQl8tkeaHPgPKY5
            \n+vA+eVxE7E961UNPtJtJg/dzBvoWUroTnpvKjVdDImFaZa/PvUMgSEe8tC3FtB6i\nAp7f0yYOGsFf6oaOxMfs/F
            0sGflsaVWuiATTsV8Er+uzge77Q8AXzy6spuXg3ALF\n56tqzZY5x/04g1KUQB4JN+7JzipnfSIUof0eAKf9gQbumU
            U+Q2b32HMC2MOlUjv+\nIl8rJ9cs0zwC1BOmqoS3Ez22dgtT7FucvIJ1MGP8oUAudMmrXDxx/d7CmnD5q1v4\nXFSa
            6Zv8LPLCz5iMbo0FjNlKyZo3699PtyBFXt3zyfTPmiy19RVGTziHqJ9NR9kW\nkBwvFzIy+qPc/dJAk435hVaV3pRB
            C7Pl2Y7k/pJxxlC07PkACXuhwtUGhQrHYWkK\niLlV21kNnWuvjS1orTwvuW3aagb6tvEEEmlMhw5a2B8sl71sQ6sx
            WidgRaOSGW7l\ng1gctfdLMARuV6LkLiGy5k2FGAW/tfepEyySA/N9WhcHg+rZ4/x1thP0eYJPQ2YJ\nAjimHyBb+3
            tFs7KaOPu9G5xgbQWUWccukMDXqybqiUDSfU/T5/+XM8CKq/Fu0DBu\n3lg0NYigkZFs99lZJ1H4BkMWgL65aybO4X
            wfZJTGLe0=\n-----END CERTIFICATE-----'}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, NodeResponse]
    """

    return sync_detailed(
        node_id=node_id,
        client=client,
        json_body=json_body,
    ).parsed


async def asyncio_detailed(
    node_id: int,
    *,
    client: AuthenticatedClient,
    json_body: NodeModify,
) -> Response[Union[Any, HTTPValidationError, NodeResponse]]:
    r"""Modify Node

    Args:
        node_id (int):
        json_body (NodeModify):  Example: {'name': 'DE node', 'address': '192.168.1.1', 'port':
            62050, 'api_port': 62051, 'certificate': '-----BEGIN CERTIFICATE-----
            \nMIIEnDCCAoQCAQAwDQYJKoZIhvcNAQENBQAwEzERMA8GA1UEAwwIR296YXJnYWgw\nIBcNMjMwMjE5MjMwOTMyWh
            gPMjEyMzAxMjYyMzA5MzJaMBMxETAPBgNVBAMMCEdv\nemFyZ2FoMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCg
            KCAgEA0BvDh0eU78EJ\n+xzBWUjjMrWf/0rWV5fDl7b4RU8AjeviG1RmEc64ueZ3s6q1LI6DJX1+qGuqDEvp\nmRc0
            9HihO07DyQgQqF38/E4CXshZ2L3UOzsa80lf74dhEqAR/EJQXXMwGSb3T9J9\nseCqCyiEn/JLEGsilDz64cTv8MXM
            AcjjpdefkFyQP+4hAKQgHbtfJ9KPSu4/lkZR\n/orsjoWGJv4LS0MsXV1t7LB/bNC7qOzlmzrfTMH4EmtmKH8HwhMk
            L1nUG+vXEfwm\nQg3Ly+yrwKNw9+L7DxbKnoy2Zqp9dN+rzKDgcpHsoIYf0feInUHHlRUu303kAFQN\nGlnzZgD8ul
            HI1sQLNS3teYpj817G3EXKOhu56MvBehBR9GfvfS1D5D/QvwRfcaZI\nCULBPoGqovhrknbUXt9TEfzc9YnfSzlcJY
            cH54/aUBVJNs74EK38OQ+JciLnw4qe\ngbXEshaeLgGM3bhXwUhctcmZf5ASWDsAVtEeCXGNK+ua6wlFXKVd0jOt2Z
            ZYG42X\nwrpHCErAWY7AoxHmXlfPcPM0Uu7FuEBP27f8U3N+glG1lWrogNn54j1ZrzQVUVVv\ngog78DrjjzrR0puQ
            9x9q6FvEUTAaaA06lvi2/6BuwO0jKrHQCP7fFUmRXg5B5lrJ\n9czSDHT9WH9Sc1qdxQTevhc9C/h6MuMCAwEAATAN
            BgkqhkiG9w0BAQ0FAAOCAgEA\nI7aXhLejp53NyuwzmdfeycY373TI4sD3WfPdEB6+FSCX38YghyQl8tkeaHPgPKY5
            \n+vA+eVxE7E961UNPtJtJg/dzBvoWUroTnpvKjVdDImFaZa/PvUMgSEe8tC3FtB6i\nAp7f0yYOGsFf6oaOxMfs/F
            0sGflsaVWuiATTsV8Er+uzge77Q8AXzy6spuXg3ALF\n56tqzZY5x/04g1KUQB4JN+7JzipnfSIUof0eAKf9gQbumU
            U+Q2b32HMC2MOlUjv+\nIl8rJ9cs0zwC1BOmqoS3Ez22dgtT7FucvIJ1MGP8oUAudMmrXDxx/d7CmnD5q1v4\nXFSa
            6Zv8LPLCz5iMbo0FjNlKyZo3699PtyBFXt3zyfTPmiy19RVGTziHqJ9NR9kW\nkBwvFzIy+qPc/dJAk435hVaV3pRB
            C7Pl2Y7k/pJxxlC07PkACXuhwtUGhQrHYWkK\niLlV21kNnWuvjS1orTwvuW3aagb6tvEEEmlMhw5a2B8sl71sQ6sx
            WidgRaOSGW7l\ng1gctfdLMARuV6LkLiGy5k2FGAW/tfepEyySA/N9WhcHg+rZ4/x1thP0eYJPQ2YJ\nAjimHyBb+3
            tFs7KaOPu9G5xgbQWUWccukMDXqybqiUDSfU/T5/+XM8CKq/Fu0DBu\n3lg0NYigkZFs99lZJ1H4BkMWgL65aybO4X
            wfZJTGLe0=\n-----END CERTIFICATE-----'}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, NodeResponse]]
    """

    kwargs = _get_kwargs(
        node_id=node_id,
        json_body=json_body,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    node_id: int,
    *,
    client: AuthenticatedClient,
    json_body: NodeModify,
) -> Optional[Union[Any, HTTPValidationError, NodeResponse]]:
    r"""Modify Node

    Args:
        node_id (int):
        json_body (NodeModify):  Example: {'name': 'DE node', 'address': '192.168.1.1', 'port':
            62050, 'api_port': 62051, 'certificate': '-----BEGIN CERTIFICATE-----
            \nMIIEnDCCAoQCAQAwDQYJKoZIhvcNAQENBQAwEzERMA8GA1UEAwwIR296YXJnYWgw\nIBcNMjMwMjE5MjMwOTMyWh
            gPMjEyMzAxMjYyMzA5MzJaMBMxETAPBgNVBAMMCEdv\nemFyZ2FoMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCg
            KCAgEA0BvDh0eU78EJ\n+xzBWUjjMrWf/0rWV5fDl7b4RU8AjeviG1RmEc64ueZ3s6q1LI6DJX1+qGuqDEvp\nmRc0
            9HihO07DyQgQqF38/E4CXshZ2L3UOzsa80lf74dhEqAR/EJQXXMwGSb3T9J9\nseCqCyiEn/JLEGsilDz64cTv8MXM
            AcjjpdefkFyQP+4hAKQgHbtfJ9KPSu4/lkZR\n/orsjoWGJv4LS0MsXV1t7LB/bNC7qOzlmzrfTMH4EmtmKH8HwhMk
            L1nUG+vXEfwm\nQg3Ly+yrwKNw9+L7DxbKnoy2Zqp9dN+rzKDgcpHsoIYf0feInUHHlRUu303kAFQN\nGlnzZgD8ul
            HI1sQLNS3teYpj817G3EXKOhu56MvBehBR9GfvfS1D5D/QvwRfcaZI\nCULBPoGqovhrknbUXt9TEfzc9YnfSzlcJY
            cH54/aUBVJNs74EK38OQ+JciLnw4qe\ngbXEshaeLgGM3bhXwUhctcmZf5ASWDsAVtEeCXGNK+ua6wlFXKVd0jOt2Z
            ZYG42X\nwrpHCErAWY7AoxHmXlfPcPM0Uu7FuEBP27f8U3N+glG1lWrogNn54j1ZrzQVUVVv\ngog78DrjjzrR0puQ
            9x9q6FvEUTAaaA06lvi2/6BuwO0jKrHQCP7fFUmRXg5B5lrJ\n9czSDHT9WH9Sc1qdxQTevhc9C/h6MuMCAwEAATAN
            BgkqhkiG9w0BAQ0FAAOCAgEA\nI7aXhLejp53NyuwzmdfeycY373TI4sD3WfPdEB6+FSCX38YghyQl8tkeaHPgPKY5
            \n+vA+eVxE7E961UNPtJtJg/dzBvoWUroTnpvKjVdDImFaZa/PvUMgSEe8tC3FtB6i\nAp7f0yYOGsFf6oaOxMfs/F
            0sGflsaVWuiATTsV8Er+uzge77Q8AXzy6spuXg3ALF\n56tqzZY5x/04g1KUQB4JN+7JzipnfSIUof0eAKf9gQbumU
            U+Q2b32HMC2MOlUjv+\nIl8rJ9cs0zwC1BOmqoS3Ez22dgtT7FucvIJ1MGP8oUAudMmrXDxx/d7CmnD5q1v4\nXFSa
            6Zv8LPLCz5iMbo0FjNlKyZo3699PtyBFXt3zyfTPmiy19RVGTziHqJ9NR9kW\nkBwvFzIy+qPc/dJAk435hVaV3pRB
            C7Pl2Y7k/pJxxlC07PkACXuhwtUGhQrHYWkK\niLlV21kNnWuvjS1orTwvuW3aagb6tvEEEmlMhw5a2B8sl71sQ6sx
            WidgRaOSGW7l\ng1gctfdLMARuV6LkLiGy5k2FGAW/tfepEyySA/N9WhcHg+rZ4/x1thP0eYJPQ2YJ\nAjimHyBb+3
            tFs7KaOPu9G5xgbQWUWccukMDXqybqiUDSfU/T5/+XM8CKq/Fu0DBu\n3lg0NYigkZFs99lZJ1H4BkMWgL65aybO4X
            wfZJTGLe0=\n-----END CERTIFICATE-----'}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, NodeResponse]
    """

    return (
        await asyncio_detailed(
            node_id=node_id,
            client=client,
            json_body=json_body,
        )
    ).parsed

marzban_client/api/node/modify_node_api_node_node_id_put.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...types import Response


def _get_kwargs(
    node_id: int,
) -> Dict[str, Any]:
    pass

    return {
        "method": "post",
        "url": "/api/node/{node_id}/reconnect".format(
            node_id=node_id,
        ),
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = cast(Any, response.json())
        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    node_id: int,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError]]:
    """Reconnect Node

    Args:
        node_id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        node_id=node_id,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    node_id: int,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError]]:
    """Reconnect Node

    Args:
        node_id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError]
    """

    return sync_detailed(
        node_id=node_id,
        client=client,
    ).parsed


async def asyncio_detailed(
    node_id: int,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError]]:
    """Reconnect Node

    Args:
        node_id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        node_id=node_id,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    node_id: int,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError]]:
    """Reconnect Node

    Args:
        node_id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError]
    """

    return (
        await asyncio_detailed(
            node_id=node_id,
            client=client,
        )
    ).parsed

marzban_client/api/node/reconnect_node_api_node_node_id_reconnect_post.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...types import Response


def _get_kwargs(
    node_id: int,
) -> Dict[str, Any]:
    pass

    return {
        "method": "delete",
        "url": "/api/node/{node_id}".format(
            node_id=node_id,
        ),
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = cast(Any, response.json())
        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    node_id: int,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError]]:
    """Remove Node

    Args:
        node_id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        node_id=node_id,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    node_id: int,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError]]:
    """Remove Node

    Args:
        node_id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError]
    """

    return sync_detailed(
        node_id=node_id,
        client=client,
    ).parsed


async def asyncio_detailed(
    node_id: int,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError]]:
    """Remove Node

    Args:
        node_id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        node_id=node_id,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    node_id: int,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError]]:
    """Remove Node

    Args:
        node_id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError]
    """

    return (
        await asyncio_detailed(
            node_id=node_id,
            client=client,
        )
    ).parsed

marzban_client/api/node/remove_node_api_node_node_id_delete.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.user_response import UserResponse
from ...types import Response


def _get_kwargs(
    token: str,
) -> Dict[str, Any]:
    pass

    return {
        "method": "get",
        "url": "/sub/{token}/info".format(
            token=token,
        ),
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[HTTPValidationError, UserResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = UserResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[HTTPValidationError, UserResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    token: str,
    *,
    client: Union[AuthenticatedClient, Client],
) -> Response[Union[HTTPValidationError, UserResponse]]:
    """User Subcription Info

    Args:
        token (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[HTTPValidationError, UserResponse]]
    """

    kwargs = _get_kwargs(
        token=token,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    token: str,
    *,
    client: Union[AuthenticatedClient, Client],
) -> Optional[Union[HTTPValidationError, UserResponse]]:
    """User Subcription Info

    Args:
        token (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[HTTPValidationError, UserResponse]
    """

    return sync_detailed(
        token=token,
        client=client,
    ).parsed


async def asyncio_detailed(
    token: str,
    *,
    client: Union[AuthenticatedClient, Client],
) -> Response[Union[HTTPValidationError, UserResponse]]:
    """User Subcription Info

    Args:
        token (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[HTTPValidationError, UserResponse]]
    """

    kwargs = _get_kwargs(
        token=token,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    token: str,
    *,
    client: Union[AuthenticatedClient, Client],
) -> Optional[Union[HTTPValidationError, UserResponse]]:
    """User Subcription Info

    Args:
        token (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[HTTPValidationError, UserResponse]
    """

    return (
        await asyncio_detailed(
            token=token,
            client=client,
        )
    ).parsed

marzban_client/api/subscription/user_subcription_info_sub_token_info_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...types import Response, Unset


def _get_kwargs(
    token: str,
    *,
    user_agent: Union[Unset, str] = "",
) -> Dict[str, Any]:
    headers = {}
    if not isinstance(user_agent, Unset):
        headers["user-agent"] = user_agent

    return {
        "method": "get",
        "url": "/sub/{token}/".format(
            token=token,
        ),
        "headers": headers,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = cast(Any, response.json())
        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    token: str,
    *,
    client: Union[AuthenticatedClient, Client],
    user_agent: Union[Unset, str] = "",
) -> Response[Union[Any, HTTPValidationError]]:
    """User Subcription

     Subscription link, V2ray and Clash supported

    Args:
        token (str):
        user_agent (Union[Unset, str]):  Default: ''.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        token=token,
        user_agent=user_agent,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    token: str,
    *,
    client: Union[AuthenticatedClient, Client],
    user_agent: Union[Unset, str] = "",
) -> Optional[Union[Any, HTTPValidationError]]:
    """User Subcription

     Subscription link, V2ray and Clash supported

    Args:
        token (str):
        user_agent (Union[Unset, str]):  Default: ''.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError]
    """

    return sync_detailed(
        token=token,
        client=client,
        user_agent=user_agent,
    ).parsed


async def asyncio_detailed(
    token: str,
    *,
    client: Union[AuthenticatedClient, Client],
    user_agent: Union[Unset, str] = "",
) -> Response[Union[Any, HTTPValidationError]]:
    """User Subcription

     Subscription link, V2ray and Clash supported

    Args:
        token (str):
        user_agent (Union[Unset, str]):  Default: ''.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        token=token,
        user_agent=user_agent,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    token: str,
    *,
    client: Union[AuthenticatedClient, Client],
    user_agent: Union[Unset, str] = "",
) -> Optional[Union[Any, HTTPValidationError]]:
    """User Subcription

     Subscription link, V2ray and Clash supported

    Args:
        token (str):
        user_agent (Union[Unset, str]):  Default: ''.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError]
    """

    return (
        await asyncio_detailed(
            token=token,
            client=client,
            user_agent=user_agent,
        )
    ).parsed

marzban_client/api/subscription/user_subcription_sub_token_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.get_hosts_response import GetHostsResponse
from ...types import Response


def _get_kwargs() -> Dict[str, Any]:
    pass

    return {
        "method": "get",
        "url": "/api/hosts",
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[GetHostsResponse]:
    if response.status_code == HTTPStatus.OK:
        response_200 = GetHostsResponse.from_dict(response.json())

        return response_200
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[GetHostsResponse]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[GetHostsResponse]:
    """Get Hosts

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[GetHostsResponse]
    """

    kwargs = _get_kwargs()

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
) -> Optional[GetHostsResponse]:
    """Get Hosts

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        GetHostsResponse
    """

    return sync_detailed(
        client=client,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[GetHostsResponse]:
    """Get Hosts

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[GetHostsResponse]
    """

    kwargs = _get_kwargs()

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
) -> Optional[GetHostsResponse]:
    """Get Hosts

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        GetHostsResponse
    """

    return (
        await asyncio_detailed(
            client=client,
        )
    ).parsed

marzban_client/api/system/get_hosts_api_hosts_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.get_inbounds_response import GetInboundsResponse
from ...types import Response


def _get_kwargs() -> Dict[str, Any]:
    pass

    return {
        "method": "get",
        "url": "/api/inbounds",
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[GetInboundsResponse]:
    if response.status_code == HTTPStatus.OK:
        response_200 = GetInboundsResponse.from_dict(response.json())

        return response_200
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[GetInboundsResponse]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[GetInboundsResponse]:
    """Get Inbounds

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[GetInboundsResponse]
    """

    kwargs = _get_kwargs()

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
) -> Optional[GetInboundsResponse]:
    """Get Inbounds

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        GetInboundsResponse
    """

    return sync_detailed(
        client=client,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[GetInboundsResponse]:
    """Get Inbounds

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[GetInboundsResponse]
    """

    kwargs = _get_kwargs()

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
) -> Optional[GetInboundsResponse]:
    """Get Inbounds

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        GetInboundsResponse
    """

    return (
        await asyncio_detailed(
            client=client,
        )
    ).parsed

marzban_client/api/system/get_inbounds_api_inbounds_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.system_stats import SystemStats
from ...types import Response


def _get_kwargs() -> Dict[str, Any]:
    pass

    return {
        "method": "get",
        "url": "/api/system",
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[SystemStats]:
    if response.status_code == HTTPStatus.OK:
        response_200 = SystemStats.from_dict(response.json())

        return response_200
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[SystemStats]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[SystemStats]:
    """Get System Stats

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[SystemStats]
    """

    kwargs = _get_kwargs()

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
) -> Optional[SystemStats]:
    """Get System Stats

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        SystemStats
    """

    return sync_detailed(
        client=client,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[SystemStats]:
    """Get System Stats

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[SystemStats]
    """

    kwargs = _get_kwargs()

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
) -> Optional[SystemStats]:
    """Get System Stats

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        SystemStats
    """

    return (
        await asyncio_detailed(
            client=client,
        )
    ).parsed

marzban_client/api/system/get_system_stats_api_system_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.modify_hosts_api_hosts_put_modified_hosts import (
    ModifyHostsApiHostsPutModifiedHosts,
)
from ...models.modify_hosts_api_hosts_put_response_modify_hosts_api_hosts_put import (
    ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut,
)
from ...types import Response


def _get_kwargs(
    *,
    json_body: ModifyHostsApiHostsPutModifiedHosts,
) -> Dict[str, Any]:
    pass

    json_json_body = json_body.to_dict()

    return {
        "method": "put",
        "url": "/api/hosts",
        "json": json_json_body,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[
    Union[
        Any, HTTPValidationError, ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut
    ]
]:
    if response.status_code == HTTPStatus.OK:
        response_200 = ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut.from_dict(
            response.json()
        )

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[
    Union[
        Any, HTTPValidationError, ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut
    ]
]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
    json_body: ModifyHostsApiHostsPutModifiedHosts,
) -> Response[
    Union[
        Any, HTTPValidationError, ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut
    ]
]:
    """Modify Hosts

    Args:
        json_body (ModifyHostsApiHostsPutModifiedHosts):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut]]
    """

    kwargs = _get_kwargs(
        json_body=json_body,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
    json_body: ModifyHostsApiHostsPutModifiedHosts,
) -> Optional[
    Union[
        Any, HTTPValidationError, ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut
    ]
]:
    """Modify Hosts

    Args:
        json_body (ModifyHostsApiHostsPutModifiedHosts):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut]
    """

    return sync_detailed(
        client=client,
        json_body=json_body,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
    json_body: ModifyHostsApiHostsPutModifiedHosts,
) -> Response[
    Union[
        Any, HTTPValidationError, ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut
    ]
]:
    """Modify Hosts

    Args:
        json_body (ModifyHostsApiHostsPutModifiedHosts):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut]]
    """

    kwargs = _get_kwargs(
        json_body=json_body,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
    json_body: ModifyHostsApiHostsPutModifiedHosts,
) -> Optional[
    Union[
        Any, HTTPValidationError, ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut
    ]
]:
    """Modify Hosts

    Args:
        json_body (ModifyHostsApiHostsPutModifiedHosts):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut]
    """

    return (
        await asyncio_detailed(
            client=client,
            json_body=json_body,
        )
    ).parsed

marzban_client/api/system/modify_hosts_api_hosts_put.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.user_create import UserCreate
from ...models.user_response import UserResponse
from ...types import Response


def _get_kwargs(
    *,
    json_body: UserCreate,
) -> Dict[str, Any]:
    pass

    json_json_body = json_body.to_dict()

    return {
        "method": "post",
        "url": "/api/user",
        "json": json_json_body,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = UserResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.CONFLICT:
        response_409 = cast(Any, None)
        return response_409
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
    json_body: UserCreate,
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    """Add User

     Add a new user

    - **username** must have 3 to 32 characters and is allowed to contain a-z, 0-9, and underscores in
    between
    - **expire** must be an UTC timestamp
    - **data_limit** must be in Bytes, e.g. 1073741824B = 1GB
    - **proxies** dictionary of protocol:settings
    - **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds

    Args:
        json_body (UserCreate):  Example: {'username': 'user1234', 'proxies': {'vmess': {'id':
            '35e4e39c-7d5c-4f4b-8b71-558e4f37ff53'}, 'vless': {}}, 'inbounds': {'vmess': ['VMess TCP',
            'VMess Websocket'], 'vless': ['VLESS TCP REALITY', 'VLESS GRPC REALITY']}, 'expire': 0,
            'data_limit': 0, 'data_limit_reset_strategy': 'no_reset', 'note': ''}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserResponse]]
    """

    kwargs = _get_kwargs(
        json_body=json_body,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
    json_body: UserCreate,
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    """Add User

     Add a new user

    - **username** must have 3 to 32 characters and is allowed to contain a-z, 0-9, and underscores in
    between
    - **expire** must be an UTC timestamp
    - **data_limit** must be in Bytes, e.g. 1073741824B = 1GB
    - **proxies** dictionary of protocol:settings
    - **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds

    Args:
        json_body (UserCreate):  Example: {'username': 'user1234', 'proxies': {'vmess': {'id':
            '35e4e39c-7d5c-4f4b-8b71-558e4f37ff53'}, 'vless': {}}, 'inbounds': {'vmess': ['VMess TCP',
            'VMess Websocket'], 'vless': ['VLESS TCP REALITY', 'VLESS GRPC REALITY']}, 'expire': 0,
            'data_limit': 0, 'data_limit_reset_strategy': 'no_reset', 'note': ''}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserResponse]
    """

    return sync_detailed(
        client=client,
        json_body=json_body,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
    json_body: UserCreate,
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    """Add User

     Add a new user

    - **username** must have 3 to 32 characters and is allowed to contain a-z, 0-9, and underscores in
    between
    - **expire** must be an UTC timestamp
    - **data_limit** must be in Bytes, e.g. 1073741824B = 1GB
    - **proxies** dictionary of protocol:settings
    - **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds

    Args:
        json_body (UserCreate):  Example: {'username': 'user1234', 'proxies': {'vmess': {'id':
            '35e4e39c-7d5c-4f4b-8b71-558e4f37ff53'}, 'vless': {}}, 'inbounds': {'vmess': ['VMess TCP',
            'VMess Websocket'], 'vless': ['VLESS TCP REALITY', 'VLESS GRPC REALITY']}, 'expire': 0,
            'data_limit': 0, 'data_limit_reset_strategy': 'no_reset', 'note': ''}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserResponse]]
    """

    kwargs = _get_kwargs(
        json_body=json_body,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
    json_body: UserCreate,
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    """Add User

     Add a new user

    - **username** must have 3 to 32 characters and is allowed to contain a-z, 0-9, and underscores in
    between
    - **expire** must be an UTC timestamp
    - **data_limit** must be in Bytes, e.g. 1073741824B = 1GB
    - **proxies** dictionary of protocol:settings
    - **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds

    Args:
        json_body (UserCreate):  Example: {'username': 'user1234', 'proxies': {'vmess': {'id':
            '35e4e39c-7d5c-4f4b-8b71-558e4f37ff53'}, 'vless': {}}, 'inbounds': {'vmess': ['VMess TCP',
            'VMess Websocket'], 'vless': ['VLESS TCP REALITY', 'VLESS GRPC REALITY']}, 'expire': 0,
            'data_limit': 0, 'data_limit_reset_strategy': 'no_reset', 'note': ''}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserResponse]
    """

    return (
        await asyncio_detailed(
            client=client,
            json_body=json_body,
        )
    ).parsed

marzban_client/api/user/add_user_api_user_post.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.user_response import UserResponse
from ...types import Response


def _get_kwargs(
    username: str,
) -> Dict[str, Any]:
    pass

    return {
        "method": "get",
        "url": "/api/user/{username}".format(
            username=username,
        ),
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = UserResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    """Get User

     Get users information

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserResponse]]
    """

    kwargs = _get_kwargs(
        username=username,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    """Get User

     Get users information

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserResponse]
    """

    return sync_detailed(
        username=username,
        client=client,
    ).parsed


async def asyncio_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    """Get User

     Get users information

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserResponse]]
    """

    kwargs = _get_kwargs(
        username=username,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    """Get User

     Get users information

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserResponse]
    """

    return (
        await asyncio_detailed(
            username=username,
            client=client,
        )
    ).parsed

marzban_client/api/user/get_user_api_user_username_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.user_usages_response import UserUsagesResponse
from ...types import UNSET, Response, Unset


def _get_kwargs(
    username: str,
    *,
    start: Union[Unset, None, str] = UNSET,
    end: Union[Unset, None, str] = UNSET,
) -> Dict[str, Any]:
    pass

    params: Dict[str, Any] = {}
    params["start"] = start

    params["end"] = end

    params = {k: v for k, v in params.items() if v is not UNSET and v is not None}

    return {
        "method": "get",
        "url": "/api/user/{username}/usage".format(
            username=username,
        ),
        "params": params,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, UserUsagesResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = UserUsagesResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, UserUsagesResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
    start: Union[Unset, None, str] = UNSET,
    end: Union[Unset, None, str] = UNSET,
) -> Response[Union[Any, HTTPValidationError, UserUsagesResponse]]:
    """Get User

     Get users usage

    Args:
        username (str):
        start (Union[Unset, None, str]):
        end (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserUsagesResponse]]
    """

    kwargs = _get_kwargs(
        username=username,
        start=start,
        end=end,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    username: str,
    *,
    client: AuthenticatedClient,
    start: Union[Unset, None, str] = UNSET,
    end: Union[Unset, None, str] = UNSET,
) -> Optional[Union[Any, HTTPValidationError, UserUsagesResponse]]:
    """Get User

     Get users usage

    Args:
        username (str):
        start (Union[Unset, None, str]):
        end (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserUsagesResponse]
    """

    return sync_detailed(
        username=username,
        client=client,
        start=start,
        end=end,
    ).parsed


async def asyncio_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
    start: Union[Unset, None, str] = UNSET,
    end: Union[Unset, None, str] = UNSET,
) -> Response[Union[Any, HTTPValidationError, UserUsagesResponse]]:
    """Get User

     Get users usage

    Args:
        username (str):
        start (Union[Unset, None, str]):
        end (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserUsagesResponse]]
    """

    kwargs = _get_kwargs(
        username=username,
        start=start,
        end=end,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    username: str,
    *,
    client: AuthenticatedClient,
    start: Union[Unset, None, str] = UNSET,
    end: Union[Unset, None, str] = UNSET,
) -> Optional[Union[Any, HTTPValidationError, UserUsagesResponse]]:
    """Get User

     Get users usage

    Args:
        username (str):
        start (Union[Unset, None, str]):
        end (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserUsagesResponse]
    """

    return (
        await asyncio_detailed(
            username=username,
            client=client,
            start=start,
            end=end,
        )
    ).parsed

marzban_client/api/user/get_user_api_user_username_usage_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.user_status import UserStatus
from ...models.users_response import UsersResponse
from ...types import UNSET, Response, Unset


def _get_kwargs(
    *,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
    username: Union[Unset, None, str] = UNSET,
    status: Union[Unset, None, UserStatus] = UNSET,
    sort: Union[Unset, None, str] = UNSET,
) -> Dict[str, Any]:
    pass

    params: Dict[str, Any] = {}
    params["offset"] = offset

    params["limit"] = limit

    params["username"] = username

    json_status: Union[Unset, None, str] = UNSET
    if not isinstance(status, Unset):
        json_status = status.value if status else None

    params["status"] = json_status

    params["sort"] = sort

    params = {k: v for k, v in params.items() if v is not UNSET and v is not None}

    return {
        "method": "get",
        "url": "/api/users",
        "params": params,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[HTTPValidationError, UsersResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = UsersResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[HTTPValidationError, UsersResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
    username: Union[Unset, None, str] = UNSET,
    status: Union[Unset, None, UserStatus] = UNSET,
    sort: Union[Unset, None, str] = UNSET,
) -> Response[Union[HTTPValidationError, UsersResponse]]:
    """Get Users

     Get all users

    Args:
        offset (Union[Unset, None, int]):
        limit (Union[Unset, None, int]):
        username (Union[Unset, None, str]):
        status (Union[Unset, None, UserStatus]): An enumeration.
        sort (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[HTTPValidationError, UsersResponse]]
    """

    kwargs = _get_kwargs(
        offset=offset,
        limit=limit,
        username=username,
        status=status,
        sort=sort,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
    username: Union[Unset, None, str] = UNSET,
    status: Union[Unset, None, UserStatus] = UNSET,
    sort: Union[Unset, None, str] = UNSET,
) -> Optional[Union[HTTPValidationError, UsersResponse]]:
    """Get Users

     Get all users

    Args:
        offset (Union[Unset, None, int]):
        limit (Union[Unset, None, int]):
        username (Union[Unset, None, str]):
        status (Union[Unset, None, UserStatus]): An enumeration.
        sort (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[HTTPValidationError, UsersResponse]
    """

    return sync_detailed(
        client=client,
        offset=offset,
        limit=limit,
        username=username,
        status=status,
        sort=sort,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
    username: Union[Unset, None, str] = UNSET,
    status: Union[Unset, None, UserStatus] = UNSET,
    sort: Union[Unset, None, str] = UNSET,
) -> Response[Union[HTTPValidationError, UsersResponse]]:
    """Get Users

     Get all users

    Args:
        offset (Union[Unset, None, int]):
        limit (Union[Unset, None, int]):
        username (Union[Unset, None, str]):
        status (Union[Unset, None, UserStatus]): An enumeration.
        sort (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[HTTPValidationError, UsersResponse]]
    """

    kwargs = _get_kwargs(
        offset=offset,
        limit=limit,
        username=username,
        status=status,
        sort=sort,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
    username: Union[Unset, None, str] = UNSET,
    status: Union[Unset, None, UserStatus] = UNSET,
    sort: Union[Unset, None, str] = UNSET,
) -> Optional[Union[HTTPValidationError, UsersResponse]]:
    """Get Users

     Get all users

    Args:
        offset (Union[Unset, None, int]):
        limit (Union[Unset, None, int]):
        username (Union[Unset, None, str]):
        status (Union[Unset, None, UserStatus]): An enumeration.
        sort (Union[Unset, None, str]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[HTTPValidationError, UsersResponse]
    """

    return (
        await asyncio_detailed(
            client=client,
            offset=offset,
            limit=limit,
            username=username,
            status=status,
            sort=sort,
        )
    ).parsed

marzban_client/api/user/get_users_api_users_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.user_modify import UserModify
from ...models.user_response import UserResponse
from ...types import Response


def _get_kwargs(
    username: str,
    *,
    json_body: UserModify,
) -> Dict[str, Any]:
    pass

    json_json_body = json_body.to_dict()

    return {
        "method": "put",
        "url": "/api/user/{username}".format(
            username=username,
        ),
        "json": json_json_body,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = UserResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
    json_body: UserModify,
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    """Modify User

     Modify a user

    - set **expire** to 0 to make the user unlimited in time, null to no change
    - set **data_limit** to 0 to make the user unlimited in data, null to no change
    - **proxies** dictionary of protocol:settings, empty means no change
    - **inbounds** dictionary of protocol:inbound_tags, empty means no change

    Args:
        username (str):
        json_body (UserModify):  Example: {'proxies': {'vmess': {'id':
            '35e4e39c-7d5c-4f4b-8b71-558e4f37ff53'}, 'vless': {}}, 'inbounds': {'vmess': ['VMess TCP',
            'VMess Websocket'], 'vless': ['VLESS TCP REALITY', 'VLESS GRPC REALITY']}, 'expire': 0,
            'data_limit': 0, 'data_limit_reset_strategy': 'no_reset', 'status': 'active', 'note': ''}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserResponse]]
    """

    kwargs = _get_kwargs(
        username=username,
        json_body=json_body,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    username: str,
    *,
    client: AuthenticatedClient,
    json_body: UserModify,
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    """Modify User

     Modify a user

    - set **expire** to 0 to make the user unlimited in time, null to no change
    - set **data_limit** to 0 to make the user unlimited in data, null to no change
    - **proxies** dictionary of protocol:settings, empty means no change
    - **inbounds** dictionary of protocol:inbound_tags, empty means no change

    Args:
        username (str):
        json_body (UserModify):  Example: {'proxies': {'vmess': {'id':
            '35e4e39c-7d5c-4f4b-8b71-558e4f37ff53'}, 'vless': {}}, 'inbounds': {'vmess': ['VMess TCP',
            'VMess Websocket'], 'vless': ['VLESS TCP REALITY', 'VLESS GRPC REALITY']}, 'expire': 0,
            'data_limit': 0, 'data_limit_reset_strategy': 'no_reset', 'status': 'active', 'note': ''}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserResponse]
    """

    return sync_detailed(
        username=username,
        client=client,
        json_body=json_body,
    ).parsed


async def asyncio_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
    json_body: UserModify,
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    """Modify User

     Modify a user

    - set **expire** to 0 to make the user unlimited in time, null to no change
    - set **data_limit** to 0 to make the user unlimited in data, null to no change
    - **proxies** dictionary of protocol:settings, empty means no change
    - **inbounds** dictionary of protocol:inbound_tags, empty means no change

    Args:
        username (str):
        json_body (UserModify):  Example: {'proxies': {'vmess': {'id':
            '35e4e39c-7d5c-4f4b-8b71-558e4f37ff53'}, 'vless': {}}, 'inbounds': {'vmess': ['VMess TCP',
            'VMess Websocket'], 'vless': ['VLESS TCP REALITY', 'VLESS GRPC REALITY']}, 'expire': 0,
            'data_limit': 0, 'data_limit_reset_strategy': 'no_reset', 'status': 'active', 'note': ''}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserResponse]]
    """

    kwargs = _get_kwargs(
        username=username,
        json_body=json_body,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    username: str,
    *,
    client: AuthenticatedClient,
    json_body: UserModify,
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    """Modify User

     Modify a user

    - set **expire** to 0 to make the user unlimited in time, null to no change
    - set **data_limit** to 0 to make the user unlimited in data, null to no change
    - **proxies** dictionary of protocol:settings, empty means no change
    - **inbounds** dictionary of protocol:inbound_tags, empty means no change

    Args:
        username (str):
        json_body (UserModify):  Example: {'proxies': {'vmess': {'id':
            '35e4e39c-7d5c-4f4b-8b71-558e4f37ff53'}, 'vless': {}}, 'inbounds': {'vmess': ['VMess TCP',
            'VMess Websocket'], 'vless': ['VLESS TCP REALITY', 'VLESS GRPC REALITY']}, 'expire': 0,
            'data_limit': 0, 'data_limit_reset_strategy': 'no_reset', 'status': 'active', 'note': ''}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserResponse]
    """

    return (
        await asyncio_detailed(
            username=username,
            client=client,
            json_body=json_body,
        )
    ).parsed

marzban_client/api/user/modify_user_api_user_username_put.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...types import Response


def _get_kwargs(
    username: str,
) -> Dict[str, Any]:
    pass

    return {
        "method": "delete",
        "url": "/api/user/{username}".format(
            username=username,
        ),
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = cast(Any, response.json())
        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError]]:
    """Remove User

     Remove a user

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        username=username,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError]]:
    """Remove User

     Remove a user

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError]
    """

    return sync_detailed(
        username=username,
        client=client,
    ).parsed


async def asyncio_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError]]:
    """Remove User

     Remove a user

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        username=username,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError]]:
    """Remove User

     Remove a user

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError]
    """

    return (
        await asyncio_detailed(
            username=username,
            client=client,
        )
    ).parsed

marzban_client/api/user/remove_user_api_user_username_delete.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.user_response import UserResponse
from ...types import Response


def _get_kwargs(
    username: str,
) -> Dict[str, Any]:
    pass

    return {
        "method": "post",
        "url": "/api/user/{username}/reset".format(
            username=username,
        ),
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = UserResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if response.status_code == HTTPStatus.CONFLICT:
        response_409 = cast(Any, None)
        return response_409
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    """Reset User Data Usage

     Reset user data usage

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserResponse]]
    """

    kwargs = _get_kwargs(
        username=username,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    """Reset User Data Usage

     Reset user data usage

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserResponse]
    """

    return sync_detailed(
        username=username,
        client=client,
    ).parsed


async def asyncio_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    """Reset User Data Usage

     Reset user data usage

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserResponse]]
    """

    kwargs = _get_kwargs(
        username=username,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    """Reset User Data Usage

     Reset user data usage

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserResponse]
    """

    return (
        await asyncio_detailed(
            username=username,
            client=client,
        )
    ).parsed

marzban_client/api/user/reset_user_data_usage_api_user_username_reset_post.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...types import Response


def _get_kwargs() -> Dict[str, Any]:
    pass

    return {
        "method": "post",
        "url": "/api/users/reset",
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Any]:
    if response.status_code == HTTPStatus.OK:
        return None
    if response.status_code == HTTPStatus.FORBIDDEN:
        return None
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Any]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[Any]:
    """Reset Users Data Usage

     Reset all users data usage

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Any]
    """

    kwargs = _get_kwargs()

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
) -> Response[Any]:
    """Reset Users Data Usage

     Reset all users data usage

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Any]
    """

    kwargs = _get_kwargs()

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)

marzban_client/api/user/reset_users_data_usage_api_users_reset_post.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.user_response import UserResponse
from ...types import Response


def _get_kwargs(
    username: str,
) -> Dict[str, Any]:
    pass

    return {
        "method": "post",
        "url": "/api/user/{username}/revoke_sub".format(
            username=username,
        ),
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = UserResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    """Revoke User Subscription

     Revoke users subscription (Subscription link and proxies)

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserResponse]]
    """

    kwargs = _get_kwargs(
        username=username,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    """Revoke User Subscription

     Revoke users subscription (Subscription link and proxies)

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserResponse]
    """

    return sync_detailed(
        username=username,
        client=client,
    ).parsed


async def asyncio_detailed(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError, UserResponse]]:
    """Revoke User Subscription

     Revoke users subscription (Subscription link and proxies)

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserResponse]]
    """

    kwargs = _get_kwargs(
        username=username,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    username: str,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError, UserResponse]]:
    """Revoke User Subscription

     Revoke users subscription (Subscription link and proxies)

    Args:
        username (str):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserResponse]
    """

    return (
        await asyncio_detailed(
            username=username,
            client=client,
        )
    ).parsed

marzban_client/api/user/revoke_user_subscription_api_user_username_revoke_sub_post.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.user_template_create import UserTemplateCreate
from ...models.user_template_response import UserTemplateResponse
from ...types import Response


def _get_kwargs(
    *,
    json_body: UserTemplateCreate,
) -> Dict[str, Any]:
    pass

    json_json_body = json_body.to_dict()

    return {
        "method": "post",
        "url": "/api/user_template",
        "json": json_json_body,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = UserTemplateResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if response.status_code == HTTPStatus.CONFLICT:
        response_409 = cast(Any, None)
        return response_409
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
    json_body: UserTemplateCreate,
) -> Response[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    """Add User Template

     Add a new user template

    - **name** can be up to 64 characters
    - **data_limit** must be in bytes and larger or equal to 0
    - **expire_duration** must be in seconds and larger or equat to 0
    - **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds

    Args:
        json_body (UserTemplateCreate):  Example: {'name': 'my template 1', 'inbounds': {'vmess':
            ['VMESS_INBOUND'], 'vless': ['VLESS_INBOUND']}, 'data_limit': 0, 'expire_duration': 0}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserTemplateResponse]]
    """

    kwargs = _get_kwargs(
        json_body=json_body,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
    json_body: UserTemplateCreate,
) -> Optional[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    """Add User Template

     Add a new user template

    - **name** can be up to 64 characters
    - **data_limit** must be in bytes and larger or equal to 0
    - **expire_duration** must be in seconds and larger or equat to 0
    - **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds

    Args:
        json_body (UserTemplateCreate):  Example: {'name': 'my template 1', 'inbounds': {'vmess':
            ['VMESS_INBOUND'], 'vless': ['VLESS_INBOUND']}, 'data_limit': 0, 'expire_duration': 0}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserTemplateResponse]
    """

    return sync_detailed(
        client=client,
        json_body=json_body,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
    json_body: UserTemplateCreate,
) -> Response[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    """Add User Template

     Add a new user template

    - **name** can be up to 64 characters
    - **data_limit** must be in bytes and larger or equal to 0
    - **expire_duration** must be in seconds and larger or equat to 0
    - **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds

    Args:
        json_body (UserTemplateCreate):  Example: {'name': 'my template 1', 'inbounds': {'vmess':
            ['VMESS_INBOUND'], 'vless': ['VLESS_INBOUND']}, 'data_limit': 0, 'expire_duration': 0}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserTemplateResponse]]
    """

    kwargs = _get_kwargs(
        json_body=json_body,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
    json_body: UserTemplateCreate,
) -> Optional[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    """Add User Template

     Add a new user template

    - **name** can be up to 64 characters
    - **data_limit** must be in bytes and larger or equal to 0
    - **expire_duration** must be in seconds and larger or equat to 0
    - **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds

    Args:
        json_body (UserTemplateCreate):  Example: {'name': 'my template 1', 'inbounds': {'vmess':
            ['VMESS_INBOUND'], 'vless': ['VLESS_INBOUND']}, 'data_limit': 0, 'expire_duration': 0}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserTemplateResponse]
    """

    return (
        await asyncio_detailed(
            client=client,
            json_body=json_body,
        )
    ).parsed

marzban_client/api/user_template/add_user_template_api_user_template_post.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.user_template_response import UserTemplateResponse
from ...types import Response


def _get_kwargs(
    id: int,
) -> Dict[str, Any]:
    pass

    return {
        "method": "get",
        "url": "/api/user_template/{id}".format(
            id=id,
        ),
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = UserTemplateResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    id: int,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    """Get User Template

     Get User Template information with id

    Args:
        id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserTemplateResponse]]
    """

    kwargs = _get_kwargs(
        id=id,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    id: int,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    """Get User Template

     Get User Template information with id

    Args:
        id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserTemplateResponse]
    """

    return sync_detailed(
        id=id,
        client=client,
    ).parsed


async def asyncio_detailed(
    id: int,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    """Get User Template

     Get User Template information with id

    Args:
        id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserTemplateResponse]]
    """

    kwargs = _get_kwargs(
        id=id,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    id: int,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    """Get User Template

     Get User Template information with id

    Args:
        id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserTemplateResponse]
    """

    return (
        await asyncio_detailed(
            id=id,
            client=client,
        )
    ).parsed

marzban_client/api/user_template/get_user_template_api_user_template_id_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, List, Optional, Union

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.user_template_response import UserTemplateResponse
from ...types import UNSET, Response, Unset


def _get_kwargs(
    *,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
) -> Dict[str, Any]:
    pass

    params: Dict[str, Any] = {}
    params["offset"] = offset

    params["limit"] = limit

    params = {k: v for k, v in params.items() if v is not UNSET and v is not None}

    return {
        "method": "get",
        "url": "/api/user_template",
        "params": params,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[HTTPValidationError, List["UserTemplateResponse"]]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = []
        _response_200 = response.json()
        for response_200_item_data in _response_200:
            response_200_item = UserTemplateResponse.from_dict(response_200_item_data)

            response_200.append(response_200_item)

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[HTTPValidationError, List["UserTemplateResponse"]]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    *,
    client: AuthenticatedClient,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
) -> Response[Union[HTTPValidationError, List["UserTemplateResponse"]]]:
    """Get User Templates

    Args:
        offset (Union[Unset, None, int]):
        limit (Union[Unset, None, int]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[HTTPValidationError, List['UserTemplateResponse']]]
    """

    kwargs = _get_kwargs(
        offset=offset,
        limit=limit,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    *,
    client: AuthenticatedClient,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
) -> Optional[Union[HTTPValidationError, List["UserTemplateResponse"]]]:
    """Get User Templates

    Args:
        offset (Union[Unset, None, int]):
        limit (Union[Unset, None, int]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[HTTPValidationError, List['UserTemplateResponse']]
    """

    return sync_detailed(
        client=client,
        offset=offset,
        limit=limit,
    ).parsed


async def asyncio_detailed(
    *,
    client: AuthenticatedClient,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
) -> Response[Union[HTTPValidationError, List["UserTemplateResponse"]]]:
    """Get User Templates

    Args:
        offset (Union[Unset, None, int]):
        limit (Union[Unset, None, int]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[HTTPValidationError, List['UserTemplateResponse']]]
    """

    kwargs = _get_kwargs(
        offset=offset,
        limit=limit,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    *,
    client: AuthenticatedClient,
    offset: Union[Unset, None, int] = UNSET,
    limit: Union[Unset, None, int] = UNSET,
) -> Optional[Union[HTTPValidationError, List["UserTemplateResponse"]]]:
    """Get User Templates

    Args:
        offset (Union[Unset, None, int]):
        limit (Union[Unset, None, int]):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[HTTPValidationError, List['UserTemplateResponse']]
    """

    return (
        await asyncio_detailed(
            client=client,
            offset=offset,
            limit=limit,
        )
    ).parsed

marzban_client/api/user_template/get_user_templates_api_user_template_get.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...models.user_template_modify import UserTemplateModify
from ...models.user_template_response import UserTemplateResponse
from ...types import Response


def _get_kwargs(
    id: int,
    *,
    json_body: UserTemplateModify,
) -> Dict[str, Any]:
    pass

    json_json_body = json_body.to_dict()

    return {
        "method": "put",
        "url": "/api/user_template/{id}".format(
            id=id,
        ),
        "json": json_json_body,
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = UserTemplateResponse.from_dict(response.json())

        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if response.status_code == HTTPStatus.CONFLICT:
        response_409 = cast(Any, None)
        return response_409
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    id: int,
    *,
    client: AuthenticatedClient,
    json_body: UserTemplateModify,
) -> Response[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    """Modify User Template

     Modify User Template

    - **name** can be up to 64 characters
    - **data_limit** must be in bytes and larger or equal to 0
    - **expire_duration** must be in seconds and larger or equat to 0
    - **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds

    Args:
        id (int):
        json_body (UserTemplateModify):  Example: {'name': 'my template 1', 'inbounds': {'vmess':
            ['VMESS_INBOUND'], 'vless': ['VLESS_INBOUND']}, 'data_limit': 0, 'expire_duration': 0}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserTemplateResponse]]
    """

    kwargs = _get_kwargs(
        id=id,
        json_body=json_body,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    id: int,
    *,
    client: AuthenticatedClient,
    json_body: UserTemplateModify,
) -> Optional[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    """Modify User Template

     Modify User Template

    - **name** can be up to 64 characters
    - **data_limit** must be in bytes and larger or equal to 0
    - **expire_duration** must be in seconds and larger or equat to 0
    - **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds

    Args:
        id (int):
        json_body (UserTemplateModify):  Example: {'name': 'my template 1', 'inbounds': {'vmess':
            ['VMESS_INBOUND'], 'vless': ['VLESS_INBOUND']}, 'data_limit': 0, 'expire_duration': 0}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserTemplateResponse]
    """

    return sync_detailed(
        id=id,
        client=client,
        json_body=json_body,
    ).parsed


async def asyncio_detailed(
    id: int,
    *,
    client: AuthenticatedClient,
    json_body: UserTemplateModify,
) -> Response[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    """Modify User Template

     Modify User Template

    - **name** can be up to 64 characters
    - **data_limit** must be in bytes and larger or equal to 0
    - **expire_duration** must be in seconds and larger or equat to 0
    - **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds

    Args:
        id (int):
        json_body (UserTemplateModify):  Example: {'name': 'my template 1', 'inbounds': {'vmess':
            ['VMESS_INBOUND'], 'vless': ['VLESS_INBOUND']}, 'data_limit': 0, 'expire_duration': 0}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError, UserTemplateResponse]]
    """

    kwargs = _get_kwargs(
        id=id,
        json_body=json_body,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    id: int,
    *,
    client: AuthenticatedClient,
    json_body: UserTemplateModify,
) -> Optional[Union[Any, HTTPValidationError, UserTemplateResponse]]:
    """Modify User Template

     Modify User Template

    - **name** can be up to 64 characters
    - **data_limit** must be in bytes and larger or equal to 0
    - **expire_duration** must be in seconds and larger or equat to 0
    - **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds

    Args:
        id (int):
        json_body (UserTemplateModify):  Example: {'name': 'my template 1', 'inbounds': {'vmess':
            ['VMESS_INBOUND'], 'vless': ['VLESS_INBOUND']}, 'data_limit': 0, 'expire_duration': 0}.

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError, UserTemplateResponse]
    """

    return (
        await asyncio_detailed(
            id=id,
            client=client,
            json_body=json_body,
        )
    ).parsed

marzban_client/api/user_template/modify_user_template_api_user_template_id_put.py
govfvck/Marzbot-free
from http import HTTPStatus
from typing import Any, Dict, Optional, Union, cast

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.http_validation_error import HTTPValidationError
from ...types import Response


def _get_kwargs(
    id: int,
) -> Dict[str, Any]:
    pass

    return {
        "method": "delete",
        "url": "/api/user_template/{id}".format(
            id=id,
        ),
    }


def _parse_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Optional[Union[Any, HTTPValidationError]]:
    if response.status_code == HTTPStatus.OK:
        response_200 = cast(Any, response.json())
        return response_200
    if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
        response_422 = HTTPValidationError.from_dict(response.json())

        return response_422
    if response.status_code == HTTPStatus.NOT_FOUND:
        response_404 = cast(Any, None)
        return response_404
    if response.status_code == HTTPStatus.FORBIDDEN:
        response_403 = cast(Any, None)
        return response_403
    if client.raise_on_unexpected_status:
        raise errors.UnexpectedStatus(response.status_code, response.content)
    else:
        return None


def _build_response(
    *, client: Union[AuthenticatedClient, Client], response: httpx.Response
) -> Response[Union[Any, HTTPValidationError]]:
    return Response(
        status_code=HTTPStatus(response.status_code),
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(client=client, response=response),
    )


def sync_detailed(
    id: int,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError]]:
    """Remove User Template

    Args:
        id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        id=id,
    )

    response = client.get_httpx_client().request(
        **kwargs,
    )

    return _build_response(client=client, response=response)


def sync(
    id: int,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError]]:
    """Remove User Template

    Args:
        id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError]
    """

    return sync_detailed(
        id=id,
        client=client,
    ).parsed


async def asyncio_detailed(
    id: int,
    *,
    client: AuthenticatedClient,
) -> Response[Union[Any, HTTPValidationError]]:
    """Remove User Template

    Args:
        id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Response[Union[Any, HTTPValidationError]]
    """

    kwargs = _get_kwargs(
        id=id,
    )

    response = await client.get_async_httpx_client().request(**kwargs)

    return _build_response(client=client, response=response)


async def asyncio(
    id: int,
    *,
    client: AuthenticatedClient,
) -> Optional[Union[Any, HTTPValidationError]]:
    """Remove User Template

    Args:
        id (int):

    Raises:
        errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
        httpx.TimeoutException: If the request takes longer than Client.timeout.

    Returns:
        Union[Any, HTTPValidationError]
    """

    return (
        await asyncio_detailed(
            id=id,
            client=client,
        )
    ).parsed

marzban_client/api/user_template/remove_user_template_api_user_template_id_delete.py
govfvck/Marzbot-free
import ssl
from typing import Any, Dict, Optional, Union

import httpx
from attrs import define, evolve, field


@define
class Client:
    """A class for keeping track of data related to the API

    The following are accepted as keyword arguments and will be used to construct httpx Clients internally:

        ``base_url``: The base URL for the API, all requests are made to a relative path to this URL

        ``cookies``: A dictionary of cookies to be sent with every request

        ``headers``: A dictionary of headers to be sent with every request

        ``timeout``: The maximum amount of a time a request can take. API functions will raise
        httpx.TimeoutException if this is exceeded.

        ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production,
        but can be set to False for testing purposes.

        ``follow_redirects``: Whether or not to follow redirects. Default value is False.

        ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor.


    Attributes:
        raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a
            status code that was not documented in the source OpenAPI document. Can also be provided as a keyword
            argument to the constructor.
    """

    raise_on_unexpected_status: bool = field(default=False, kw_only=True)
    _base_url: str
    _cookies: Dict[str, str] = field(factory=dict, kw_only=True)
    _headers: Dict[str, str] = field(factory=dict, kw_only=True)
    _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True)
    _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True)
    _follow_redirects: bool = field(default=False, kw_only=True)
    _httpx_args: Dict[str, Any] = field(factory=dict, kw_only=True)
    _client: Optional[httpx.Client] = field(default=None, init=False)
    _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False)

    def with_headers(self, headers: Dict[str, str]) -> "Client":
        """Get a new client matching this one with additional headers"""
        if self._client is not None:
            self._client.headers.update(headers)
        if self._async_client is not None:
            self._async_client.headers.update(headers)
        return evolve(self, headers={**self._headers, **headers})

    def with_cookies(self, cookies: Dict[str, str]) -> "Client":
        """Get a new client matching this one with additional cookies"""
        if self._client is not None:
            self._client.cookies.update(cookies)
        if self._async_client is not None:
            self._async_client.cookies.update(cookies)
        return evolve(self, cookies={**self._cookies, **cookies})

    def with_timeout(self, timeout: httpx.Timeout) -> "Client":
        """Get a new client matching this one with a new timeout (in seconds)"""
        if self._client is not None:
            self._client.timeout = timeout
        if self._async_client is not None:
            self._async_client.timeout = timeout
        return evolve(self, timeout=timeout)

    def set_httpx_client(self, client: httpx.Client) -> "Client":
        """Manually the underlying httpx.Client

        **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout.
        """
        self._client = client
        return self

    def get_httpx_client(self) -> httpx.Client:
        """Get the underlying httpx.Client, constructing a new one if not previously set"""
        if self._client is None:
            self._client = httpx.Client(
                base_url=self._base_url,
                cookies=self._cookies,
                headers=self._headers,
                timeout=self._timeout,
                verify=self._verify_ssl,
                follow_redirects=self._follow_redirects,
                **self._httpx_args,
            )
        return self._client

    def __enter__(self) -> "Client":
        """Enter a context manager for self.client—you cannot enter twice (see httpx docs)"""
        self.get_httpx_client().__enter__()
        return self

    def __exit__(self, *args: Any, **kwargs: Any) -> None:
        """Exit a context manager for internal httpx.Client (see httpx docs)"""
        self.get_httpx_client().__exit__(*args, **kwargs)

    def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client":
        """Manually the underlying httpx.AsyncClient

        **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout.
        """
        self._async_client = async_client
        return self

    def get_async_httpx_client(self) -> httpx.AsyncClient:
        """Get the underlying httpx.AsyncClient, constructing a new one if not previously set"""
        if self._async_client is None:
            self._async_client = httpx.AsyncClient(
                base_url=self._base_url,
                cookies=self._cookies,
                headers=self._headers,
                timeout=self._timeout,
                verify=self._verify_ssl,
                follow_redirects=self._follow_redirects,
                **self._httpx_args,
            )
        return self._async_client

    async def __aenter__(self) -> "Client":
        """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)"""
        await self.get_async_httpx_client().__aenter__()
        return self

    async def __aexit__(self, *args: Any, **kwargs: Any) -> None:
        """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)"""
        await self.get_async_httpx_client().__aexit__(*args, **kwargs)


@define
class AuthenticatedClient:
    """A Client which has been authenticated for use on secured endpoints

    The following are accepted as keyword arguments and will be used to construct httpx Clients internally:

        ``base_url``: The base URL for the API, all requests are made to a relative path to this URL

        ``cookies``: A dictionary of cookies to be sent with every request

        ``headers``: A dictionary of headers to be sent with every request

        ``timeout``: The maximum amount of a time a request can take. API functions will raise
        httpx.TimeoutException if this is exceeded.

        ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production,
        but can be set to False for testing purposes.

        ``follow_redirects``: Whether or not to follow redirects. Default value is False.

        ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor.


    Attributes:
        raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a
            status code that was not documented in the source OpenAPI document. Can also be provided as a keyword
            argument to the constructor.
        token: The token to use for authentication
        prefix: The prefix to use for the Authorization header
        auth_header_name: The name of the Authorization header
    """

    raise_on_unexpected_status: bool = field(default=False, kw_only=True)
    _base_url: str
    _cookies: Dict[str, str] = field(factory=dict, kw_only=True)
    _headers: Dict[str, str] = field(factory=dict, kw_only=True)
    _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True)
    _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True)
    _follow_redirects: bool = field(default=False, kw_only=True)
    _httpx_args: Dict[str, Any] = field(factory=dict, kw_only=True)
    _client: Optional[httpx.Client] = field(default=None, init=False)
    _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False)

    token: str
    prefix: str = "Bearer"
    auth_header_name: str = "Authorization"

    def with_headers(self, headers: Dict[str, str]) -> "AuthenticatedClient":
        """Get a new client matching this one with additional headers"""
        if self._client is not None:
            self._client.headers.update(headers)
        if self._async_client is not None:
            self._async_client.headers.update(headers)
        return evolve(self, headers={**self._headers, **headers})

    def with_cookies(self, cookies: Dict[str, str]) -> "AuthenticatedClient":
        """Get a new client matching this one with additional cookies"""
        if self._client is not None:
            self._client.cookies.update(cookies)
        if self._async_client is not None:
            self._async_client.cookies.update(cookies)
        return evolve(self, cookies={**self._cookies, **cookies})

    def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient":
        """Get a new client matching this one with a new timeout (in seconds)"""
        if self._client is not None:
            self._client.timeout = timeout
        if self._async_client is not None:
            self._async_client.timeout = timeout
        return evolve(self, timeout=timeout)

    def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient":
        """Manually the underlying httpx.Client

        **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout.
        """
        self._client = client
        return self

    def get_httpx_client(self) -> httpx.Client:
        """Get the underlying httpx.Client, constructing a new one if not previously set"""
        if self._client is None:
            self._headers[self.auth_header_name] = (
                f"{self.prefix} {self.token}" if self.prefix else self.token
            )
            self._client = httpx.Client(
                base_url=self._base_url,
                cookies=self._cookies,
                headers=self._headers,
                timeout=self._timeout,
                verify=self._verify_ssl,
                follow_redirects=self._follow_redirects,
                **self._httpx_args,
            )
        return self._client

    def __enter__(self) -> "AuthenticatedClient":
        """Enter a context manager for self.client—you cannot enter twice (see httpx docs)"""
        self.get_httpx_client().__enter__()
        return self

    def __exit__(self, *args: Any, **kwargs: Any) -> None:
        """Exit a context manager for internal httpx.Client (see httpx docs)"""
        self.get_httpx_client().__exit__(*args, **kwargs)

    def set_async_httpx_client(
        self, async_client: httpx.AsyncClient
    ) -> "AuthenticatedClient":
        """Manually the underlying httpx.AsyncClient

        **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout.
        """
        self._async_client = async_client
        return self

    def get_async_httpx_client(self) -> httpx.AsyncClient:
        """Get the underlying httpx.AsyncClient, constructing a new one if not previously set"""
        if self._async_client is None:
            self._headers[self.auth_header_name] = (
                f"{self.prefix} {self.token}" if self.prefix else self.token
            )
            self._async_client = httpx.AsyncClient(
                base_url=self._base_url,
                cookies=self._cookies,
                headers=self._headers,
                timeout=self._timeout,
                verify=self._verify_ssl,
                follow_redirects=self._follow_redirects,
                **self._httpx_args,
            )
        return self._async_client

    async def __aenter__(self) -> "AuthenticatedClient":
        """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)"""
        await self.get_async_httpx_client().__aenter__()
        return self

    async def __aexit__(self, *args: Any, **kwargs: Any) -> None:
        """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)"""
        await self.get_async_httpx_client().__aexit__(*args, **kwargs)

marzban_client/client.py
govfvck/Marzbot-free
""" Contains all the data models used in inputs/outputs """

from .admin import Admin
from .admin_create import AdminCreate
from .admin_modify import AdminModify
from .body_login_for_acess_token import BodyLoginForAcessToken
from .core_stats import CoreStats
from .get_core_config_api_core_config_get_response_get_core_config_api_core_config_get import (
    GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet,
)
from .get_core_config_api_core_config_put_payload import (
    GetCoreConfigApiCoreConfigPutPayload,
)
from .get_core_config_api_core_config_put_response_get_core_config_api_core_config_put import (
    GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut,
)
from .get_hosts_response import GetHostsResponse
from .get_inbounds_response import GetInboundsResponse
from .http_validation_error import HTTPValidationError
from .modify_hosts_api_hosts_put_modified_hosts import (
    ModifyHostsApiHostsPutModifiedHosts,
)
from .modify_hosts_api_hosts_put_response_modify_hosts_api_hosts_put import (
    ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut,
)
from .node_create import NodeCreate
from .node_modify import NodeModify
from .node_response import NodeResponse
from .node_status import NodeStatus
from .node_usage_response import NodeUsageResponse
from .nodes_usage_response import NodesUsageResponse
from .proxy_host import ProxyHost
from .proxy_host_alpn import ProxyHostALPN
from .proxy_host_fingerprint import ProxyHostFingerprint
from .proxy_host_security import ProxyHostSecurity
from .proxy_inbound import ProxyInbound
from .proxy_settings import ProxySettings
from .proxy_types import ProxyTypes
from .system_stats import SystemStats
from .token import Token
from .user_create import UserCreate
from .user_create_inbounds import UserCreateInbounds
from .user_create_proxies import UserCreateProxies
from .user_data_limit_reset_strategy import UserDataLimitResetStrategy
from .user_modify import UserModify
from .user_modify_inbounds import UserModifyInbounds
from .user_modify_proxies import UserModifyProxies
from .user_response import UserResponse
from .user_response_excluded_inbounds import UserResponseExcludedInbounds
from .user_response_inbounds import UserResponseInbounds
from .user_response_proxies import UserResponseProxies
from .user_status import UserStatus
from .user_status_modify import UserStatusModify
from .user_template_create import UserTemplateCreate
from .user_template_create_inbounds import UserTemplateCreateInbounds
from .user_template_modify import UserTemplateModify
from .user_template_modify_inbounds import UserTemplateModifyInbounds
from .user_template_response import UserTemplateResponse
from .user_template_response_inbounds import UserTemplateResponseInbounds
from .user_usage_response import UserUsageResponse
from .user_usages_response import UserUsagesResponse
from .users_response import UsersResponse
from .validation_error import ValidationError

__all__ = (
    "Admin",
    "AdminCreate",
    "AdminModify",
    "BodyLoginForAcessToken",
    "CoreStats",
    "GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet",
    "GetCoreConfigApiCoreConfigPutPayload",
    "GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut",
    "GetHostsResponse",
    "GetInboundsResponse",
    "HTTPValidationError",
    "ModifyHostsApiHostsPutModifiedHosts",
    "ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut",
    "NodeCreate",
    "NodeModify",
    "NodeResponse",
    "NodeStatus",
    "NodesUsageResponse",
    "NodeUsageResponse",
    "ProxyHost",
    "ProxyHostALPN",
    "ProxyHostFingerprint",
    "ProxyHostSecurity",
    "ProxyInbound",
    "ProxySettings",
    "ProxyTypes",
    "SystemStats",
    "Token",
    "UserCreate",
    "UserCreateInbounds",
    "UserCreateProxies",
    "UserDataLimitResetStrategy",
    "UserModify",
    "UserModifyInbounds",
    "UserModifyProxies",
    "UserResponse",
    "UserResponseExcludedInbounds",
    "UserResponseInbounds",
    "UserResponseProxies",
    "UsersResponse",
    "UserStatus",
    "UserStatusModify",
    "UserTemplateCreate",
    "UserTemplateCreateInbounds",
    "UserTemplateModify",
    "UserTemplateModifyInbounds",
    "UserTemplateResponse",
    "UserTemplateResponseInbounds",
    "UserUsageResponse",
    "UserUsagesResponse",
    "ValidationError",
)

marzban_client/models/__init__.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="Admin")


@_attrs_define
class Admin:
    """
    Attributes:
        username (str):
        is_sudo (bool):
    """

    username: str
    is_sudo: bool
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        username = self.username
        is_sudo = self.is_sudo

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "username": username,
                "is_sudo": is_sudo,
            }
        )

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        username = d.pop("username")

        is_sudo = d.pop("is_sudo")

        admin = cls(
            username=username,
            is_sudo=is_sudo,
        )

        admin.additional_properties = d
        return admin

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/admin.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="AdminCreate")


@_attrs_define
class AdminCreate:
    """
    Attributes:
        username (str):
        is_sudo (bool):
        password (str):
    """

    username: str
    is_sudo: bool
    password: str
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        username = self.username
        is_sudo = self.is_sudo
        password = self.password

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "username": username,
                "is_sudo": is_sudo,
                "password": password,
            }
        )

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        username = d.pop("username")

        is_sudo = d.pop("is_sudo")

        password = d.pop("password")

        admin_create = cls(
            username=username,
            is_sudo=is_sudo,
            password=password,
        )

        admin_create.additional_properties = d
        return admin_create

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/admin_create.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="AdminModify")


@_attrs_define
class AdminModify:
    """
    Attributes:
        password (str):
        is_sudo (bool):
    """

    password: str
    is_sudo: bool
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        password = self.password
        is_sudo = self.is_sudo

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "password": password,
                "is_sudo": is_sudo,
            }
        )

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        password = d.pop("password")

        is_sudo = d.pop("is_sudo")

        admin_modify = cls(
            password=password,
            is_sudo=is_sudo,
        )

        admin_modify.additional_properties = d
        return admin_modify

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/admin_modify.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

T = TypeVar("T", bound="BodyLoginForAcessToken")


@_attrs_define
class BodyLoginForAcessToken:
    """
    Attributes:
        username (str):
        password (str):
        grant_type (Union[Unset, str]):
        scope (Union[Unset, str]):  Default: ''.
        client_id (Union[Unset, str]):
        client_secret (Union[Unset, str]):
    """

    username: str
    password: str
    grant_type: Union[Unset, str] = UNSET
    scope: Union[Unset, str] = ""
    client_id: Union[Unset, str] = UNSET
    client_secret: Union[Unset, str] = UNSET
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        username = self.username
        password = self.password
        grant_type = self.grant_type
        scope = self.scope
        client_id = self.client_id
        client_secret = self.client_secret

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "username": username,
                "password": password,
            }
        )
        if grant_type is not UNSET:
            field_dict["grant_type"] = grant_type
        if scope is not UNSET:
            field_dict["scope"] = scope
        if client_id is not UNSET:
            field_dict["client_id"] = client_id
        if client_secret is not UNSET:
            field_dict["client_secret"] = client_secret

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        username = d.pop("username")

        password = d.pop("password")

        grant_type = d.pop("grant_type", UNSET)

        scope = d.pop("scope", UNSET)

        client_id = d.pop("client_id", UNSET)

        client_secret = d.pop("client_secret", UNSET)

        body_login_for_acess_token = cls(
            username=username,
            password=password,
            grant_type=grant_type,
            scope=scope,
            client_id=client_id,
            client_secret=client_secret,
        )

        body_login_for_acess_token.additional_properties = d
        return body_login_for_acess_token

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/body_login_for_acess_token.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="CoreStats")


@_attrs_define
class CoreStats:
    """
    Attributes:
        version (str):
        started (bool):
        logs_websocket (str):
    """

    version: str
    started: bool
    logs_websocket: str
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        version = self.version
        started = self.started
        logs_websocket = self.logs_websocket

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "version": version,
                "started": started,
                "logs_websocket": logs_websocket,
            }
        )

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        version = d.pop("version")

        started = d.pop("started")

        logs_websocket = d.pop("logs_websocket")

        core_stats = cls(
            version=version,
            started=started,
            logs_websocket=logs_websocket,
        )

        core_stats.additional_properties = d
        return core_stats

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/core_stats.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar(
    "T", bound="GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet"
)


@_attrs_define
class GetCoreConfigApiCoreConfigGetResponseGetCoreConfigApiCoreConfigGet:
    """ """

    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        get_core_config_api_core_config_get_response_get_core_config_api_core_config_get = (
            cls()
        )

        get_core_config_api_core_config_get_response_get_core_config_api_core_config_get.additional_properties = (
            d
        )
        return get_core_config_api_core_config_get_response_get_core_config_api_core_config_get

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/get_core_config_api_core_config_get_response_get_core_config_api_core_config_get.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="GetCoreConfigApiCoreConfigPutPayload")


@_attrs_define
class GetCoreConfigApiCoreConfigPutPayload:
    """ """

    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        get_core_config_api_core_config_put_payload = cls()

        get_core_config_api_core_config_put_payload.additional_properties = d
        return get_core_config_api_core_config_put_payload

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/get_core_config_api_core_config_put_payload.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar(
    "T", bound="GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut"
)


@_attrs_define
class GetCoreConfigApiCoreConfigPutResponseGetCoreConfigApiCoreConfigPut:
    """ """

    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        get_core_config_api_core_config_put_response_get_core_config_api_core_config_put = (
            cls()
        )

        get_core_config_api_core_config_put_response_get_core_config_api_core_config_put.additional_properties = (
            d
        )
        return get_core_config_api_core_config_put_response_get_core_config_api_core_config_put

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/get_core_config_api_core_config_put_response_get_core_config_api_core_config_put.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

if TYPE_CHECKING:
    from ..models.proxy_host import ProxyHost


T = TypeVar("T", bound="GetHostsResponse")


@_attrs_define
class GetHostsResponse:
    """ """

    additional_properties: Dict[str, List["ProxyHost"]] = _attrs_field(
        init=False, factory=dict
    )

    def to_dict(self) -> Dict[str, Any]:
        pass

        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = []
            for additional_property_item_data in prop:
                additional_property_item = additional_property_item_data.to_dict()

                field_dict[prop_name].append(additional_property_item)

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.proxy_host import ProxyHost

        d = src_dict.copy()
        get_hosts_response = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = []
            _additional_property = prop_dict
            for additional_property_item_data in _additional_property:
                additional_property_item = ProxyHost.from_dict(
                    additional_property_item_data
                )

                additional_property.append(additional_property_item)

            additional_properties[prop_name] = additional_property

        get_hosts_response.additional_properties = additional_properties
        return get_hosts_response

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> List["ProxyHost"]:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: List["ProxyHost"]) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/get_hosts_response.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

if TYPE_CHECKING:
    from ..models.proxy_inbound import ProxyInbound


T = TypeVar("T", bound="GetInboundsResponse")


@_attrs_define
class GetInboundsResponse:
    """ """

    additional_properties: Dict[str, List["ProxyInbound"]] = _attrs_field(
        init=False, factory=dict
    )

    def to_dict(self) -> Dict[str, Any]:
        pass

        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = []
            for additional_property_item_data in prop:
                additional_property_item = additional_property_item_data.to_dict()

                field_dict[prop_name].append(additional_property_item)

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.proxy_inbound import ProxyInbound

        d = src_dict.copy()
        get_inbounds_response = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = []
            _additional_property = prop_dict
            for additional_property_item_data in _additional_property:
                additional_property_item = ProxyInbound.from_dict(
                    additional_property_item_data
                )

                additional_property.append(additional_property_item)

            additional_properties[prop_name] = additional_property

        get_inbounds_response.additional_properties = additional_properties
        return get_inbounds_response

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> List["ProxyInbound"]:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: List["ProxyInbound"]) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/get_inbounds_response.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

if TYPE_CHECKING:
    from ..models.validation_error import ValidationError


T = TypeVar("T", bound="HTTPValidationError")


@_attrs_define
class HTTPValidationError:
    """
    Attributes:
        detail (Union[Unset, List['ValidationError']]):
    """

    detail: Union[Unset, List["ValidationError"]] = UNSET
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        detail: Union[Unset, List[Dict[str, Any]]] = UNSET
        if not isinstance(self.detail, Unset):
            detail = []
            for detail_item_data in self.detail:
                detail_item = detail_item_data.to_dict()

                detail.append(detail_item)

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})
        if detail is not UNSET:
            field_dict["detail"] = detail

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.validation_error import ValidationError

        d = src_dict.copy()
        detail = []
        _detail = d.pop("detail", UNSET)
        for detail_item_data in _detail or []:
            detail_item = ValidationError.from_dict(detail_item_data)

            detail.append(detail_item)

        http_validation_error = cls(
            detail=detail,
        )

        http_validation_error.additional_properties = d
        return http_validation_error

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/http_validation_error.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

if TYPE_CHECKING:
    from ..models.proxy_host import ProxyHost


T = TypeVar("T", bound="ModifyHostsApiHostsPutModifiedHosts")


@_attrs_define
class ModifyHostsApiHostsPutModifiedHosts:
    """ """

    additional_properties: Dict[str, List["ProxyHost"]] = _attrs_field(
        init=False, factory=dict
    )

    def to_dict(self) -> Dict[str, Any]:
        pass

        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = []
            for additional_property_item_data in prop:
                additional_property_item = additional_property_item_data.to_dict()

                field_dict[prop_name].append(additional_property_item)

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.proxy_host import ProxyHost

        d = src_dict.copy()
        modify_hosts_api_hosts_put_modified_hosts = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = []
            _additional_property = prop_dict
            for additional_property_item_data in _additional_property:
                additional_property_item = ProxyHost.from_dict(
                    additional_property_item_data
                )

                additional_property.append(additional_property_item)

            additional_properties[prop_name] = additional_property

        modify_hosts_api_hosts_put_modified_hosts.additional_properties = (
            additional_properties
        )
        return modify_hosts_api_hosts_put_modified_hosts

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> List["ProxyHost"]:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: List["ProxyHost"]) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/modify_hosts_api_hosts_put_modified_hosts.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

if TYPE_CHECKING:
    from ..models.proxy_host import ProxyHost


T = TypeVar("T", bound="ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut")


@_attrs_define
class ModifyHostsApiHostsPutResponseModifyHostsApiHostsPut:
    """ """

    additional_properties: Dict[str, List["ProxyHost"]] = _attrs_field(
        init=False, factory=dict
    )

    def to_dict(self) -> Dict[str, Any]:
        pass

        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = []
            for additional_property_item_data in prop:
                additional_property_item = additional_property_item_data.to_dict()

                field_dict[prop_name].append(additional_property_item)

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.proxy_host import ProxyHost

        d = src_dict.copy()
        modify_hosts_api_hosts_put_response_modify_hosts_api_hosts_put = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = []
            _additional_property = prop_dict
            for additional_property_item_data in _additional_property:
                additional_property_item = ProxyHost.from_dict(
                    additional_property_item_data
                )

                additional_property.append(additional_property_item)

            additional_properties[prop_name] = additional_property

        modify_hosts_api_hosts_put_response_modify_hosts_api_hosts_put.additional_properties = (
            additional_properties
        )
        return modify_hosts_api_hosts_put_response_modify_hosts_api_hosts_put

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> List["ProxyHost"]:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: List["ProxyHost"]) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/modify_hosts_api_hosts_put_response_modify_hosts_api_hosts_put.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

T = TypeVar("T", bound="NodeCreate")


@_attrs_define
class NodeCreate:
    r"""
    Example:
        {'name': 'DE node', 'address': '192.168.1.1', 'port': 62050, 'api_port': 62051, 'add_as_new_host': True,
            'certificate': '-----BEGIN CERTIFICATE-----
            \nMIIEnDCCAoQCAQAwDQYJKoZIhvcNAQENBQAwEzERMA8GA1UEAwwIR296YXJnYWgw\nIBcNMjMwMjE5MjMwOTMyWhgPMjEyMzAxMjYyMzA5MzJa
            MBMxETAPBgNVBAMMCEdv\nemFyZ2FoMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0BvDh0eU78EJ\n+xzBWUjjMrWf/0rWV5fDl7b4
            RU8AjeviG1RmEc64ueZ3s6q1LI6DJX1+qGuqDEvp\nmRc09HihO07DyQgQqF38/E4CXshZ2L3UOzsa80lf74dhEqAR/EJQXXMwGSb3T9J9\nseCq
            CyiEn/JLEGsilDz64cTv8MXMAcjjpdefkFyQP+4hAKQgHbtfJ9KPSu4/lkZR\n/orsjoWGJv4LS0MsXV1t7LB/bNC7qOzlmzrfTMH4EmtmKH8Hwh
            MkL1nUG+vXEfwm\nQg3Ly+yrwKNw9+L7DxbKnoy2Zqp9dN+rzKDgcpHsoIYf0feInUHHlRUu303kAFQN\nGlnzZgD8ulHI1sQLNS3teYpj817G3E
            XKOhu56MvBehBR9GfvfS1D5D/QvwRfcaZI\nCULBPoGqovhrknbUXt9TEfzc9YnfSzlcJYcH54/aUBVJNs74EK38OQ+JciLnw4qe\ngbXEshaeLg
            GM3bhXwUhctcmZf5ASWDsAVtEeCXGNK+ua6wlFXKVd0jOt2ZZYG42X\nwrpHCErAWY7AoxHmXlfPcPM0Uu7FuEBP27f8U3N+glG1lWrogNn54j1Z
            rzQVUVVv\ngog78DrjjzrR0puQ9x9q6FvEUTAaaA06lvi2/6BuwO0jKrHQCP7fFUmRXg5B5lrJ\n9czSDHT9WH9Sc1qdxQTevhc9C/h6MuMCAwEA
            ATANBgkqhkiG9w0BAQ0FAAOCAgEA\nI7aXhLejp53NyuwzmdfeycY373TI4sD3WfPdEB6+FSCX38YghyQl8tkeaHPgPKY5\n+vA+eVxE7E961UNP
            tJtJg/dzBvoWUroTnpvKjVdDImFaZa/PvUMgSEe8tC3FtB6i\nAp7f0yYOGsFf6oaOxMfs/F0sGflsaVWuiATTsV8Er+uzge77Q8AXzy6spuXg3A
            LF\n56tqzZY5x/04g1KUQB4JN+7JzipnfSIUof0eAKf9gQbumUU+Q2b32HMC2MOlUjv+\nIl8rJ9cs0zwC1BOmqoS3Ez22dgtT7FucvIJ1MGP8oU
            AudMmrXDxx/d7CmnD5q1v4\nXFSa6Zv8LPLCz5iMbo0FjNlKyZo3699PtyBFXt3zyfTPmiy19RVGTziHqJ9NR9kW\nkBwvFzIy+qPc/dJAk435hV
            aV3pRBC7Pl2Y7k/pJxxlC07PkACXuhwtUGhQrHYWkK\niLlV21kNnWuvjS1orTwvuW3aagb6tvEEEmlMhw5a2B8sl71sQ6sxWidgRaOSGW7l\ng1
            gctfdLMARuV6LkLiGy5k2FGAW/tfepEyySA/N9WhcHg+rZ4/x1thP0eYJPQ2YJ\nAjimHyBb+3tFs7KaOPu9G5xgbQWUWccukMDXqybqiUDSfU/T
            5/+XM8CKq/Fu0DBu\n3lg0NYigkZFs99lZJ1H4BkMWgL65aybO4XwfZJTGLe0=\n-----END CERTIFICATE-----'}

    Attributes:
        name (str):
        address (str):
        certificate (str):
        port (Union[Unset, int]):  Default: 62050.
        api_port (Union[Unset, int]):  Default: 62051.
        add_as_new_host (Union[Unset, bool]):  Default: True.
    """

    name: str
    address: str
    certificate: str
    port: Union[Unset, int] = 62050
    api_port: Union[Unset, int] = 62051
    add_as_new_host: Union[Unset, bool] = True
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        name = self.name
        address = self.address
        certificate = self.certificate
        port = self.port
        api_port = self.api_port
        add_as_new_host = self.add_as_new_host

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "name": name,
                "address": address,
                "certificate": certificate,
            }
        )
        if port is not UNSET:
            field_dict["port"] = port
        if api_port is not UNSET:
            field_dict["api_port"] = api_port
        if add_as_new_host is not UNSET:
            field_dict["add_as_new_host"] = add_as_new_host

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        name = d.pop("name")

        address = d.pop("address")

        certificate = d.pop("certificate")

        port = d.pop("port", UNSET)

        api_port = d.pop("api_port", UNSET)

        add_as_new_host = d.pop("add_as_new_host", UNSET)

        node_create = cls(
            name=name,
            address=address,
            certificate=certificate,
            port=port,
            api_port=api_port,
            add_as_new_host=add_as_new_host,
        )

        node_create.additional_properties = d
        return node_create

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/node_create.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

T = TypeVar("T", bound="NodeModify")


@_attrs_define
class NodeModify:
    r"""
    Example:
        {'name': 'DE node', 'address': '192.168.1.1', 'port': 62050, 'api_port': 62051, 'certificate': '-----BEGIN CERTI
            FICATE-----
            \nMIIEnDCCAoQCAQAwDQYJKoZIhvcNAQENBQAwEzERMA8GA1UEAwwIR296YXJnYWgw\nIBcNMjMwMjE5MjMwOTMyWhgPMjEyMzAxMjYyMzA5MzJa
            MBMxETAPBgNVBAMMCEdv\nemFyZ2FoMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0BvDh0eU78EJ\n+xzBWUjjMrWf/0rWV5fDl7b4
            RU8AjeviG1RmEc64ueZ3s6q1LI6DJX1+qGuqDEvp\nmRc09HihO07DyQgQqF38/E4CXshZ2L3UOzsa80lf74dhEqAR/EJQXXMwGSb3T9J9\nseCq
            CyiEn/JLEGsilDz64cTv8MXMAcjjpdefkFyQP+4hAKQgHbtfJ9KPSu4/lkZR\n/orsjoWGJv4LS0MsXV1t7LB/bNC7qOzlmzrfTMH4EmtmKH8Hwh
            MkL1nUG+vXEfwm\nQg3Ly+yrwKNw9+L7DxbKnoy2Zqp9dN+rzKDgcpHsoIYf0feInUHHlRUu303kAFQN\nGlnzZgD8ulHI1sQLNS3teYpj817G3E
            XKOhu56MvBehBR9GfvfS1D5D/QvwRfcaZI\nCULBPoGqovhrknbUXt9TEfzc9YnfSzlcJYcH54/aUBVJNs74EK38OQ+JciLnw4qe\ngbXEshaeLg
            GM3bhXwUhctcmZf5ASWDsAVtEeCXGNK+ua6wlFXKVd0jOt2ZZYG42X\nwrpHCErAWY7AoxHmXlfPcPM0Uu7FuEBP27f8U3N+glG1lWrogNn54j1Z
            rzQVUVVv\ngog78DrjjzrR0puQ9x9q6FvEUTAaaA06lvi2/6BuwO0jKrHQCP7fFUmRXg5B5lrJ\n9czSDHT9WH9Sc1qdxQTevhc9C/h6MuMCAwEA
            ATANBgkqhkiG9w0BAQ0FAAOCAgEA\nI7aXhLejp53NyuwzmdfeycY373TI4sD3WfPdEB6+FSCX38YghyQl8tkeaHPgPKY5\n+vA+eVxE7E961UNP
            tJtJg/dzBvoWUroTnpvKjVdDImFaZa/PvUMgSEe8tC3FtB6i\nAp7f0yYOGsFf6oaOxMfs/F0sGflsaVWuiATTsV8Er+uzge77Q8AXzy6spuXg3A
            LF\n56tqzZY5x/04g1KUQB4JN+7JzipnfSIUof0eAKf9gQbumUU+Q2b32HMC2MOlUjv+\nIl8rJ9cs0zwC1BOmqoS3Ez22dgtT7FucvIJ1MGP8oU
            AudMmrXDxx/d7CmnD5q1v4\nXFSa6Zv8LPLCz5iMbo0FjNlKyZo3699PtyBFXt3zyfTPmiy19RVGTziHqJ9NR9kW\nkBwvFzIy+qPc/dJAk435hV
            aV3pRBC7Pl2Y7k/pJxxlC07PkACXuhwtUGhQrHYWkK\niLlV21kNnWuvjS1orTwvuW3aagb6tvEEEmlMhw5a2B8sl71sQ6sxWidgRaOSGW7l\ng1
            gctfdLMARuV6LkLiGy5k2FGAW/tfepEyySA/N9WhcHg+rZ4/x1thP0eYJPQ2YJ\nAjimHyBb+3tFs7KaOPu9G5xgbQWUWccukMDXqybqiUDSfU/T
            5/+XM8CKq/Fu0DBu\n3lg0NYigkZFs99lZJ1H4BkMWgL65aybO4XwfZJTGLe0=\n-----END CERTIFICATE-----'}

    Attributes:
        name (Union[Unset, None, str]):
        address (Union[Unset, None, str]):
        port (Union[Unset, None, int]):
        api_port (Union[Unset, None, int]):
        certificate (Union[Unset, None, str]):
    """

    name: Union[Unset, None, str] = UNSET
    address: Union[Unset, None, str] = UNSET
    port: Union[Unset, None, int] = UNSET
    api_port: Union[Unset, None, int] = UNSET
    certificate: Union[Unset, None, str] = UNSET
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        name = self.name
        address = self.address
        port = self.port
        api_port = self.api_port
        certificate = self.certificate

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})
        if name is not UNSET:
            field_dict["name"] = name
        if address is not UNSET:
            field_dict["address"] = address
        if port is not UNSET:
            field_dict["port"] = port
        if api_port is not UNSET:
            field_dict["api_port"] = api_port
        if certificate is not UNSET:
            field_dict["certificate"] = certificate

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        name = d.pop("name", UNSET)

        address = d.pop("address", UNSET)

        port = d.pop("port", UNSET)

        api_port = d.pop("api_port", UNSET)

        certificate = d.pop("certificate", UNSET)

        node_modify = cls(
            name=name,
            address=address,
            port=port,
            api_port=api_port,
            certificate=certificate,
        )

        node_modify.additional_properties = d
        return node_modify

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/node_modify.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..models.node_status import NodeStatus
from ..types import UNSET, Unset

T = TypeVar("T", bound="NodeResponse")


@_attrs_define
class NodeResponse:
    """
    Attributes:
        name (str):
        address (str):
        certificate (str):
        id (int):
        status (NodeStatus): An enumeration.
        port (Union[Unset, int]):  Default: 62050.
        api_port (Union[Unset, int]):  Default: 62051.
        xray_version (Union[Unset, str]):
        message (Union[Unset, str]):
    """

    name: str
    address: str
    certificate: str
    id: int
    status: NodeStatus
    port: Union[Unset, int] = 62050
    api_port: Union[Unset, int] = 62051
    xray_version: Union[Unset, str] = UNSET
    message: Union[Unset, str] = UNSET
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        name = self.name
        address = self.address
        certificate = self.certificate
        id = self.id
        status = self.status.value

        port = self.port
        api_port = self.api_port
        xray_version = self.xray_version
        message = self.message

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "name": name,
                "address": address,
                "certificate": certificate,
                "id": id,
                "status": status,
            }
        )
        if port is not UNSET:
            field_dict["port"] = port
        if api_port is not UNSET:
            field_dict["api_port"] = api_port
        if xray_version is not UNSET:
            field_dict["xray_version"] = xray_version
        if message is not UNSET:
            field_dict["message"] = message

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        name = d.pop("name")

        address = d.pop("address")

        certificate = d.pop("certificate")

        id = d.pop("id")

        status = NodeStatus(d.pop("status"))

        port = d.pop("port", UNSET)

        api_port = d.pop("api_port", UNSET)

        xray_version = d.pop("xray_version", UNSET)

        message = d.pop("message", UNSET)

        node_response = cls(
            name=name,
            address=address,
            certificate=certificate,
            id=id,
            status=status,
            port=port,
            api_port=api_port,
            xray_version=xray_version,
            message=message,
        )

        node_response.additional_properties = d
        return node_response

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/node_response.py
govfvck/Marzbot-free
from enum import Enum


class NodeStatus(str, Enum):
    CONNECTED = "connected"
    CONNECTING = "connecting"
    DISABLED = "disabled"
    ERROR = "error"

    def __str__(self) -> str:
        return str(self.value)

marzban_client/models/node_status.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

T = TypeVar("T", bound="NodeUsageResponse")


@_attrs_define
class NodeUsageResponse:
    """
    Attributes:
        node_name (str):
        uplink (int):
        downlink (int):
        node_id (Union[Unset, int]):
    """

    node_name: str
    uplink: int
    downlink: int
    node_id: Union[Unset, int] = UNSET
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        node_name = self.node_name
        uplink = self.uplink
        downlink = self.downlink
        node_id = self.node_id

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "node_name": node_name,
                "uplink": uplink,
                "downlink": downlink,
            }
        )
        if node_id is not UNSET:
            field_dict["node_id"] = node_id

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        node_name = d.pop("node_name")

        uplink = d.pop("uplink")

        downlink = d.pop("downlink")

        node_id = d.pop("node_id", UNSET)

        node_usage_response = cls(
            node_name=node_name,
            uplink=uplink,
            downlink=downlink,
            node_id=node_id,
        )

        node_usage_response.additional_properties = d
        return node_usage_response

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/node_usage_response.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

if TYPE_CHECKING:
    from ..models.node_usage_response import NodeUsageResponse


T = TypeVar("T", bound="NodesUsageResponse")


@_attrs_define
class NodesUsageResponse:
    """
    Attributes:
        usages (List['NodeUsageResponse']):
    """

    usages: List["NodeUsageResponse"]
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        usages = []
        for usages_item_data in self.usages:
            usages_item = usages_item_data.to_dict()

            usages.append(usages_item)

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "usages": usages,
            }
        )

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.node_usage_response import NodeUsageResponse

        d = src_dict.copy()
        usages = []
        _usages = d.pop("usages")
        for usages_item_data in _usages:
            usages_item = NodeUsageResponse.from_dict(usages_item_data)

            usages.append(usages_item)

        nodes_usage_response = cls(
            usages=usages,
        )

        nodes_usage_response.additional_properties = d
        return nodes_usage_response

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/nodes_usage_response.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..models.proxy_host_alpn import ProxyHostALPN
from ..models.proxy_host_fingerprint import ProxyHostFingerprint
from ..models.proxy_host_security import ProxyHostSecurity
from ..types import UNSET, Unset

T = TypeVar("T", bound="ProxyHost")


@_attrs_define
class ProxyHost:
    """
    Attributes:
        remark (str):
        address (str):
        port (Union[Unset, None, int]):
        sni (Union[Unset, None, str]):
        host (Union[Unset, None, str]):
        security (Union[Unset, ProxyHostSecurity]): An enumeration. Default: ProxyHostSecurity.INBOUND_DEFAULT.
        alpn (Union[Unset, ProxyHostALPN]): An enumeration. Default: ProxyHostALPN.VALUE_0.
        fingerprint (Union[Unset, ProxyHostFingerprint]): An enumeration. Default: ProxyHostFingerprint.VALUE_0.
    """

    remark: str
    address: str
    port: Union[Unset, None, int] = UNSET
    sni: Union[Unset, None, str] = UNSET
    host: Union[Unset, None, str] = UNSET
    security: Union[Unset, ProxyHostSecurity] = ProxyHostSecurity.INBOUND_DEFAULT
    alpn: Union[Unset, ProxyHostALPN] = ProxyHostALPN.VALUE_0
    fingerprint: Union[Unset, ProxyHostFingerprint] = ProxyHostFingerprint.VALUE_0
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        remark = self.remark
        address = self.address
        port = self.port
        sni = self.sni
        host = self.host
        security: Union[Unset, str] = UNSET
        if not isinstance(self.security, Unset):
            security = self.security.value

        alpn: Union[Unset, str] = UNSET
        if not isinstance(self.alpn, Unset):
            alpn = self.alpn.value

        fingerprint: Union[Unset, str] = UNSET
        if not isinstance(self.fingerprint, Unset):
            fingerprint = self.fingerprint.value

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "remark": remark,
                "address": address,
            }
        )
        if port is not UNSET:
            field_dict["port"] = port
        if sni is not UNSET:
            field_dict["sni"] = sni
        if host is not UNSET:
            field_dict["host"] = host
        if security is not UNSET:
            field_dict["security"] = security
        if alpn is not UNSET:
            field_dict["alpn"] = alpn
        if fingerprint is not UNSET:
            field_dict["fingerprint"] = fingerprint

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        remark = d.pop("remark")

        address = d.pop("address")

        port = d.pop("port", UNSET)

        sni = d.pop("sni", UNSET)

        host = d.pop("host", UNSET)

        _security = d.pop("security", UNSET)
        security: Union[Unset, ProxyHostSecurity]
        if isinstance(_security, Unset):
            security = UNSET
        else:
            security = ProxyHostSecurity(_security)

        _alpn = d.pop("alpn", UNSET)
        alpn: Union[Unset, ProxyHostALPN]
        if isinstance(_alpn, Unset):
            alpn = UNSET
        else:
            alpn = ProxyHostALPN(_alpn)

        _fingerprint = d.pop("fingerprint", UNSET)
        fingerprint: Union[Unset, ProxyHostFingerprint]
        if isinstance(_fingerprint, Unset):
            fingerprint = UNSET
        else:
            fingerprint = ProxyHostFingerprint(_fingerprint)

        proxy_host = cls(
            remark=remark,
            address=address,
            port=port,
            sni=sni,
            host=host,
            security=security,
            alpn=alpn,
            fingerprint=fingerprint,
        )

        proxy_host.additional_properties = d
        return proxy_host

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/proxy_host.py
govfvck/Marzbot-free
from enum import Enum


class ProxyHostALPN(str, Enum):
    H2 = "h2"
    H2HTTP1_1 = "h2,http/1.1"
    HTTP1_1 = "http/1.1"
    VALUE_0 = ""

    def __str__(self) -> str:
        return str(self.value)

marzban_client/models/proxy_host_alpn.py
govfvck/Marzbot-free
from enum import Enum


class ProxyHostFingerprint(str, Enum):
    ANDROID = "android"
    CHROME = "chrome"
    EDGE = "edge"
    FIREFOX = "firefox"
    IOS = "ios"
    QQ = "qq"
    RANDOM = "random"
    RANDOMIZED = "randomized"
    SAFARI = "safari"
    VALUE_0 = ""
    VALUE_7 = "360"

    def __str__(self) -> str:
        return str(self.value)

marzban_client/models/proxy_host_fingerprint.py
govfvck/Marzbot-free
from enum import Enum


class ProxyHostSecurity(str, Enum):
    INBOUND_DEFAULT = "inbound_default"
    NONE = "none"
    TLS = "tls"

    def __str__(self) -> str:
        return str(self.value)

marzban_client/models/proxy_host_security.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, Union, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..models.proxy_types import ProxyTypes

T = TypeVar("T", bound="ProxyInbound")


@_attrs_define
class ProxyInbound:
    """
    Attributes:
        tag (str):
        protocol (ProxyTypes): An enumeration.
        network (str):
        tls (str):
        port (Union[int, str]):
    """

    tag: str
    protocol: ProxyTypes
    network: str
    tls: str
    port: Union[int, str]
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        tag = self.tag
        protocol = self.protocol.value

        network = self.network
        tls = self.tls
        port: Union[int, str]

        port = self.port

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "tag": tag,
                "protocol": protocol,
                "network": network,
                "tls": tls,
                "port": port,
            }
        )

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        tag = d.pop("tag")

        protocol = ProxyTypes(d.pop("protocol"))

        network = d.pop("network")

        tls = d.pop("tls")

        def _parse_port(data: object) -> Union[int, str]:
            return cast(Union[int, str], data)

        port = _parse_port(d.pop("port"))

        proxy_inbound = cls(
            tag=tag,
            protocol=protocol,
            network=network,
            tls=tls,
            port=port,
        )

        proxy_inbound.additional_properties = d
        return proxy_inbound

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/proxy_inbound.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="ProxySettings")


@_attrs_define
class ProxySettings:
    """ """

    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        proxy_settings = cls()

        proxy_settings.additional_properties = d
        return proxy_settings

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/proxy_settings.py
govfvck/Marzbot-free
from enum import Enum


class ProxyTypes(str, Enum):
    SHADOWSOCKS = "shadowsocks"
    TROJAN = "trojan"
    VLESS = "vless"
    VMESS = "vmess"

    def __str__(self) -> str:
        return str(self.value)

marzban_client/models/proxy_types.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="SystemStats")


@_attrs_define
class SystemStats:
    """
    Attributes:
        version (str):
        mem_total (int):
        mem_used (int):
        cpu_cores (int):
        cpu_usage (float):
        total_user (int):
        users_active (int):
        incoming_bandwidth (int):
        outgoing_bandwidth (int):
        incoming_bandwidth_speed (int):
        outgoing_bandwidth_speed (int):
    """

    version: str
    mem_total: int
    mem_used: int
    cpu_cores: int
    cpu_usage: float
    total_user: int
    users_active: int
    incoming_bandwidth: int
    outgoing_bandwidth: int
    incoming_bandwidth_speed: int
    outgoing_bandwidth_speed: int
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        version = self.version
        mem_total = self.mem_total
        mem_used = self.mem_used
        cpu_cores = self.cpu_cores
        cpu_usage = self.cpu_usage
        total_user = self.total_user
        users_active = self.users_active
        incoming_bandwidth = self.incoming_bandwidth
        outgoing_bandwidth = self.outgoing_bandwidth
        incoming_bandwidth_speed = self.incoming_bandwidth_speed
        outgoing_bandwidth_speed = self.outgoing_bandwidth_speed

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "version": version,
                "mem_total": mem_total,
                "mem_used": mem_used,
                "cpu_cores": cpu_cores,
                "cpu_usage": cpu_usage,
                "total_user": total_user,
                "users_active": users_active,
                "incoming_bandwidth": incoming_bandwidth,
                "outgoing_bandwidth": outgoing_bandwidth,
                "incoming_bandwidth_speed": incoming_bandwidth_speed,
                "outgoing_bandwidth_speed": outgoing_bandwidth_speed,
            }
        )

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        version = d.pop("version")

        mem_total = d.pop("mem_total")

        mem_used = d.pop("mem_used")

        cpu_cores = d.pop("cpu_cores")

        cpu_usage = d.pop("cpu_usage")

        total_user = d.pop("total_user")

        users_active = d.pop("users_active")

        incoming_bandwidth = d.pop("incoming_bandwidth")

        outgoing_bandwidth = d.pop("outgoing_bandwidth")

        incoming_bandwidth_speed = d.pop("incoming_bandwidth_speed")

        outgoing_bandwidth_speed = d.pop("outgoing_bandwidth_speed")

        system_stats = cls(
            version=version,
            mem_total=mem_total,
            mem_used=mem_used,
            cpu_cores=cpu_cores,
            cpu_usage=cpu_usage,
            total_user=total_user,
            users_active=users_active,
            incoming_bandwidth=incoming_bandwidth,
            outgoing_bandwidth=outgoing_bandwidth,
            incoming_bandwidth_speed=incoming_bandwidth_speed,
            outgoing_bandwidth_speed=outgoing_bandwidth_speed,
        )

        system_stats.additional_properties = d
        return system_stats

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/system_stats.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

T = TypeVar("T", bound="Token")


@_attrs_define
class Token:
    """
    Attributes:
        access_token (str):
        token_type (Union[Unset, str]):  Default: 'bearer'.
    """

    access_token: str
    token_type: Union[Unset, str] = "bearer"
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        access_token = self.access_token
        token_type = self.token_type

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "access_token": access_token,
            }
        )
        if token_type is not UNSET:
            field_dict["token_type"] = token_type

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        access_token = d.pop("access_token")

        token_type = d.pop("token_type", UNSET)

        token = cls(
            access_token=access_token,
            token_type=token_type,
        )

        token.additional_properties = d
        return token

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/token.py
govfvck/Marzbot-free
import datetime
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field
from dateutil.parser import isoparse

from ..models.user_data_limit_reset_strategy import UserDataLimitResetStrategy
from ..types import UNSET, Unset

if TYPE_CHECKING:
    from ..models.user_create_inbounds import UserCreateInbounds
    from ..models.user_create_proxies import UserCreateProxies


T = TypeVar("T", bound="UserCreate")


@_attrs_define
class UserCreate:
    """
    Example:
        {'username': 'user1234', 'proxies': {'vmess': {'id': '35e4e39c-7d5c-4f4b-8b71-558e4f37ff53'}, 'vless': {}},
            'inbounds': {'vmess': ['VMess TCP', 'VMess Websocket'], 'vless': ['VLESS TCP REALITY', 'VLESS GRPC REALITY']},
            'expire': 0, 'data_limit': 0, 'data_limit_reset_strategy': 'no_reset', 'note': ''}

    Attributes:
        username (str):
        proxies (Union[Unset, UserCreateProxies]):
        expire (Union[Unset, None, int]):
        data_limit (Union[Unset, int]): data_limit can be 0 or greater
        data_limit_reset_strategy (Union[Unset, UserDataLimitResetStrategy]): An enumeration. Default:
            UserDataLimitResetStrategy.NO_RESET.
        inbounds (Union[Unset, UserCreateInbounds]):
        note (Union[Unset, None, str]):
        sub_updated_at (Union[Unset, None, datetime.datetime]):
        sub_last_user_agent (Union[Unset, None, str]):
    """

    username: str
    proxies: Union[Unset, "UserCreateProxies"] = UNSET
    expire: Union[Unset, None, int] = UNSET
    data_limit: Union[Unset, int] = UNSET
    data_limit_reset_strategy: Union[
        Unset, UserDataLimitResetStrategy
    ] = UserDataLimitResetStrategy.NO_RESET
    inbounds: Union[Unset, "UserCreateInbounds"] = UNSET
    note: Union[Unset, None, str] = UNSET
    sub_updated_at: Union[Unset, None, datetime.datetime] = UNSET
    sub_last_user_agent: Union[Unset, None, str] = UNSET
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        username = self.username
        proxies: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.proxies, Unset):
            proxies = self.proxies.to_dict()

        expire = self.expire
        data_limit = self.data_limit
        data_limit_reset_strategy: Union[Unset, str] = UNSET
        if not isinstance(self.data_limit_reset_strategy, Unset):
            data_limit_reset_strategy = self.data_limit_reset_strategy.value

        inbounds: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.inbounds, Unset):
            inbounds = self.inbounds.to_dict()

        note = self.note
        sub_updated_at: Union[Unset, None, str] = UNSET
        if not isinstance(self.sub_updated_at, Unset):
            sub_updated_at = (
                self.sub_updated_at.isoformat() if self.sub_updated_at else None
            )

        sub_last_user_agent = self.sub_last_user_agent

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "username": username,
            }
        )
        if proxies is not UNSET:
            field_dict["proxies"] = proxies
        if expire is not UNSET:
            field_dict["expire"] = expire
        if data_limit is not UNSET:
            field_dict["data_limit"] = data_limit
        if data_limit_reset_strategy is not UNSET:
            field_dict["data_limit_reset_strategy"] = data_limit_reset_strategy
        if inbounds is not UNSET:
            field_dict["inbounds"] = inbounds
        if note is not UNSET:
            field_dict["note"] = note
        if sub_updated_at is not UNSET:
            field_dict["sub_updated_at"] = sub_updated_at
        if sub_last_user_agent is not UNSET:
            field_dict["sub_last_user_agent"] = sub_last_user_agent

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.user_create_inbounds import UserCreateInbounds
        from ..models.user_create_proxies import UserCreateProxies

        d = src_dict.copy()
        username = d.pop("username")

        _proxies = d.pop("proxies", UNSET)
        proxies: Union[Unset, UserCreateProxies]
        if isinstance(_proxies, Unset):
            proxies = UNSET
        else:
            proxies = UserCreateProxies.from_dict(_proxies)

        expire = d.pop("expire", UNSET)

        data_limit = d.pop("data_limit", UNSET)

        _data_limit_reset_strategy = d.pop("data_limit_reset_strategy", UNSET)
        data_limit_reset_strategy: Union[Unset, UserDataLimitResetStrategy]
        if isinstance(_data_limit_reset_strategy, Unset):
            data_limit_reset_strategy = UNSET
        else:
            data_limit_reset_strategy = UserDataLimitResetStrategy(
                _data_limit_reset_strategy
            )

        _inbounds = d.pop("inbounds", UNSET)
        inbounds: Union[Unset, UserCreateInbounds]
        if isinstance(_inbounds, Unset):
            inbounds = UNSET
        else:
            inbounds = UserCreateInbounds.from_dict(_inbounds)

        note = d.pop("note", UNSET)

        _sub_updated_at = d.pop("sub_updated_at", UNSET)
        sub_updated_at: Union[Unset, None, datetime.datetime]
        if _sub_updated_at is None:
            sub_updated_at = None
        elif isinstance(_sub_updated_at, Unset):
            sub_updated_at = UNSET
        else:
            sub_updated_at = isoparse(_sub_updated_at)

        sub_last_user_agent = d.pop("sub_last_user_agent", UNSET)

        user_create = cls(
            username=username,
            proxies=proxies,
            expire=expire,
            data_limit=data_limit,
            data_limit_reset_strategy=data_limit_reset_strategy,
            inbounds=inbounds,
            note=note,
            sub_updated_at=sub_updated_at,
            sub_last_user_agent=sub_last_user_agent,
        )

        user_create.additional_properties = d
        return user_create

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_create.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="UserCreateInbounds")


@_attrs_define
class UserCreateInbounds:
    """ """

    additional_properties: Dict[str, List[str]] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = prop

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        user_create_inbounds = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = cast(List[str], prop_dict)

            additional_properties[prop_name] = additional_property

        user_create_inbounds.additional_properties = additional_properties
        return user_create_inbounds

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> List[str]:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: List[str]) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_create_inbounds.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

if TYPE_CHECKING:
    from ..models.proxy_settings import ProxySettings


T = TypeVar("T", bound="UserCreateProxies")


@_attrs_define
class UserCreateProxies:
    """ """

    additional_properties: Dict[str, "ProxySettings"] = _attrs_field(
        init=False, factory=dict
    )

    def to_dict(self) -> Dict[str, Any]:
        pass

        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = prop.to_dict()

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.proxy_settings import ProxySettings

        d = src_dict.copy()
        user_create_proxies = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = ProxySettings.from_dict(prop_dict)

            additional_properties[prop_name] = additional_property

        user_create_proxies.additional_properties = additional_properties
        return user_create_proxies

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> "ProxySettings":
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: "ProxySettings") -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_create_proxies.py
govfvck/Marzbot-free
from enum import Enum


class UserDataLimitResetStrategy(str, Enum):
    DAY = "day"
    MONTH = "month"
    NO_RESET = "no_reset"
    WEEK = "week"
    YEAR = "year"

    def __str__(self) -> str:
        return str(self.value)

marzban_client/models/user_data_limit_reset_strategy.py
govfvck/Marzbot-free
import datetime
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field
from dateutil.parser import isoparse

from ..models.user_data_limit_reset_strategy import UserDataLimitResetStrategy
from ..models.user_status_modify import UserStatusModify
from ..types import UNSET, Unset

if TYPE_CHECKING:
    from ..models.user_modify_inbounds import UserModifyInbounds
    from ..models.user_modify_proxies import UserModifyProxies


T = TypeVar("T", bound="UserModify")


@_attrs_define
class UserModify:
    """
    Example:
        {'proxies': {'vmess': {'id': '35e4e39c-7d5c-4f4b-8b71-558e4f37ff53'}, 'vless': {}}, 'inbounds': {'vmess':
            ['VMess TCP', 'VMess Websocket'], 'vless': ['VLESS TCP REALITY', 'VLESS GRPC REALITY']}, 'expire': 0,
            'data_limit': 0, 'data_limit_reset_strategy': 'no_reset', 'status': 'active', 'note': ''}

    Attributes:
        proxies (Union[Unset, UserModifyProxies]):
        expire (Union[Unset, None, int]):
        data_limit (Union[Unset, int]): data_limit can be 0 or greater
        data_limit_reset_strategy (Union[Unset, UserDataLimitResetStrategy]): An enumeration.
        inbounds (Union[Unset, UserModifyInbounds]):
        note (Union[Unset, None, str]):
        sub_updated_at (Union[Unset, None, datetime.datetime]):
        sub_last_user_agent (Union[Unset, None, str]):
        status (Union[Unset, UserStatusModify]): An enumeration.
    """

    proxies: Union[Unset, "UserModifyProxies"] = UNSET
    expire: Union[Unset, None, int] = UNSET
    data_limit: Union[Unset, int] = UNSET
    data_limit_reset_strategy: Union[Unset, UserDataLimitResetStrategy] = UNSET
    inbounds: Union[Unset, "UserModifyInbounds"] = UNSET
    note: Union[Unset, None, str] = UNSET
    sub_updated_at: Union[Unset, None, datetime.datetime] = UNSET
    sub_last_user_agent: Union[Unset, None, str] = UNSET
    status: Union[Unset, UserStatusModify] = UNSET
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        proxies: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.proxies, Unset):
            proxies = self.proxies.to_dict()

        expire = self.expire
        data_limit = self.data_limit
        data_limit_reset_strategy: Union[Unset, str] = UNSET
        if not isinstance(self.data_limit_reset_strategy, Unset):
            data_limit_reset_strategy = self.data_limit_reset_strategy.value

        inbounds: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.inbounds, Unset):
            inbounds = self.inbounds.to_dict()

        note = self.note
        sub_updated_at: Union[Unset, None, str] = UNSET
        if not isinstance(self.sub_updated_at, Unset):
            sub_updated_at = (
                self.sub_updated_at.isoformat() if self.sub_updated_at else None
            )

        sub_last_user_agent = self.sub_last_user_agent
        status: Union[Unset, str] = UNSET
        if not isinstance(self.status, Unset):
            status = self.status.value

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})
        if proxies is not UNSET:
            field_dict["proxies"] = proxies
        if expire is not UNSET:
            field_dict["expire"] = expire
        if data_limit is not UNSET:
            field_dict["data_limit"] = data_limit
        if data_limit_reset_strategy is not UNSET:
            field_dict["data_limit_reset_strategy"] = data_limit_reset_strategy
        if inbounds is not UNSET:
            field_dict["inbounds"] = inbounds
        if note is not UNSET:
            field_dict["note"] = note
        if sub_updated_at is not UNSET:
            field_dict["sub_updated_at"] = sub_updated_at
        if sub_last_user_agent is not UNSET:
            field_dict["sub_last_user_agent"] = sub_last_user_agent
        if status is not UNSET:
            field_dict["status"] = status

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.user_modify_inbounds import UserModifyInbounds
        from ..models.user_modify_proxies import UserModifyProxies

        d = src_dict.copy()
        _proxies = d.pop("proxies", UNSET)
        proxies: Union[Unset, UserModifyProxies]
        if isinstance(_proxies, Unset):
            proxies = UNSET
        else:
            proxies = UserModifyProxies.from_dict(_proxies)

        expire = d.pop("expire", UNSET)

        data_limit = d.pop("data_limit", UNSET)

        _data_limit_reset_strategy = d.pop("data_limit_reset_strategy", UNSET)
        data_limit_reset_strategy: Union[Unset, UserDataLimitResetStrategy]
        if isinstance(_data_limit_reset_strategy, Unset):
            data_limit_reset_strategy = UNSET
        else:
            data_limit_reset_strategy = UserDataLimitResetStrategy(
                _data_limit_reset_strategy
            )

        _inbounds = d.pop("inbounds", UNSET)
        inbounds: Union[Unset, UserModifyInbounds]
        if isinstance(_inbounds, Unset):
            inbounds = UNSET
        else:
            inbounds = UserModifyInbounds.from_dict(_inbounds)

        note = d.pop("note", UNSET)

        _sub_updated_at = d.pop("sub_updated_at", UNSET)
        sub_updated_at: Union[Unset, None, datetime.datetime]
        if _sub_updated_at is None:
            sub_updated_at = None
        elif isinstance(_sub_updated_at, Unset):
            sub_updated_at = UNSET
        else:
            sub_updated_at = isoparse(_sub_updated_at)

        sub_last_user_agent = d.pop("sub_last_user_agent", UNSET)

        _status = d.pop("status", UNSET)
        status: Union[Unset, UserStatusModify]
        if isinstance(_status, Unset):
            status = UNSET
        else:
            status = UserStatusModify(_status)

        user_modify = cls(
            proxies=proxies,
            expire=expire,
            data_limit=data_limit,
            data_limit_reset_strategy=data_limit_reset_strategy,
            inbounds=inbounds,
            note=note,
            sub_updated_at=sub_updated_at,
            sub_last_user_agent=sub_last_user_agent,
            status=status,
        )

        user_modify.additional_properties = d
        return user_modify

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_modify.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="UserModifyInbounds")


@_attrs_define
class UserModifyInbounds:
    """ """

    additional_properties: Dict[str, List[str]] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = prop

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        user_modify_inbounds = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = cast(List[str], prop_dict)

            additional_properties[prop_name] = additional_property

        user_modify_inbounds.additional_properties = additional_properties
        return user_modify_inbounds

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> List[str]:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: List[str]) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_modify_inbounds.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

if TYPE_CHECKING:
    from ..models.proxy_settings import ProxySettings


T = TypeVar("T", bound="UserModifyProxies")


@_attrs_define
class UserModifyProxies:
    """ """

    additional_properties: Dict[str, "ProxySettings"] = _attrs_field(
        init=False, factory=dict
    )

    def to_dict(self) -> Dict[str, Any]:
        pass

        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = prop.to_dict()

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.proxy_settings import ProxySettings

        d = src_dict.copy()
        user_modify_proxies = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = ProxySettings.from_dict(prop_dict)

            additional_properties[prop_name] = additional_property

        user_modify_proxies.additional_properties = additional_properties
        return user_modify_proxies

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> "ProxySettings":
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: "ProxySettings") -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_modify_proxies.py
govfvck/Marzbot-free
import datetime
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field
from dateutil.parser import isoparse

from ..models.user_data_limit_reset_strategy import UserDataLimitResetStrategy
from ..models.user_status import UserStatus
from ..types import UNSET, Unset

if TYPE_CHECKING:
    from ..models.user_response_excluded_inbounds import UserResponseExcludedInbounds
    from ..models.user_response_inbounds import UserResponseInbounds
    from ..models.user_response_proxies import UserResponseProxies


T = TypeVar("T", bound="UserResponse")


@_attrs_define
class UserResponse:
    """
    Attributes:
        proxies (UserResponseProxies):
        username (str):
        status (UserStatus): An enumeration.
        used_traffic (int):
        created_at (datetime.datetime):
        expire (Union[Unset, None, int]):
        data_limit (Union[Unset, int]): data_limit can be 0 or greater
        data_limit_reset_strategy (Union[Unset, UserDataLimitResetStrategy]): An enumeration. Default:
            UserDataLimitResetStrategy.NO_RESET.
        inbounds (Union[Unset, UserResponseInbounds]):
        note (Union[Unset, None, str]):
        sub_updated_at (Union[Unset, None, datetime.datetime]):
        sub_last_user_agent (Union[Unset, None, str]):
        lifetime_used_traffic (Union[Unset, int]):
        links (Union[Unset, List[str]]):
        subscription_url (Union[Unset, str]):  Default: ''.
        excluded_inbounds (Union[Unset, UserResponseExcludedInbounds]):
    """

    proxies: "UserResponseProxies"
    username: str
    status: UserStatus
    used_traffic: int
    created_at: datetime.datetime
    expire: Union[Unset, None, int] = UNSET
    data_limit: Union[Unset, int] = UNSET
    data_limit_reset_strategy: Union[
        Unset, UserDataLimitResetStrategy
    ] = UserDataLimitResetStrategy.NO_RESET
    inbounds: Union[Unset, "UserResponseInbounds"] = UNSET
    note: Union[Unset, None, str] = UNSET
    sub_updated_at: Union[Unset, None, datetime.datetime] = UNSET
    sub_last_user_agent: Union[Unset, None, str] = UNSET
    lifetime_used_traffic: Union[Unset, int] = 0
    links: Union[Unset, List[str]] = UNSET
    subscription_url: Union[Unset, str] = ""
    excluded_inbounds: Union[Unset, "UserResponseExcludedInbounds"] = UNSET
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        proxies = self.proxies.to_dict()

        username = self.username
        status = self.status.value

        used_traffic = self.used_traffic
        created_at = self.created_at.isoformat()

        expire = self.expire
        data_limit = self.data_limit
        data_limit_reset_strategy: Union[Unset, str] = UNSET
        if not isinstance(self.data_limit_reset_strategy, Unset):
            data_limit_reset_strategy = self.data_limit_reset_strategy.value

        inbounds: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.inbounds, Unset):
            inbounds = self.inbounds.to_dict()

        note = self.note
        sub_updated_at: Union[Unset, None, str] = UNSET
        if not isinstance(self.sub_updated_at, Unset):
            sub_updated_at = (
                self.sub_updated_at.isoformat() if self.sub_updated_at else None
            )

        sub_last_user_agent = self.sub_last_user_agent
        lifetime_used_traffic = self.lifetime_used_traffic
        links: Union[Unset, List[str]] = UNSET
        if not isinstance(self.links, Unset):
            links = self.links

        subscription_url = self.subscription_url
        excluded_inbounds: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.excluded_inbounds, Unset):
            excluded_inbounds = self.excluded_inbounds.to_dict()

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "proxies": proxies,
                "username": username,
                "status": status,
                "used_traffic": used_traffic,
                "created_at": created_at,
            }
        )
        if expire is not UNSET:
            field_dict["expire"] = expire
        if data_limit is not UNSET:
            field_dict["data_limit"] = data_limit
        if data_limit_reset_strategy is not UNSET:
            field_dict["data_limit_reset_strategy"] = data_limit_reset_strategy
        if inbounds is not UNSET:
            field_dict["inbounds"] = inbounds
        if note is not UNSET:
            field_dict["note"] = note
        if sub_updated_at is not UNSET:
            field_dict["sub_updated_at"] = sub_updated_at
        if sub_last_user_agent is not UNSET:
            field_dict["sub_last_user_agent"] = sub_last_user_agent
        if lifetime_used_traffic is not UNSET:
            field_dict["lifetime_used_traffic"] = lifetime_used_traffic
        if links is not UNSET:
            field_dict["links"] = links
        if subscription_url is not UNSET:
            field_dict["subscription_url"] = subscription_url
        if excluded_inbounds is not UNSET:
            field_dict["excluded_inbounds"] = excluded_inbounds

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.user_response_excluded_inbounds import (
            UserResponseExcludedInbounds,
        )
        from ..models.user_response_inbounds import UserResponseInbounds
        from ..models.user_response_proxies import UserResponseProxies

        d = src_dict.copy()
        proxies = UserResponseProxies.from_dict(d.pop("proxies"))

        username = d.pop("username")

        status = UserStatus(d.pop("status"))

        used_traffic = d.pop("used_traffic")

        created_at = isoparse(d.pop("created_at"))

        expire = d.pop("expire", UNSET)

        data_limit = d.pop("data_limit", UNSET)

        _data_limit_reset_strategy = d.pop("data_limit_reset_strategy", UNSET)
        data_limit_reset_strategy: Union[Unset, UserDataLimitResetStrategy]
        if isinstance(_data_limit_reset_strategy, Unset):
            data_limit_reset_strategy = UNSET
        else:
            data_limit_reset_strategy = UserDataLimitResetStrategy(
                _data_limit_reset_strategy
            )

        _inbounds = d.pop("inbounds", UNSET)
        inbounds: Union[Unset, UserResponseInbounds]
        if isinstance(_inbounds, Unset):
            inbounds = UNSET
        else:
            inbounds = UserResponseInbounds.from_dict(_inbounds)

        note = d.pop("note", UNSET)

        _sub_updated_at = d.pop("sub_updated_at", UNSET)
        sub_updated_at: Union[Unset, None, datetime.datetime]
        if _sub_updated_at is None:
            sub_updated_at = None
        elif isinstance(_sub_updated_at, Unset):
            sub_updated_at = UNSET
        else:
            sub_updated_at = isoparse(_sub_updated_at)

        sub_last_user_agent = d.pop("sub_last_user_agent", UNSET)

        lifetime_used_traffic = d.pop("lifetime_used_traffic", UNSET)

        links = cast(List[str], d.pop("links", UNSET))

        subscription_url = d.pop("subscription_url", UNSET)

        _excluded_inbounds = d.pop("excluded_inbounds", UNSET)
        excluded_inbounds: Union[Unset, UserResponseExcludedInbounds]
        if isinstance(_excluded_inbounds, Unset):
            excluded_inbounds = UNSET
        else:
            excluded_inbounds = UserResponseExcludedInbounds.from_dict(
                _excluded_inbounds
            )

        user_response = cls(
            proxies=proxies,
            username=username,
            status=status,
            used_traffic=used_traffic,
            created_at=created_at,
            expire=expire,
            data_limit=data_limit,
            data_limit_reset_strategy=data_limit_reset_strategy,
            inbounds=inbounds,
            note=note,
            sub_updated_at=sub_updated_at,
            sub_last_user_agent=sub_last_user_agent,
            lifetime_used_traffic=lifetime_used_traffic,
            links=links,
            subscription_url=subscription_url,
            excluded_inbounds=excluded_inbounds,
        )

        user_response.additional_properties = d
        return user_response

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_response.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="UserResponseExcludedInbounds")


@_attrs_define
class UserResponseExcludedInbounds:
    """ """

    additional_properties: Dict[str, List[str]] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = prop

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        user_response_excluded_inbounds = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = cast(List[str], prop_dict)

            additional_properties[prop_name] = additional_property

        user_response_excluded_inbounds.additional_properties = additional_properties
        return user_response_excluded_inbounds

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> List[str]:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: List[str]) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_response_excluded_inbounds.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="UserResponseInbounds")


@_attrs_define
class UserResponseInbounds:
    """ """

    additional_properties: Dict[str, List[str]] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = prop

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        user_response_inbounds = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = cast(List[str], prop_dict)

            additional_properties[prop_name] = additional_property

        user_response_inbounds.additional_properties = additional_properties
        return user_response_inbounds

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> List[str]:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: List[str]) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_response_inbounds.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="UserResponseProxies")


@_attrs_define
class UserResponseProxies:
    """ """

    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        user_response_proxies = cls()

        user_response_proxies.additional_properties = d
        return user_response_proxies

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_response_proxies.py
govfvck/Marzbot-free
from enum import Enum


class UserStatus(str, Enum):
    ACTIVE = "active"
    DISABLED = "disabled"
    EXPIRED = "expired"
    LIMITED = "limited"

    def __str__(self) -> str:
        return str(self.value)

marzban_client/models/user_status.py
govfvck/Marzbot-free
from enum import Enum


class UserStatusModify(str, Enum):
    ACTIVE = "active"
    DISABLED = "disabled"

    def __str__(self) -> str:
        return str(self.value)

marzban_client/models/user_status_modify.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

if TYPE_CHECKING:
    from ..models.user_template_create_inbounds import UserTemplateCreateInbounds


T = TypeVar("T", bound="UserTemplateCreate")


@_attrs_define
class UserTemplateCreate:
    """
    Example:
        {'name': 'my template 1', 'inbounds': {'vmess': ['VMESS_INBOUND'], 'vless': ['VLESS_INBOUND']}, 'data_limit': 0,
            'expire_duration': 0}

    Attributes:
        name (Union[Unset, None, str]):
        data_limit (Union[Unset, int]): data_limit can be 0 or greater
        expire_duration (Union[Unset, int]): expire_duration can be 0 or greater in seconds
        username_prefix (Union[Unset, str]):
        username_suffix (Union[Unset, str]):
        inbounds (Union[Unset, UserTemplateCreateInbounds]):
    """

    name: Union[Unset, None, str] = UNSET
    data_limit: Union[Unset, int] = UNSET
    expire_duration: Union[Unset, int] = UNSET
    username_prefix: Union[Unset, str] = UNSET
    username_suffix: Union[Unset, str] = UNSET
    inbounds: Union[Unset, "UserTemplateCreateInbounds"] = UNSET
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        name = self.name
        data_limit = self.data_limit
        expire_duration = self.expire_duration
        username_prefix = self.username_prefix
        username_suffix = self.username_suffix
        inbounds: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.inbounds, Unset):
            inbounds = self.inbounds.to_dict()

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})
        if name is not UNSET:
            field_dict["name"] = name
        if data_limit is not UNSET:
            field_dict["data_limit"] = data_limit
        if expire_duration is not UNSET:
            field_dict["expire_duration"] = expire_duration
        if username_prefix is not UNSET:
            field_dict["username_prefix"] = username_prefix
        if username_suffix is not UNSET:
            field_dict["username_suffix"] = username_suffix
        if inbounds is not UNSET:
            field_dict["inbounds"] = inbounds

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.user_template_create_inbounds import UserTemplateCreateInbounds

        d = src_dict.copy()
        name = d.pop("name", UNSET)

        data_limit = d.pop("data_limit", UNSET)

        expire_duration = d.pop("expire_duration", UNSET)

        username_prefix = d.pop("username_prefix", UNSET)

        username_suffix = d.pop("username_suffix", UNSET)

        _inbounds = d.pop("inbounds", UNSET)
        inbounds: Union[Unset, UserTemplateCreateInbounds]
        if isinstance(_inbounds, Unset):
            inbounds = UNSET
        else:
            inbounds = UserTemplateCreateInbounds.from_dict(_inbounds)

        user_template_create = cls(
            name=name,
            data_limit=data_limit,
            expire_duration=expire_duration,
            username_prefix=username_prefix,
            username_suffix=username_suffix,
            inbounds=inbounds,
        )

        user_template_create.additional_properties = d
        return user_template_create

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_template_create.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="UserTemplateCreateInbounds")


@_attrs_define
class UserTemplateCreateInbounds:
    """ """

    additional_properties: Dict[str, List[str]] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = prop

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        user_template_create_inbounds = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = cast(List[str], prop_dict)

            additional_properties[prop_name] = additional_property

        user_template_create_inbounds.additional_properties = additional_properties
        return user_template_create_inbounds

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> List[str]:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: List[str]) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_template_create_inbounds.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

if TYPE_CHECKING:
    from ..models.user_template_modify_inbounds import UserTemplateModifyInbounds


T = TypeVar("T", bound="UserTemplateModify")


@_attrs_define
class UserTemplateModify:
    """
    Example:
        {'name': 'my template 1', 'inbounds': {'vmess': ['VMESS_INBOUND'], 'vless': ['VLESS_INBOUND']}, 'data_limit': 0,
            'expire_duration': 0}

    Attributes:
        name (Union[Unset, None, str]):
        data_limit (Union[Unset, int]): data_limit can be 0 or greater
        expire_duration (Union[Unset, int]): expire_duration can be 0 or greater in seconds
        username_prefix (Union[Unset, str]):
        username_suffix (Union[Unset, str]):
        inbounds (Union[Unset, UserTemplateModifyInbounds]):
    """

    name: Union[Unset, None, str] = UNSET
    data_limit: Union[Unset, int] = UNSET
    expire_duration: Union[Unset, int] = UNSET
    username_prefix: Union[Unset, str] = UNSET
    username_suffix: Union[Unset, str] = UNSET
    inbounds: Union[Unset, "UserTemplateModifyInbounds"] = UNSET
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        name = self.name
        data_limit = self.data_limit
        expire_duration = self.expire_duration
        username_prefix = self.username_prefix
        username_suffix = self.username_suffix
        inbounds: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.inbounds, Unset):
            inbounds = self.inbounds.to_dict()

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})
        if name is not UNSET:
            field_dict["name"] = name
        if data_limit is not UNSET:
            field_dict["data_limit"] = data_limit
        if expire_duration is not UNSET:
            field_dict["expire_duration"] = expire_duration
        if username_prefix is not UNSET:
            field_dict["username_prefix"] = username_prefix
        if username_suffix is not UNSET:
            field_dict["username_suffix"] = username_suffix
        if inbounds is not UNSET:
            field_dict["inbounds"] = inbounds

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.user_template_modify_inbounds import UserTemplateModifyInbounds

        d = src_dict.copy()
        name = d.pop("name", UNSET)

        data_limit = d.pop("data_limit", UNSET)

        expire_duration = d.pop("expire_duration", UNSET)

        username_prefix = d.pop("username_prefix", UNSET)

        username_suffix = d.pop("username_suffix", UNSET)

        _inbounds = d.pop("inbounds", UNSET)
        inbounds: Union[Unset, UserTemplateModifyInbounds]
        if isinstance(_inbounds, Unset):
            inbounds = UNSET
        else:
            inbounds = UserTemplateModifyInbounds.from_dict(_inbounds)

        user_template_modify = cls(
            name=name,
            data_limit=data_limit,
            expire_duration=expire_duration,
            username_prefix=username_prefix,
            username_suffix=username_suffix,
            inbounds=inbounds,
        )

        user_template_modify.additional_properties = d
        return user_template_modify

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_template_modify.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="UserTemplateModifyInbounds")


@_attrs_define
class UserTemplateModifyInbounds:
    """ """

    additional_properties: Dict[str, List[str]] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = prop

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        user_template_modify_inbounds = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = cast(List[str], prop_dict)

            additional_properties[prop_name] = additional_property

        user_template_modify_inbounds.additional_properties = additional_properties
        return user_template_modify_inbounds

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> List[str]:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: List[str]) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_template_modify_inbounds.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

if TYPE_CHECKING:
    from ..models.user_template_response_inbounds import UserTemplateResponseInbounds


T = TypeVar("T", bound="UserTemplateResponse")


@_attrs_define
class UserTemplateResponse:
    """
    Attributes:
        id (int):
        name (Union[Unset, None, str]):
        data_limit (Union[Unset, int]): data_limit can be 0 or greater
        expire_duration (Union[Unset, int]): expire_duration can be 0 or greater in seconds
        username_prefix (Union[Unset, str]):
        username_suffix (Union[Unset, str]):
        inbounds (Union[Unset, UserTemplateResponseInbounds]):
    """

    id: int
    name: Union[Unset, None, str] = UNSET
    data_limit: Union[Unset, int] = UNSET
    expire_duration: Union[Unset, int] = UNSET
    username_prefix: Union[Unset, str] = UNSET
    username_suffix: Union[Unset, str] = UNSET
    inbounds: Union[Unset, "UserTemplateResponseInbounds"] = UNSET
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        id = self.id
        name = self.name
        data_limit = self.data_limit
        expire_duration = self.expire_duration
        username_prefix = self.username_prefix
        username_suffix = self.username_suffix
        inbounds: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.inbounds, Unset):
            inbounds = self.inbounds.to_dict()

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "id": id,
            }
        )
        if name is not UNSET:
            field_dict["name"] = name
        if data_limit is not UNSET:
            field_dict["data_limit"] = data_limit
        if expire_duration is not UNSET:
            field_dict["expire_duration"] = expire_duration
        if username_prefix is not UNSET:
            field_dict["username_prefix"] = username_prefix
        if username_suffix is not UNSET:
            field_dict["username_suffix"] = username_suffix
        if inbounds is not UNSET:
            field_dict["inbounds"] = inbounds

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.user_template_response_inbounds import (
            UserTemplateResponseInbounds,
        )

        d = src_dict.copy()
        id = d.pop("id")

        name = d.pop("name", UNSET)

        data_limit = d.pop("data_limit", UNSET)

        expire_duration = d.pop("expire_duration", UNSET)

        username_prefix = d.pop("username_prefix", UNSET)

        username_suffix = d.pop("username_suffix", UNSET)

        _inbounds = d.pop("inbounds", UNSET)
        inbounds: Union[Unset, UserTemplateResponseInbounds]
        if isinstance(_inbounds, Unset):
            inbounds = UNSET
        else:
            inbounds = UserTemplateResponseInbounds.from_dict(_inbounds)

        user_template_response = cls(
            id=id,
            name=name,
            data_limit=data_limit,
            expire_duration=expire_duration,
            username_prefix=username_prefix,
            username_suffix=username_suffix,
            inbounds=inbounds,
        )

        user_template_response.additional_properties = d
        return user_template_response

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_template_response.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="UserTemplateResponseInbounds")


@_attrs_define
class UserTemplateResponseInbounds:
    """ """

    additional_properties: Dict[str, List[str]] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        field_dict: Dict[str, Any] = {}
        for prop_name, prop in self.additional_properties.items():
            field_dict[prop_name] = prop

        field_dict.update({})

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        user_template_response_inbounds = cls()

        additional_properties = {}
        for prop_name, prop_dict in d.items():
            additional_property = cast(List[str], prop_dict)

            additional_properties[prop_name] = additional_property

        user_template_response_inbounds.additional_properties = additional_properties
        return user_template_response_inbounds

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> List[str]:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: List[str]) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_template_response_inbounds.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

T = TypeVar("T", bound="UserUsageResponse")


@_attrs_define
class UserUsageResponse:
    """
    Attributes:
        node_name (str):
        used_traffic (int):
        node_id (Union[Unset, int]):
    """

    node_name: str
    used_traffic: int
    node_id: Union[Unset, int] = UNSET
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        node_name = self.node_name
        used_traffic = self.used_traffic
        node_id = self.node_id

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "node_name": node_name,
                "used_traffic": used_traffic,
            }
        )
        if node_id is not UNSET:
            field_dict["node_id"] = node_id

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        node_name = d.pop("node_name")

        used_traffic = d.pop("used_traffic")

        node_id = d.pop("node_id", UNSET)

        user_usage_response = cls(
            node_name=node_name,
            used_traffic=used_traffic,
            node_id=node_id,
        )

        user_usage_response.additional_properties = d
        return user_usage_response

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_usage_response.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

if TYPE_CHECKING:
    from ..models.user_usage_response import UserUsageResponse


T = TypeVar("T", bound="UserUsagesResponse")


@_attrs_define
class UserUsagesResponse:
    """
    Attributes:
        username (str):
        usages (List['UserUsageResponse']):
    """

    username: str
    usages: List["UserUsageResponse"]
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        username = self.username
        usages = []
        for usages_item_data in self.usages:
            usages_item = usages_item_data.to_dict()

            usages.append(usages_item)

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "username": username,
                "usages": usages,
            }
        )

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.user_usage_response import UserUsageResponse

        d = src_dict.copy()
        username = d.pop("username")

        usages = []
        _usages = d.pop("usages")
        for usages_item_data in _usages:
            usages_item = UserUsageResponse.from_dict(usages_item_data)

            usages.append(usages_item)

        user_usages_response = cls(
            username=username,
            usages=usages,
        )

        user_usages_response.additional_properties = d
        return user_usages_response

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/user_usages_response.py
govfvck/Marzbot-free
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

if TYPE_CHECKING:
    from ..models.user_response import UserResponse


T = TypeVar("T", bound="UsersResponse")


@_attrs_define
class UsersResponse:
    """
    Attributes:
        users (List['UserResponse']):
        total (int):
    """

    users: List["UserResponse"]
    total: int
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        users = []
        for users_item_data in self.users:
            users_item = users_item_data.to_dict()

            users.append(users_item)

        total = self.total

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "users": users,
                "total": total,
            }
        )

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        from ..models.user_response import UserResponse

        d = src_dict.copy()
        users = []
        _users = d.pop("users")
        for users_item_data in _users:
            users_item = UserResponse.from_dict(users_item_data)

            users.append(users_item)

        total = d.pop("total")

        users_response = cls(
            users=users,
            total=total,
        )

        users_response.additional_properties = d
        return users_response

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/users_response.py
govfvck/Marzbot-free
from typing import Any, Dict, List, Type, TypeVar, Union, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="ValidationError")


@_attrs_define
class ValidationError:
    """
    Attributes:
        loc (List[Union[int, str]]):
        msg (str):
        type (str):
    """

    loc: List[Union[int, str]]
    msg: str
    type: str
    additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        loc = []
        for loc_item_data in self.loc:
            loc_item: Union[int, str]

            loc_item = loc_item_data

            loc.append(loc_item)

        msg = self.msg
        type = self.type

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "loc": loc,
                "msg": msg,
                "type": type,
            }
        )

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        loc = []
        _loc = d.pop("loc")
        for loc_item_data in _loc:

            def _parse_loc_item(data: object) -> Union[int, str]:
                return cast(Union[int, str], data)

            loc_item = _parse_loc_item(loc_item_data)

            loc.append(loc_item)

        msg = d.pop("msg")

        type = d.pop("type")

        validation_error = cls(
            loc=loc,
            msg=msg,
            type=type,
        )

        validation_error.additional_properties = d
        return validation_error

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties

marzban_client/models/validation_error.py
govfvck/Marzbot-free
""" Contains some shared types for properties """
from http import HTTPStatus
from typing import BinaryIO, Generic, Literal, MutableMapping, Optional, Tuple, TypeVar

from attrs import define


class Unset:
    def __bool__(self) -> Literal[False]:
        return False


UNSET: Unset = Unset()

FileJsonType = Tuple[Optional[str], BinaryIO, Optional[str]]


@define
class File:
    """Contains information for file uploads"""

    payload: BinaryIO
    file_name: Optional[str] = None
    mime_type: Optional[str] = None

    def to_tuple(self) -> FileJsonType:
        """Return a tuple representation that httpx will accept for multipart/form-data"""
        return self.file_name, self.payload, self.mime_type


T = TypeVar("T")


@define
class Response(Generic[T]):
    """A response from an endpoint"""

    status_code: HTTPStatus
    content: bytes
    headers: MutableMapping[str, str]
    parsed: Optional[T]


__all__ = ["File", "Response", "FileJsonType"]

marzban_client/types.py
govfvck/Marzbot-free
from tortoise import BaseDBAsyncClient


async def upgrade(db: BaseDBAsyncClient) -> str:
    return """
        CREATE TABLE IF NOT EXISTS `users` (
    `created_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6),
    `updated_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
    `id` BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `username` VARCHAR(200),
    `name` VARCHAR(200),
    `is_blocked` BOOL NOT NULL  DEFAULT 0,
    `super_user` BOOL NOT NULL  DEFAULT 0,
    `force_join_check` DATETIME(6)
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `transactions` (
    `created_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6),
    `updated_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
    `id` BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `type` SMALLINT NOT NULL  COMMENT 'crypto: 1\nby_admin: 2',
    `status` SMALLINT NOT NULL  COMMENT 'waiting: 1\nfailed: 2\ncanceled: 3\npartially_paid: 4\nfinished: 5' DEFAULT 1,
    `finished_at` DATETIME(6),
    `amount` INT NOT NULL,
    `amount_paid` INT,
    `user_id` BIGINT NOT NULL,
    CONSTRAINT `fk_transact_users_6189e5a9` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `byadmin_payments` (
    `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `created_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6),
    `updated_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
    `type` SMALLINT NOT NULL  COMMENT 'crypto: 1\nby_admin: 2' DEFAULT 2,
    `by_admin_id` BIGINT,
    `transaction_id` BIGINT NOT NULL UNIQUE,
    CONSTRAINT `fk_byadmin__users_22c9072e` FOREIGN KEY (`by_admin_id`) REFERENCES `users` (`id`) ON DELETE SET NULL,
    CONSTRAINT `fk_byadmin__transact_617e558f` FOREIGN KEY (`transaction_id`) REFERENCES `transactions` (`id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `crypto_payments` (
    `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `created_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6),
    `updated_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
    `type` SMALLINT NOT NULL  COMMENT 'crypto: 1\nby_admin: 2' DEFAULT 1,
    `usdt_rate` INT NOT NULL,
    `invoice_id` VARCHAR(64) NOT NULL,
    `order_id` VARCHAR(64),
    `price_amount` DOUBLE NOT NULL,
    `price_currency` VARCHAR(20) NOT NULL,
    `nowpm_created_at` DATETIME(6),
    `pay_currency` VARCHAR(32),
    `pay_amount` DOUBLE,
    `order_description` VARCHAR(64),
    `nowpm_updated_at` DATETIME(6),
    `payment_status` SMALLINT NOT NULL  COMMENT 'waiting: 0\nconfirming: 1\nconfirmed: 2\nsending: 3\npartially_paid: 4\nfinished: 5\nfailed: 6\nrefunded: 7\nexpired: 8' DEFAULT 0,
    `outcome_amount` DOUBLE,
    `outcome_currency` VARCHAR(20),
    `purchase_id` VARCHAR(64),
    `pay_address` VARCHAR(128),
    `transaction_id` BIGINT NOT NULL UNIQUE,
    CONSTRAINT `fk_crypto_p_transact_d08038fb` FOREIGN KEY (`transaction_id`) REFERENCES `transactions` (`id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `servers` (
    `created_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6),
    `updated_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
    `id` BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `host` VARCHAR(64) NOT NULL,
    `port` INT,
    `token` VARCHAR(512) NOT NULL,
    `https` BOOL NOT NULL  DEFAULT 0,
    `name` VARCHAR(200),
    `is_enabled` BOOL NOT NULL  DEFAULT 1
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `services` (
    `created_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6),
    `updated_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
    `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `name` VARCHAR(64) NOT NULL,
    `data_limit` BIGINT NOT NULL,
    `expire_duration` INT NOT NULL,
    `inbounds` JSON NOT NULL,
    `flow` VARCHAR(20)   COMMENT 'none: None\nxtls_rprx_vision: xtls-rprx-vision' DEFAULT 'None',
    `price` INT NOT NULL,
    `one_time_only` BOOL NOT NULL  DEFAULT 0,
    `is_test_service` BOOL NOT NULL  DEFAULT 0,
    `purchaseable` BOOL NOT NULL  DEFAULT 0,
    `renewable` BOOL NOT NULL  DEFAULT 0,
    `server_id` BIGINT NOT NULL,
    CONSTRAINT `fk_services_servers_be0c61a1` FOREIGN KEY (`server_id`) REFERENCES `servers` (`id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `proxies` (
    `created_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6),
    `updated_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
    `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `custom_name` VARCHAR(64),
    `username` VARCHAR(32) NOT NULL UNIQUE,
    `cost` INT,
    `status` VARCHAR(12) NOT NULL  COMMENT 'active: active\ndisabled: disabled\nlimited: limited\nexpired: expired' DEFAULT 'active',
    `renewed_at` DATETIME(6),
    `server_id` BIGINT NOT NULL,
    `service_id` INT,
    `user_id` BIGINT NOT NULL,
    CONSTRAINT `fk_proxies_servers_43cfb161` FOREIGN KEY (`server_id`) REFERENCES `servers` (`id`) ON DELETE CASCADE,
    CONSTRAINT `fk_proxies_services_338cef03` FOREIGN KEY (`service_id`) REFERENCES `services` (`id`) ON DELETE SET NULL,
    CONSTRAINT `fk_proxies_users_b8af88b7` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
    KEY `idx_proxies_usernam_c3e1f3` (`username`)
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `invoices` (
    `created_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6),
    `updated_at` DATETIME(6)   DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
    `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `amount` INT NOT NULL,
    `type` SMALLINT NOT NULL  COMMENT 'purchase: 1\nrenew: 2' DEFAULT 1,
    `proxy_id` INT,
    `transaction_id` BIGINT,
    `user_id` BIGINT NOT NULL,
    CONSTRAINT `fk_invoices_proxies_dfa62f0f` FOREIGN KEY (`proxy_id`) REFERENCES `proxies` (`id`) ON DELETE SET NULL,
    CONSTRAINT `fk_invoices_transact_dbab496e` FOREIGN KEY (`transaction_id`) REFERENCES `transactions` (`id`) ON DELETE SET NULL,
    CONSTRAINT `fk_invoices_users_b9efcef2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `aerich` (
    `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `version` VARCHAR(255) NOT NULL,
    `app` VARCHAR(100) NOT NULL,
    `content` JSON NOT NULL
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `user_purchased` (
    `services_id` INT NOT NULL,
    `user_id` BIGINT NOT NULL,
    FOREIGN KEY (`services_id`) REFERENCES `services` (`id`) ON DELETE CASCADE,
    FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;"""


async def downgrade(db: BaseDBAsyncClient) -> str:
    return """
        """

migrations/models/0_20230909004458_init.py
govfvck/Marzbot-free
from datetime import datetime as dt

import httpx

BASE_URL = "https://api.nobitex.ir/market"

DEFAULT_HEADERS = {"content-type": "application/json"}


class CouldNotGetUSDTPrice(Exception):
    pass


class NobitexMarketAPI:
    cached_price: int = None
    last_cached: int = None
    cached_trx_price: int = None
    last_cached_trx: int = None

    @classmethod
    async def _call_api(
        cls,
        method: str,
        json: dict[str, str],
        headers: dict[str, str] = DEFAULT_HEADERS,
    ):
        url = BASE_URL.rstrip("/") + method
        async with httpx.AsyncClient(headers=headers) as client:
            r = await client.post(url, json=json)
            if r.status_code == 200:
                return r.json()

    @classmethod
    async def get_price(cls, use_cache: bool = True) -> int:
        """Fetch latest usdttrc20 price from Nobitex

        the price will be cached for 5 minutes
        """
        if use_cache and cls.cached_price:
            if not cls.last_cached or (
                cls.last_cached - dt.now().timestamp() > 5
            ):  # fine minute cache
                return await cls.get_price(use_cache=False)
            return cls.cached_price

        r = await cls._call_api(
            "/stats", json={"dstCurrency": "rls", "srcCurrency": "usdt"}
        )
        if r:
            usdt_rls = r.get("stats").get("usdt-rls")
            cls.cached_price = int(int(usdt_rls.get("latest")) / 10)
            cls.last_cached = dt.now().timestamp()
            return cls.cached_price
        else:
            raise CouldNotGetUSDTPrice("could not fetch usdt price from nobitex")

    @classmethod
    async def get_trx_price(cls, use_cache: bool = True) -> int:
        """Fetch latest trx price from Nobitex

        the price will be cached for 5 minutes
        """
        if use_cache and cls.cached_trx_price:
            if not cls.last_cached_trx or (
                cls.last_cached_trx - dt.now().timestamp() > 5
            ):  # five minute cache
                return await cls.get_price(use_cache=False)
            return cls.cached_trx_price

        r = await cls._call_api(
            "/stats", json={"dstCurrency": "rls", "srcCurrency": "trx"}
        )
        if r:
            trx_rls = r.get("stats").get("trx-rls")
            cls.cached_trx_price = int(int(trx_rls.get("latest")) / 10)
            cls.last_cached_trx = dt.now().timestamp()
            return cls.cached_trx_price
        else:
            raise CouldNotGetUSDTPrice("could not fetch usdt price from nobitex")

payment_clients/nobitex.py
govfvck/Marzbot-free
from datetime import datetime as dt
from typing import Any, Literal

import httpx
from pydantic import BaseModel

import config

DEFAULT_HEADERS = {
    "x-api-key": config.NP_API_KEY,
}


def get_parsed_query_parameters(data: dict[str, str]) -> str:
    return "&".join(
        [f"{key}={value}" for key, value in data.items() if value is not None]
    )


class NowPaymentsError(Exception):
    pass


class MinAmountResponse(BaseModel):
    currency_from: str
    currency_to: str
    min_amount: float
    fiat_equivalent: float


class PaymentResponse(BaseModel):
    payment_id: int | str
    payment_status: str
    pay_address: str
    price_amount: float
    price_currency: str
    pay_amount: float
    pay_currency: str
    order_id: int
    created_at: dt | None = None
    updated_at: dt | None = None
    purchase_id: str | None = None
    amount_received: float | None = None
    network: str | None = None
    network_percision: int | None = None
    expiration_estimate_date: dt | None = None
    outcome_amount: float | None = None
    outcome_currency: str | None = None


class CreateInvoiceResponse(BaseModel):
    id: str
    order_id: str
    order_description: str | None = None
    price_amount: float
    price_currency: str
    pay_currency: str | None = None
    ipn_callback_url: str
    invoice_url: str
    success_url: str | None = None
    cancel_url: str | None = None
    created_at: dt
    updated_at: dt


class NowPaymentsAPI:
    @classmethod
    async def _call_api(
        cls,
        method: Literal["GET", "POST"],
        path: str,
        headers: dict[str, str] = DEFAULT_HEADERS,
        get_data: dict[str, Any] = None,
        post_data: dict[str, Any] = None,
    ):
        if headers.get("x-api-key") is None:
            raise NowPaymentsError("Nowpayments Api key is not defined!")
        async with httpx.AsyncClient(headers=headers) as client:
            url = config.NP_API_URL + path
            if method == "GET":
                if get_data:
                    url = url + "?" + get_parsed_query_parameters(data=get_data)
                r = await client.get(url=url)
                if r.status_code == 200:
                    return r.json()
            elif method == "POST":
                r = await client.post(url=url, json=post_data)
                print(r.text)
                print(r.status_code)
                if r.status_code in {200, 201}:
                    return r.json()
                else:
                    raise NowPaymentsError(f"{r.text}")

    @classmethod
    async def status(cls) -> bool:
        r = await cls._call_api(
            "GET",
            "/status",
            headers=dict(**DEFAULT_HEADERS),
        )
        if r:
            if r.get("message") == "OK":
                return True
        return False

    @classmethod
    async def create_invoice(
        cls,
        price_amount: float,
        order_id: int,
        order_description: str = "",
        price_currency: str = "usd",
        ipn_callback_url: str = config.NP_IPN_CALLBACK_URL,
        success_url: str = config.NP_SUCCESS_URL,
        cancel_url: str = config.NP_CANCEL_URL,
    ):
        data = {
            "price_amount": price_amount,
            "price_currency": price_currency,
            "order_id": order_id,
            "order_description": order_description,
            "ipn_callback_url": ipn_callback_url,
            "success_url": success_url,
            "cancel_url": cancel_url,
            "is_fee_paid_by_user": False if price_amount < 2.7 else True,
        }
        r = await cls._call_api(
            "POST",
            "/invoice",
            headers=dict(**DEFAULT_HEADERS, **{"Content-Type": "application/json"}),
            post_data=data,
        )
        return CreateInvoiceResponse(**r)

    @classmethod
    async def create_payment(
        cls,
        price_amount: float,
        pay_currency: str,
        order_id: int,
        price_currency: str = "usd",
        ipn_callback_url: str = config.NP_IPN_CALLBACK_URL,
    ) -> PaymentResponse:
        data = {
            "price_amount": price_amount + (price_amount * 0.005),
            "pay_currency": pay_currency,
            "price_currency": price_currency,
            "ipn_callback_url": ipn_callback_url,
            "order_id": order_id,
        }
        r = await cls._call_api(
            "POST",
            "/payment",
            headers=dict(**DEFAULT_HEADERS, **{"Content-Type": "application/json"}),
            post_data=data,
        )
        return PaymentResponse(**r)

    @classmethod
    async def get_payment_status(cls, payment_id: str) -> PaymentResponse:
        r = await cls._call_api("GET", f"/payment/{payment_id}")
        return PaymentResponse(**r)

    @classmethod
    async def get_minimum_amount(
        cls, currency_from: str, currency_to: str, fiat_equivalent: str = "usd"
    ) -> MinAmountResponse:
        r = await cls._call_api(
            "GET",
            "/min-amount",
            get_data={
                "currency_from": currency_from,
                "currency_to": currency_to,
                "fiat_equivalent": fiat_equivalent,
            },
        )
        return MinAmountResponse(**r)

payment_clients/nowpayments.py
govfvck/Marzbot-free