forked from FOSS/AutoShop-Djimbo
refactor: remove Alembic migrations and Discord integration
This commit is contained in:
@@ -27,31 +27,12 @@ YOOMONEY_CLIENT_ID=
|
|||||||
|
|
||||||
Конфигурация читается только из `.env` или переменных окружения.
|
Конфигурация читается только из `.env` или переменных окружения.
|
||||||
|
|
||||||
5. Примени миграции:
|
5. Запусти бота:
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 migrate.py up
|
|
||||||
```
|
|
||||||
|
|
||||||
6. Запусти бота:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 main.py
|
python3 main.py
|
||||||
```
|
```
|
||||||
|
|
||||||
## Миграции
|
|
||||||
|
|
||||||
Основные команды:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 migrate.py status
|
|
||||||
python3 migrate.py up
|
|
||||||
python3 migrate.py down
|
|
||||||
python3 migrate.py auto "change description"
|
|
||||||
```
|
|
||||||
|
|
||||||
Схема БД теперь живет в `migrations/`, модели — в `tgbot/database/db_*.py`.
|
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
-188
@@ -1,188 +0,0 @@
|
|||||||
# - *- coding: utf- 8 - *-
|
|
||||||
import argparse
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from alembic import command
|
|
||||||
from alembic.config import Config
|
|
||||||
|
|
||||||
HELP_TEXT = """
|
|
||||||
Миграции базы данных
|
|
||||||
|
|
||||||
Безопасное правило:
|
|
||||||
python migrate.py только показывает эту справку
|
|
||||||
действия с БД выполняются только при явной команде
|
|
||||||
|
|
||||||
Основные команды:
|
|
||||||
python migrate.py help показать эту справку
|
|
||||||
python migrate.py up применить все миграции до head
|
|
||||||
python migrate.py down откатить последнюю миграцию
|
|
||||||
python migrate.py new "add users" создать пустую миграцию
|
|
||||||
python migrate.py auto "add users" создать миграцию по SQLAlchemy-моделям
|
|
||||||
python migrate.py status показать текущую версию и последние версии
|
|
||||||
|
|
||||||
Короткие алиасы:
|
|
||||||
up -> upgrade
|
|
||||||
down -> downgrade
|
|
||||||
new -> revision
|
|
||||||
auto -> revision --autogenerate
|
|
||||||
autogen -> auto
|
|
||||||
cur -> current
|
|
||||||
hist -> history
|
|
||||||
st -> status
|
|
||||||
""".strip()
|
|
||||||
|
|
||||||
|
|
||||||
# Сбор CLI-парсера миграций
|
|
||||||
def build_parser() -> argparse.ArgumentParser:
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="Удобный CLI для Alembic-миграций",
|
|
||||||
formatter_class=argparse.RawTextHelpFormatter,
|
|
||||||
)
|
|
||||||
subparsers = parser.add_subparsers(dest="command")
|
|
||||||
|
|
||||||
help_parser = subparsers.add_parser("help", aliases=["h"], help="Показать понятную справку")
|
|
||||||
help_parser.set_defaults(action=show_help)
|
|
||||||
|
|
||||||
upgrade_parser = subparsers.add_parser("upgrade", aliases=["up"], help="Применить миграции")
|
|
||||||
upgrade_parser.add_argument("revision", nargs="?", default="head", help="Версия миграции, по умолчанию head")
|
|
||||||
upgrade_parser.set_defaults(action=run_upgrade)
|
|
||||||
|
|
||||||
downgrade_parser = subparsers.add_parser("downgrade", aliases=["down"], help="Откатить миграции")
|
|
||||||
downgrade_parser.add_argument("revision", nargs="?", default="-1", help="Версия отката, по умолчанию -1")
|
|
||||||
downgrade_parser.set_defaults(action=run_downgrade)
|
|
||||||
|
|
||||||
revision_parser = subparsers.add_parser("revision", aliases=["new"], help="Создать пустую миграцию")
|
|
||||||
revision_parser.add_argument("message", nargs="?", help="Название миграции")
|
|
||||||
revision_parser.add_argument("-m", "--message-option", dest="message_option", help="Название миграции")
|
|
||||||
revision_parser.add_argument("--autogenerate", "-a", action="store_true", help="Собрать изменения из моделей")
|
|
||||||
revision_parser.set_defaults(action=run_revision)
|
|
||||||
|
|
||||||
auto_parser = subparsers.add_parser("auto", aliases=["autogen"], help="Создать миграцию по моделям")
|
|
||||||
auto_parser.add_argument("message", nargs="?", help="Название миграции")
|
|
||||||
auto_parser.add_argument("-m", "--message-option", dest="message_option", help="Название миграции")
|
|
||||||
auto_parser.set_defaults(action=run_auto_revision)
|
|
||||||
|
|
||||||
current_parser = subparsers.add_parser("current", aliases=["cur"], help="Показать текущую версию БД")
|
|
||||||
current_parser.set_defaults(action=run_current)
|
|
||||||
|
|
||||||
history_parser = subparsers.add_parser("history", aliases=["hist"], help="Показать историю миграций")
|
|
||||||
history_parser.set_defaults(action=run_history)
|
|
||||||
|
|
||||||
heads_parser = subparsers.add_parser("heads", help="Показать последние версии веток")
|
|
||||||
heads_parser.set_defaults(action=run_heads)
|
|
||||||
|
|
||||||
status_parser = subparsers.add_parser("status", aliases=["st"], help="Показать текущую версию и heads")
|
|
||||||
status_parser.set_defaults(action=run_status)
|
|
||||||
|
|
||||||
return parser
|
|
||||||
|
|
||||||
|
|
||||||
# Просмотр справки по миграциям
|
|
||||||
def show_help(_config: Optional[Config], _args: argparse.Namespace) -> None:
|
|
||||||
print(HELP_TEXT)
|
|
||||||
|
|
||||||
|
|
||||||
# Применение миграций до версии
|
|
||||||
def run_upgrade(config: Config, args: argparse.Namespace) -> None:
|
|
||||||
print(f"Применяю миграции до версии: {args.revision}")
|
|
||||||
command.upgrade(config, args.revision)
|
|
||||||
print("Готово")
|
|
||||||
|
|
||||||
|
|
||||||
# Откат миграции до версии
|
|
||||||
def run_downgrade(config: Config, args: argparse.Namespace) -> None:
|
|
||||||
print(f"Откатываю миграции до версии: {args.revision}")
|
|
||||||
command.downgrade(config, args.revision)
|
|
||||||
print("Готово")
|
|
||||||
|
|
||||||
|
|
||||||
# Создание пустой миграции
|
|
||||||
def run_revision(config: Config, args: argparse.Namespace) -> None:
|
|
||||||
message = get_revision_message(args)
|
|
||||||
print(f"Создаю миграцию: {message}")
|
|
||||||
config.attributes["autogenerate_empty"] = False
|
|
||||||
command.revision(config, message=message, autogenerate=args.autogenerate)
|
|
||||||
if config.attributes.get("autogenerate_empty"):
|
|
||||||
print("Изменений в моделях не найдено, файл миграции не создан")
|
|
||||||
return
|
|
||||||
|
|
||||||
print("Готово")
|
|
||||||
|
|
||||||
|
|
||||||
# Создание миграции по моделям
|
|
||||||
def run_auto_revision(config: Config, args: argparse.Namespace) -> None:
|
|
||||||
message = get_revision_message(args)
|
|
||||||
print(f"Создаю миграцию по моделям: {message}")
|
|
||||||
config.attributes["autogenerate_empty"] = False
|
|
||||||
command.revision(config, message=message, autogenerate=True)
|
|
||||||
if config.attributes.get("autogenerate_empty"):
|
|
||||||
print("Изменений в моделях не найдено, файл миграции не создан")
|
|
||||||
return
|
|
||||||
|
|
||||||
print("Готово")
|
|
||||||
|
|
||||||
|
|
||||||
# Просмотр текущей версии БД
|
|
||||||
def run_current(config: Config, _args: argparse.Namespace) -> None:
|
|
||||||
print("Текущая версия БД:")
|
|
||||||
command.current(config)
|
|
||||||
|
|
||||||
|
|
||||||
# Просмотр истории миграций
|
|
||||||
def run_history(config: Config, _args: argparse.Namespace) -> None:
|
|
||||||
print("История миграций:")
|
|
||||||
command.history(config)
|
|
||||||
|
|
||||||
|
|
||||||
# Просмотр heads миграций
|
|
||||||
def run_heads(config: Config, _args: argparse.Namespace) -> None:
|
|
||||||
print("Последние версии миграций:")
|
|
||||||
command.heads(config)
|
|
||||||
|
|
||||||
|
|
||||||
# Просмотр текущей версии и heads
|
|
||||||
def run_status(config: Config, args: argparse.Namespace) -> None:
|
|
||||||
run_current(config, args)
|
|
||||||
print()
|
|
||||||
run_heads(config, args)
|
|
||||||
|
|
||||||
|
|
||||||
# Получение названия миграции
|
|
||||||
def get_revision_message(args: argparse.Namespace) -> str:
|
|
||||||
message: Optional[str] = args.message_option or args.message
|
|
||||||
|
|
||||||
if not message:
|
|
||||||
raise SystemExit("Укажи название миграции. Пример: python migrate.py auto \"add users\"")
|
|
||||||
|
|
||||||
return message
|
|
||||||
|
|
||||||
|
|
||||||
# Получение Alembic-конфига
|
|
||||||
def get_config() -> Config:
|
|
||||||
from tgbot.database.migration_runner import get_alembic_config
|
|
||||||
|
|
||||||
return get_alembic_config()
|
|
||||||
|
|
||||||
|
|
||||||
# Запуск CLI миграций
|
|
||||||
def main() -> None:
|
|
||||||
parser = build_parser()
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if args.command is None:
|
|
||||||
show_help(None, args)
|
|
||||||
return
|
|
||||||
|
|
||||||
if args.action == show_help:
|
|
||||||
show_help(None, args)
|
|
||||||
return
|
|
||||||
|
|
||||||
if args.action in (run_revision, run_auto_revision):
|
|
||||||
get_revision_message(args)
|
|
||||||
|
|
||||||
config = get_config()
|
|
||||||
args.action(config, args)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
# - *- coding: utf- 8 - *-
|
|
||||||
import asyncio
|
|
||||||
from logging.config import fileConfig
|
|
||||||
from typing import Any, List, Optional
|
|
||||||
|
|
||||||
from alembic import context
|
|
||||||
from alembic.operations import ops
|
|
||||||
from sqlalchemy import pool, text
|
|
||||||
from sqlalchemy.engine import Connection
|
|
||||||
from sqlalchemy.schema import DefaultClause
|
|
||||||
from sqlalchemy.ext.asyncio import async_engine_from_config
|
|
||||||
|
|
||||||
from tgbot.database.core import Base
|
|
||||||
|
|
||||||
import tgbot.database # noqa: F401
|
|
||||||
|
|
||||||
config = context.config
|
|
||||||
|
|
||||||
if config.config_file_name is not None:
|
|
||||||
fileConfig(config.config_file_name)
|
|
||||||
|
|
||||||
target_metadata = Base.metadata
|
|
||||||
INDEX_DIFF_NOISE = {"ix_storage_payments_id", "ix_storage_settings_id"}
|
|
||||||
|
|
||||||
|
|
||||||
# Отбрасывание SQLite-шума из автогенерации
|
|
||||||
def _filter_autogenerated_ops(container: Any) -> None:
|
|
||||||
filtered_ops = []
|
|
||||||
|
|
||||||
for operation in container.ops:
|
|
||||||
if isinstance(operation, ops.AlterColumnOp):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if _is_index_noise(operation):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(operation, ops.ModifyTableOps):
|
|
||||||
_filter_autogenerated_ops(operation)
|
|
||||||
|
|
||||||
if operation.ops:
|
|
||||||
filtered_ops.append(operation)
|
|
||||||
|
|
||||||
continue
|
|
||||||
|
|
||||||
filtered_ops.append(operation)
|
|
||||||
|
|
||||||
container.ops = filtered_ops
|
|
||||||
|
|
||||||
|
|
||||||
# Подготовка новых колонок к безопасному SQLite ADD COLUMN
|
|
||||||
def _prepare_sqlite_add_columns(container: Any) -> None:
|
|
||||||
for operation in container.ops:
|
|
||||||
if isinstance(operation, ops.AddColumnOp):
|
|
||||||
_apply_server_default(operation.column)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(operation, ops.ModifyTableOps):
|
|
||||||
_prepare_sqlite_add_columns(operation)
|
|
||||||
|
|
||||||
|
|
||||||
# Перенос default модели в server_default миграции
|
|
||||||
def _apply_server_default(column: Any) -> None:
|
|
||||||
if column.nullable or column.server_default is not None or column.default is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
default_value = _get_simple_default(column.default.arg)
|
|
||||||
|
|
||||||
if default_value is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
column.server_default = DefaultClause(text(default_value))
|
|
||||||
|
|
||||||
|
|
||||||
# Получение SQL-литерала для простых default-значений
|
|
||||||
def _get_simple_default(value: Any) -> Optional[str]:
|
|
||||||
if callable(value):
|
|
||||||
return None
|
|
||||||
|
|
||||||
if isinstance(value, bool):
|
|
||||||
return "1" if value else "0"
|
|
||||||
|
|
||||||
if isinstance(value, (int, float)):
|
|
||||||
return str(value)
|
|
||||||
|
|
||||||
if isinstance(value, str):
|
|
||||||
return repr(value)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# Игнорирование индексов, которые SQLite отражает иначе
|
|
||||||
def _is_index_noise(operation: Any) -> bool:
|
|
||||||
if not isinstance(operation, (ops.CreateIndexOp, ops.DropIndexOp)):
|
|
||||||
return False
|
|
||||||
|
|
||||||
return getattr(operation, "index_name", "") in INDEX_DIFF_NOISE
|
|
||||||
|
|
||||||
|
|
||||||
# Ограничение сравнения SQLite только реальными добавлениями/удалениями
|
|
||||||
def _include_object(object_: Any, name: str, type_: str, reflected: bool, compare_to: Any) -> bool:
|
|
||||||
if type_ == "column" and compare_to is not None:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if type_ == "index" and name in INDEX_DIFF_NOISE:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
# Очистка автосозданной миграции перед записью
|
|
||||||
def _process_revision_directives(_context: Any, _revision: Any, directives: List[Any]) -> None:
|
|
||||||
if not directives:
|
|
||||||
return
|
|
||||||
|
|
||||||
script = directives[0]
|
|
||||||
_prepare_sqlite_add_columns(script.upgrade_ops)
|
|
||||||
_filter_autogenerated_ops(script.upgrade_ops)
|
|
||||||
_filter_autogenerated_ops(script.downgrade_ops)
|
|
||||||
|
|
||||||
if not script.upgrade_ops.ops and not script.downgrade_ops.ops:
|
|
||||||
config.attributes["autogenerate_empty"] = True
|
|
||||||
directives.clear()
|
|
||||||
|
|
||||||
|
|
||||||
# Запуск миграций без подключения
|
|
||||||
def run_migrations_offline() -> None:
|
|
||||||
url = config.get_main_option("sqlalchemy.url")
|
|
||||||
|
|
||||||
context.configure(
|
|
||||||
url=url,
|
|
||||||
target_metadata=target_metadata,
|
|
||||||
literal_binds=True,
|
|
||||||
dialect_opts={"paramstyle": "named"},
|
|
||||||
render_as_batch=True,
|
|
||||||
compare_type=False,
|
|
||||||
include_object=_include_object,
|
|
||||||
process_revision_directives=_process_revision_directives,
|
|
||||||
)
|
|
||||||
|
|
||||||
with context.begin_transaction():
|
|
||||||
context.run_migrations()
|
|
||||||
|
|
||||||
|
|
||||||
# Запуск миграций на соединении
|
|
||||||
def do_run_migrations(connection: Connection) -> None:
|
|
||||||
context.configure(
|
|
||||||
connection=connection,
|
|
||||||
target_metadata=target_metadata,
|
|
||||||
render_as_batch=True,
|
|
||||||
compare_type=False,
|
|
||||||
include_object=_include_object,
|
|
||||||
process_revision_directives=_process_revision_directives,
|
|
||||||
)
|
|
||||||
|
|
||||||
with context.begin_transaction():
|
|
||||||
context.run_migrations()
|
|
||||||
|
|
||||||
|
|
||||||
# Запуск миграций через async-engine
|
|
||||||
async def run_async_migrations() -> None:
|
|
||||||
connectable = async_engine_from_config(
|
|
||||||
config.get_section(config.config_ini_section, {}),
|
|
||||||
poolclass=pool.NullPool,
|
|
||||||
)
|
|
||||||
connection = connectable.connect()
|
|
||||||
|
|
||||||
try:
|
|
||||||
await connection.start()
|
|
||||||
await connection.run_sync(do_run_migrations)
|
|
||||||
finally:
|
|
||||||
await connection.close()
|
|
||||||
|
|
||||||
await connectable.dispose()
|
|
||||||
|
|
||||||
|
|
||||||
if context.is_offline_mode():
|
|
||||||
run_migrations_offline()
|
|
||||||
else:
|
|
||||||
external_connection = config.attributes.get("connection")
|
|
||||||
|
|
||||||
if external_connection is not None:
|
|
||||||
do_run_migrations(external_connection)
|
|
||||||
else:
|
|
||||||
asyncio.run(run_async_migrations())
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
"""${message}
|
|
||||||
|
|
||||||
Revision ID: ${up_revision}
|
|
||||||
Revises: ${down_revision | comma,n}
|
|
||||||
Create Date: ${create_date}
|
|
||||||
"""
|
|
||||||
from typing import Sequence, Union
|
|
||||||
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
${imports if imports else ""}
|
|
||||||
|
|
||||||
revision: str = ${repr(up_revision)}
|
|
||||||
down_revision: Union[str, None] = ${repr(down_revision)}
|
|
||||||
branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
|
|
||||||
depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade() -> None:
|
|
||||||
${upgrades if upgrades else "pass"}
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade() -> None:
|
|
||||||
${downgrades if downgrades else "pass"}
|
|
||||||
@@ -1,515 +0,0 @@
|
|||||||
"""Начальная схема Телеграм-магазина
|
|
||||||
|
|
||||||
Revision ID: 0001_shop_schema
|
|
||||||
Revises:
|
|
||||||
Create Date: 2026-05-29 00:00:00
|
|
||||||
"""
|
|
||||||
from typing import Sequence, Union
|
|
||||||
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
revision: str = "0001_shop_schema"
|
|
||||||
down_revision: Union[str, None] = None
|
|
||||||
branch_labels: Union[str, Sequence[str], None] = None
|
|
||||||
depends_on: Union[str, Sequence[str], None] = None
|
|
||||||
|
|
||||||
|
|
||||||
# Проверка наличия таблицы
|
|
||||||
def _table_exists(table_name: str) -> bool:
|
|
||||||
bind = op.get_bind()
|
|
||||||
result = bind.execute(
|
|
||||||
sa.text(
|
|
||||||
"""
|
|
||||||
SELECT name
|
|
||||||
FROM sqlite_master
|
|
||||||
WHERE type = 'table'
|
|
||||||
AND name = :table_name
|
|
||||||
"""
|
|
||||||
),
|
|
||||||
{"table_name": table_name},
|
|
||||||
)
|
|
||||||
|
|
||||||
return result.scalar_one_or_none() is not None
|
|
||||||
|
|
||||||
|
|
||||||
# Проверка наличия колонки
|
|
||||||
def _column_exists(table_name: str, column_name: str) -> bool:
|
|
||||||
bind = op.get_bind()
|
|
||||||
result = bind.execute(sa.text(f"PRAGMA table_info({table_name})"))
|
|
||||||
|
|
||||||
return column_name in [row.name for row in result]
|
|
||||||
|
|
||||||
|
|
||||||
# Добавление колонки, если ее нет
|
|
||||||
def _add_column(table_name: str, column_name: str, column_sql: str) -> None:
|
|
||||||
if not _column_exists(table_name, column_name):
|
|
||||||
op.execute(sa.text(f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_sql}"))
|
|
||||||
|
|
||||||
|
|
||||||
# Создание индекса, если его нет
|
|
||||||
def _create_index(index_name: str, table_name: str, columns: str, *, unique: bool = False) -> None:
|
|
||||||
unique_sql = "UNIQUE " if unique else ""
|
|
||||||
op.execute(sa.text(f"CREATE {unique_sql}INDEX IF NOT EXISTS {index_name} ON {table_name} ({columns})"))
|
|
||||||
|
|
||||||
|
|
||||||
# Нормализация текстовых bool-значений
|
|
||||||
def _normalize_boolean_text(table_name: str, column_name: str, default_value: str) -> None:
|
|
||||||
bind = op.get_bind()
|
|
||||||
bind.execute(
|
|
||||||
sa.text(
|
|
||||||
f"""
|
|
||||||
UPDATE {table_name}
|
|
||||||
SET {column_name} = CASE LOWER(CAST(COALESCE({column_name}, :default_value) AS TEXT))
|
|
||||||
WHEN '1' THEN 'True'
|
|
||||||
WHEN 'true' THEN 'True'
|
|
||||||
WHEN 'yes' THEN 'True'
|
|
||||||
WHEN 'on' THEN 'True'
|
|
||||||
WHEN 'да' THEN 'True'
|
|
||||||
WHEN '0' THEN 'False'
|
|
||||||
WHEN 'false' THEN 'False'
|
|
||||||
WHEN 'no' THEN 'False'
|
|
||||||
WHEN 'off' THEN 'False'
|
|
||||||
WHEN 'нет' THEN 'False'
|
|
||||||
ELSE :default_value
|
|
||||||
END
|
|
||||||
"""
|
|
||||||
),
|
|
||||||
{"default_value": default_value},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Сбор SQL для переноса текстовой колонки
|
|
||||||
def _copy_expr(table_name: str, column_name: str, default_value: str) -> str:
|
|
||||||
if _column_exists(table_name, column_name):
|
|
||||||
return f"COALESCE({column_name}, '{default_value}')"
|
|
||||||
|
|
||||||
return f"'{default_value}'"
|
|
||||||
|
|
||||||
|
|
||||||
# Сбор SQL для переноса числовой колонки
|
|
||||||
def _copy_int_expr(table_name: str, column_name: str, default_value: int = 0) -> str:
|
|
||||||
if _column_exists(table_name, column_name):
|
|
||||||
return f"COALESCE({column_name}, {default_value})"
|
|
||||||
|
|
||||||
return str(default_value)
|
|
||||||
|
|
||||||
|
|
||||||
# Создание или правка таблицы пользователей
|
|
||||||
def _ensure_users() -> None:
|
|
||||||
bind = op.get_bind()
|
|
||||||
|
|
||||||
if not _table_exists("storage_users"):
|
|
||||||
op.create_table(
|
|
||||||
"storage_users",
|
|
||||||
sa.Column("increment", sa.Integer(), autoincrement=True, nullable=False),
|
|
||||||
sa.Column("user_id", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("user_login", sa.String(length=255), nullable=False, server_default=""),
|
|
||||||
sa.Column("user_name", sa.String(length=255), nullable=False, server_default=""),
|
|
||||||
sa.Column("user_surname", sa.String(length=255), nullable=False, server_default=""),
|
|
||||||
sa.Column("user_fullname", sa.String(length=511), nullable=False, server_default=""),
|
|
||||||
sa.Column("user_balance", sa.Float(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("user_refill", sa.Float(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("user_give", sa.Float(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("user_unix", sa.Integer(), nullable=False),
|
|
||||||
sa.PrimaryKeyConstraint("increment"),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
_add_column("storage_users", "user_login", "TEXT NOT NULL DEFAULT ''")
|
|
||||||
_add_column("storage_users", "user_name", "TEXT NOT NULL DEFAULT ''")
|
|
||||||
_add_column("storage_users", "user_surname", "TEXT NOT NULL DEFAULT ''")
|
|
||||||
_add_column("storage_users", "user_fullname", "TEXT NOT NULL DEFAULT ''")
|
|
||||||
_add_column("storage_users", "user_balance", "REAL NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_users", "user_refill", "REAL NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_users", "user_give", "REAL NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_users", "user_unix", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
bind.execute(sa.text("UPDATE storage_users SET user_login = COALESCE(user_login, '')"))
|
|
||||||
bind.execute(sa.text("UPDATE storage_users SET user_name = COALESCE(user_name, '')"))
|
|
||||||
bind.execute(sa.text("UPDATE storage_users SET user_surname = COALESCE(user_surname, '')"))
|
|
||||||
bind.execute(
|
|
||||||
sa.text(
|
|
||||||
"""
|
|
||||||
UPDATE storage_users
|
|
||||||
SET user_fullname = CASE
|
|
||||||
WHEN user_fullname IS NULL OR user_fullname = '' THEN TRIM(user_name || ' ' || user_surname)
|
|
||||||
ELSE user_fullname
|
|
||||||
END
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
bind.execute(sa.text("UPDATE storage_users SET user_balance = COALESCE(user_balance, 0)"))
|
|
||||||
bind.execute(sa.text("UPDATE storage_users SET user_refill = COALESCE(user_refill, 0)"))
|
|
||||||
bind.execute(sa.text("UPDATE storage_users SET user_give = COALESCE(user_give, 0)"))
|
|
||||||
bind.execute(sa.text("UPDATE storage_users SET user_unix = COALESCE(user_unix, 0)"))
|
|
||||||
bind.execute(sa.text("DELETE FROM storage_users WHERE user_id IS NULL"))
|
|
||||||
bind.execute(
|
|
||||||
sa.text(
|
|
||||||
"""
|
|
||||||
DELETE
|
|
||||||
FROM storage_users
|
|
||||||
WHERE user_id IS NOT NULL
|
|
||||||
AND rowid NOT IN (
|
|
||||||
SELECT MAX(rowid)
|
|
||||||
FROM storage_users
|
|
||||||
WHERE user_id IS NOT NULL
|
|
||||||
GROUP BY user_id
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
_create_index("ix_storage_users_user_id", "storage_users", "user_id", unique=True)
|
|
||||||
|
|
||||||
|
|
||||||
# Создание или правка таблицы настроек
|
|
||||||
def _ensure_settings() -> None:
|
|
||||||
bind = op.get_bind()
|
|
||||||
|
|
||||||
if not _table_exists("storage_settings"):
|
|
||||||
op.create_table(
|
|
||||||
"storage_settings",
|
|
||||||
sa.Column("id", sa.Integer(), nullable=False),
|
|
||||||
sa.Column("status_work", sa.String(length=16), nullable=False, server_default="True"),
|
|
||||||
sa.Column("status_refill", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.Column("status_buy", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.Column("notification_refill", sa.String(length=16), nullable=False, server_default="True"),
|
|
||||||
sa.Column("notification_buy", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.Column("misc_faq", sa.String(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("misc_support", sa.String(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("misc_bot", sa.String(length=255), nullable=False, server_default="None"),
|
|
||||||
sa.Column("misc_hosting_text", sa.String(length=64), nullable=False, server_default="telegraph"),
|
|
||||||
sa.Column("misc_token_telegraph", sa.String(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("misc_discord_webhook_url", sa.String(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("misc_discord_webhook_name", sa.String(length=255), nullable=False, server_default="None"),
|
|
||||||
sa.Column("misc_hide_category", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.Column("misc_hide_position", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.Column("misc_profit_day", sa.Integer(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("misc_profit_week", sa.Integer(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("misc_profit_month", sa.Integer(), nullable=False, server_default="0"),
|
|
||||||
sa.PrimaryKeyConstraint("id"),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
bind.execute(sa.text("DROP TABLE IF EXISTS storage_settings_new"))
|
|
||||||
op.create_table(
|
|
||||||
"storage_settings_new",
|
|
||||||
sa.Column("id", sa.Integer(), nullable=False),
|
|
||||||
sa.Column("status_work", sa.String(length=16), nullable=False, server_default="True"),
|
|
||||||
sa.Column("status_refill", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.Column("status_buy", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.Column("notification_refill", sa.String(length=16), nullable=False, server_default="True"),
|
|
||||||
sa.Column("notification_buy", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.Column("misc_faq", sa.String(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("misc_support", sa.String(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("misc_bot", sa.String(length=255), nullable=False, server_default="None"),
|
|
||||||
sa.Column("misc_hosting_text", sa.String(length=64), nullable=False, server_default="telegraph"),
|
|
||||||
sa.Column("misc_token_telegraph", sa.String(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("misc_discord_webhook_url", sa.String(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("misc_discord_webhook_name", sa.String(length=255), nullable=False, server_default="None"),
|
|
||||||
sa.Column("misc_hide_category", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.Column("misc_hide_position", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.Column("misc_profit_day", sa.Integer(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("misc_profit_week", sa.Integer(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("misc_profit_month", sa.Integer(), nullable=False, server_default="0"),
|
|
||||||
sa.PrimaryKeyConstraint("id"),
|
|
||||||
)
|
|
||||||
bind.execute(
|
|
||||||
sa.text(
|
|
||||||
f"""
|
|
||||||
INSERT INTO storage_settings_new (
|
|
||||||
id,
|
|
||||||
status_work,
|
|
||||||
status_refill,
|
|
||||||
status_buy,
|
|
||||||
notification_refill,
|
|
||||||
notification_buy,
|
|
||||||
misc_faq,
|
|
||||||
misc_support,
|
|
||||||
misc_bot,
|
|
||||||
misc_hosting_text,
|
|
||||||
misc_token_telegraph,
|
|
||||||
misc_discord_webhook_url,
|
|
||||||
misc_discord_webhook_name,
|
|
||||||
misc_hide_category,
|
|
||||||
misc_hide_position,
|
|
||||||
misc_profit_day,
|
|
||||||
misc_profit_week,
|
|
||||||
misc_profit_month
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
1,
|
|
||||||
{_copy_expr("storage_settings", "status_work", "True")},
|
|
||||||
{_copy_expr("storage_settings", "status_refill", "False")},
|
|
||||||
{_copy_expr("storage_settings", "status_buy", "False")},
|
|
||||||
{_copy_expr("storage_settings", "notification_refill", "True")},
|
|
||||||
{_copy_expr("storage_settings", "notification_buy", "False")},
|
|
||||||
{_copy_expr("storage_settings", "misc_faq", "None")},
|
|
||||||
{_copy_expr("storage_settings", "misc_support", "None")},
|
|
||||||
{_copy_expr("storage_settings", "misc_bot", "None")},
|
|
||||||
{_copy_expr("storage_settings", "misc_hosting_text", "telegraph")},
|
|
||||||
{_copy_expr("storage_settings", "misc_token_telegraph", "None")},
|
|
||||||
{_copy_expr("storage_settings", "misc_discord_webhook_url", "None")},
|
|
||||||
{_copy_expr("storage_settings", "misc_discord_webhook_name", "None")},
|
|
||||||
{_copy_expr("storage_settings", "misc_hide_category", "False")},
|
|
||||||
{_copy_expr("storage_settings", "misc_hide_position", "False")},
|
|
||||||
{_copy_int_expr("storage_settings", "misc_profit_day")},
|
|
||||||
{_copy_int_expr("storage_settings", "misc_profit_week")},
|
|
||||||
{_copy_int_expr("storage_settings", "misc_profit_month")}
|
|
||||||
FROM storage_settings
|
|
||||||
LIMIT 1
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
bind.execute(sa.text("DROP TABLE storage_settings"))
|
|
||||||
bind.execute(sa.text("ALTER TABLE storage_settings_new RENAME TO storage_settings"))
|
|
||||||
|
|
||||||
bind.execute(
|
|
||||||
sa.text(
|
|
||||||
"""
|
|
||||||
INSERT INTO storage_settings (id)
|
|
||||||
SELECT 1
|
|
||||||
WHERE NOT EXISTS (SELECT 1 FROM storage_settings WHERE id = 1)
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
for column, default in (
|
|
||||||
("status_work", "True"),
|
|
||||||
("status_refill", "False"),
|
|
||||||
("status_buy", "False"),
|
|
||||||
("notification_refill", "True"),
|
|
||||||
("notification_buy", "False"),
|
|
||||||
("misc_hide_category", "False"),
|
|
||||||
("misc_hide_position", "False"),
|
|
||||||
):
|
|
||||||
_normalize_boolean_text("storage_settings", column, default)
|
|
||||||
|
|
||||||
_create_index("ix_storage_settings_id", "storage_settings", "id", unique=True)
|
|
||||||
|
|
||||||
|
|
||||||
# Создание или правка таблицы платежей
|
|
||||||
def _ensure_payments() -> None:
|
|
||||||
bind = op.get_bind()
|
|
||||||
|
|
||||||
if not _table_exists("storage_payments"):
|
|
||||||
op.create_table(
|
|
||||||
"storage_payments",
|
|
||||||
sa.Column("id", sa.Integer(), nullable=False),
|
|
||||||
sa.Column("cryptobot_token", sa.String(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("yoomoney_token", sa.String(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("status_cryptobot", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.Column("status_yoomoney", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.PrimaryKeyConstraint("id"),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
bind.execute(sa.text("DROP TABLE IF EXISTS storage_payments_new"))
|
|
||||||
op.create_table(
|
|
||||||
"storage_payments_new",
|
|
||||||
sa.Column("id", sa.Integer(), nullable=False),
|
|
||||||
sa.Column("cryptobot_token", sa.String(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("yoomoney_token", sa.String(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("status_cryptobot", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.Column("status_yoomoney", sa.String(length=16), nullable=False, server_default="False"),
|
|
||||||
sa.PrimaryKeyConstraint("id"),
|
|
||||||
)
|
|
||||||
bind.execute(
|
|
||||||
sa.text(
|
|
||||||
f"""
|
|
||||||
INSERT INTO storage_payments_new (
|
|
||||||
id,
|
|
||||||
cryptobot_token,
|
|
||||||
yoomoney_token,
|
|
||||||
status_cryptobot,
|
|
||||||
status_yoomoney
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
1,
|
|
||||||
{_copy_expr("storage_payments", "cryptobot_token", "None")},
|
|
||||||
{_copy_expr("storage_payments", "yoomoney_token", "None")},
|
|
||||||
{_copy_expr("storage_payments", "status_cryptobot", "False")},
|
|
||||||
{_copy_expr("storage_payments", "status_yoomoney", "False")}
|
|
||||||
FROM storage_payments
|
|
||||||
LIMIT 1
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
bind.execute(sa.text("DROP TABLE storage_payments"))
|
|
||||||
bind.execute(sa.text("ALTER TABLE storage_payments_new RENAME TO storage_payments"))
|
|
||||||
|
|
||||||
bind.execute(
|
|
||||||
sa.text(
|
|
||||||
"""
|
|
||||||
INSERT INTO storage_payments (id)
|
|
||||||
SELECT 1
|
|
||||||
WHERE NOT EXISTS (SELECT 1 FROM storage_payments WHERE id = 1)
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
_normalize_boolean_text("storage_payments", "status_cryptobot", "False")
|
|
||||||
_normalize_boolean_text("storage_payments", "status_yoomoney", "False")
|
|
||||||
_create_index("ix_storage_payments_id", "storage_payments", "id", unique=True)
|
|
||||||
|
|
||||||
|
|
||||||
# Создание или правка таблицы категорий
|
|
||||||
def _ensure_category() -> None:
|
|
||||||
if not _table_exists("storage_category"):
|
|
||||||
op.create_table(
|
|
||||||
"storage_category",
|
|
||||||
sa.Column("increment", sa.Integer(), autoincrement=True, nullable=False),
|
|
||||||
sa.Column("category_id", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("category_name", sa.String(length=255), nullable=False),
|
|
||||||
sa.Column("category_unix", sa.Integer(), nullable=False),
|
|
||||||
sa.PrimaryKeyConstraint("increment"),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
_add_column("storage_category", "category_id", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_category", "category_name", "TEXT NOT NULL DEFAULT ''")
|
|
||||||
_add_column("storage_category", "category_unix", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
|
|
||||||
_create_index("ix_storage_category_category_id", "storage_category", "category_id")
|
|
||||||
|
|
||||||
|
|
||||||
# Создание или правка таблицы позиций
|
|
||||||
def _ensure_position() -> None:
|
|
||||||
if not _table_exists("storage_position"):
|
|
||||||
op.create_table(
|
|
||||||
"storage_position",
|
|
||||||
sa.Column("increment", sa.Integer(), autoincrement=True, nullable=False),
|
|
||||||
sa.Column("category_id", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("position_id", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("position_name", sa.String(length=255), nullable=False),
|
|
||||||
sa.Column("position_price", sa.Float(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("position_desc", sa.Text(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("position_photo", sa.Text(), nullable=False, server_default="None"),
|
|
||||||
sa.Column("position_unix", sa.Integer(), nullable=False),
|
|
||||||
sa.PrimaryKeyConstraint("increment"),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
_add_column("storage_position", "category_id", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_position", "position_id", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_position", "position_name", "TEXT NOT NULL DEFAULT ''")
|
|
||||||
_add_column("storage_position", "position_price", "REAL NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_position", "position_desc", "TEXT NOT NULL DEFAULT 'None'")
|
|
||||||
_add_column("storage_position", "position_photo", "TEXT NOT NULL DEFAULT 'None'")
|
|
||||||
_add_column("storage_position", "position_unix", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
|
|
||||||
_create_index("ix_storage_position_category_id", "storage_position", "category_id")
|
|
||||||
_create_index("ix_storage_position_position_id", "storage_position", "position_id")
|
|
||||||
|
|
||||||
|
|
||||||
# Создание или правка таблицы товаров
|
|
||||||
def _ensure_item() -> None:
|
|
||||||
if not _table_exists("storage_item"):
|
|
||||||
op.create_table(
|
|
||||||
"storage_item",
|
|
||||||
sa.Column("increment", sa.Integer(), autoincrement=True, nullable=False),
|
|
||||||
sa.Column("user_id", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("category_id", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("position_id", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("item_id", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("item_unix", sa.Integer(), nullable=False),
|
|
||||||
sa.Column("item_data", sa.Text(), nullable=False),
|
|
||||||
sa.PrimaryKeyConstraint("increment"),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
_add_column("storage_item", "user_id", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_item", "category_id", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_item", "position_id", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_item", "item_id", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_item", "item_unix", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_item", "item_data", "TEXT NOT NULL DEFAULT ''")
|
|
||||||
|
|
||||||
_create_index("ix_storage_item_user_id", "storage_item", "user_id")
|
|
||||||
_create_index("ix_storage_item_category_id", "storage_item", "category_id")
|
|
||||||
_create_index("ix_storage_item_position_id", "storage_item", "position_id")
|
|
||||||
_create_index("ix_storage_item_item_id", "storage_item", "item_id")
|
|
||||||
|
|
||||||
|
|
||||||
# Создание или правка таблицы покупок
|
|
||||||
def _ensure_purchases() -> None:
|
|
||||||
if not _table_exists("storage_purchases"):
|
|
||||||
op.create_table(
|
|
||||||
"storage_purchases",
|
|
||||||
sa.Column("increment", sa.Integer(), autoincrement=True, nullable=False),
|
|
||||||
sa.Column("user_id", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("user_balance_before", sa.Float(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("user_balance_after", sa.Float(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("purchase_receipt", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("purchase_data", sa.Text(), nullable=False),
|
|
||||||
sa.Column("purchase_count", sa.Integer(), nullable=False, server_default="1"),
|
|
||||||
sa.Column("purchase_price", sa.Float(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("purchase_price_one", sa.Float(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("purchase_position_id", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("purchase_position_name", sa.String(length=255), nullable=False),
|
|
||||||
sa.Column("purchase_category_id", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("purchase_category_name", sa.String(length=255), nullable=False),
|
|
||||||
sa.Column("purchase_unix", sa.Integer(), nullable=False),
|
|
||||||
sa.PrimaryKeyConstraint("increment"),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
_add_column("storage_purchases", "user_id", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_purchases", "user_balance_before", "REAL NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_purchases", "user_balance_after", "REAL NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_purchases", "purchase_receipt", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_purchases", "purchase_data", "TEXT NOT NULL DEFAULT ''")
|
|
||||||
_add_column("storage_purchases", "purchase_count", "INTEGER NOT NULL DEFAULT 1")
|
|
||||||
_add_column("storage_purchases", "purchase_price", "REAL NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_purchases", "purchase_price_one", "REAL NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_purchases", "purchase_position_id", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_purchases", "purchase_position_name", "TEXT NOT NULL DEFAULT ''")
|
|
||||||
_add_column("storage_purchases", "purchase_category_id", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_purchases", "purchase_category_name", "TEXT NOT NULL DEFAULT ''")
|
|
||||||
_add_column("storage_purchases", "purchase_unix", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
|
|
||||||
_create_index("ix_storage_purchases_user_id", "storage_purchases", "user_id")
|
|
||||||
_create_index("ix_storage_purchases_purchase_receipt", "storage_purchases", "purchase_receipt")
|
|
||||||
_create_index("ix_storage_purchases_purchase_position_id", "storage_purchases", "purchase_position_id")
|
|
||||||
_create_index("ix_storage_purchases_purchase_category_id", "storage_purchases", "purchase_category_id")
|
|
||||||
|
|
||||||
|
|
||||||
# Создание или правка таблицы пополнений
|
|
||||||
def _ensure_refill() -> None:
|
|
||||||
if not _table_exists("storage_refill"):
|
|
||||||
op.create_table(
|
|
||||||
"storage_refill",
|
|
||||||
sa.Column("increment", sa.Integer(), autoincrement=True, nullable=False),
|
|
||||||
sa.Column("user_id", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("refill_receipt", sa.BigInteger(), nullable=False),
|
|
||||||
sa.Column("refill_comment", sa.String(length=255), nullable=False, server_default=""),
|
|
||||||
sa.Column("refill_amount", sa.Float(), nullable=False, server_default="0"),
|
|
||||||
sa.Column("refill_method", sa.String(length=64), nullable=False),
|
|
||||||
sa.Column("refill_unix", sa.Integer(), nullable=False),
|
|
||||||
sa.PrimaryKeyConstraint("increment"),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
_add_column("storage_refill", "user_id", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_refill", "refill_receipt", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_refill", "refill_comment", "TEXT NOT NULL DEFAULT ''")
|
|
||||||
_add_column("storage_refill", "refill_amount", "REAL NOT NULL DEFAULT 0")
|
|
||||||
_add_column("storage_refill", "refill_method", "TEXT NOT NULL DEFAULT ''")
|
|
||||||
_add_column("storage_refill", "refill_unix", "INTEGER NOT NULL DEFAULT 0")
|
|
||||||
|
|
||||||
_create_index("ix_storage_refill_user_id", "storage_refill", "user_id")
|
|
||||||
_create_index("ix_storage_refill_refill_receipt", "storage_refill", "refill_receipt")
|
|
||||||
|
|
||||||
|
|
||||||
# Применение начальной схемы магазина
|
|
||||||
def upgrade() -> None:
|
|
||||||
_ensure_users()
|
|
||||||
_ensure_settings()
|
|
||||||
_ensure_payments()
|
|
||||||
_ensure_category()
|
|
||||||
_ensure_position()
|
|
||||||
_ensure_item()
|
|
||||||
_ensure_purchases()
|
|
||||||
_ensure_refill()
|
|
||||||
|
|
||||||
|
|
||||||
# Откат начальной схемы магазина
|
|
||||||
def downgrade() -> None:
|
|
||||||
op.drop_table("storage_refill")
|
|
||||||
op.drop_table("storage_purchases")
|
|
||||||
op.drop_table("storage_item")
|
|
||||||
op.drop_table("storage_position")
|
|
||||||
op.drop_table("storage_category")
|
|
||||||
op.drop_table("storage_payments")
|
|
||||||
op.drop_table("storage_settings")
|
|
||||||
op.drop_table("storage_users")
|
|
||||||
-32
@@ -1,32 +0,0 @@
|
|||||||
"""add column 'status_stars' into storage_payments
|
|
||||||
|
|
||||||
Revision ID: 492769059249
|
|
||||||
Revises: 0001_shop_schema
|
|
||||||
Create Date: 2026-05-30 19:15:00.214301+03:00
|
|
||||||
"""
|
|
||||||
from typing import Sequence, Union
|
|
||||||
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
revision: str = '492769059249'
|
|
||||||
down_revision: Union[str, None] = '0001_shop_schema'
|
|
||||||
branch_labels: Union[str, Sequence[str], None] = None
|
|
||||||
depends_on: Union[str, Sequence[str], None] = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade() -> None:
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
with op.batch_alter_table('storage_payments', schema=None) as batch_op:
|
|
||||||
batch_op.add_column(sa.Column('status_stars', sa.String(length=16), server_default=sa.text("'False'"), nullable=False))
|
|
||||||
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade() -> None:
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
with op.batch_alter_table('storage_payments', schema=None) as batch_op:
|
|
||||||
batch_op.drop_column('status_stars')
|
|
||||||
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
-32
@@ -1,32 +0,0 @@
|
|||||||
"""add column 'stars_course' into storage_payment
|
|
||||||
|
|
||||||
Revision ID: 700275128e27
|
|
||||||
Revises: 492769059249
|
|
||||||
Create Date: 2026-05-30 19:28:42.490458+03:00
|
|
||||||
"""
|
|
||||||
from typing import Sequence, Union
|
|
||||||
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
revision: str = '700275128e27'
|
|
||||||
down_revision: Union[str, None] = '492769059249'
|
|
||||||
branch_labels: Union[str, Sequence[str], None] = None
|
|
||||||
depends_on: Union[str, Sequence[str], None] = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade() -> None:
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
with op.batch_alter_table('storage_payments', schema=None) as batch_op:
|
|
||||||
batch_op.add_column(sa.Column('stars_course', sa.Float(), server_default=sa.text('(1.5)'), nullable=False))
|
|
||||||
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade() -> None:
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
with op.batch_alter_table('storage_payments', schema=None) as batch_op:
|
|
||||||
batch_op.drop_column('stars_course')
|
|
||||||
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
"""add column 'misc_method_prod' into 'storage_settings'
|
|
||||||
|
|
||||||
Revision ID: 36380377b0e6
|
|
||||||
Revises: 700275128e27
|
|
||||||
Create Date: 2026-06-01 19:34:35.858117+03:00
|
|
||||||
"""
|
|
||||||
from typing import Sequence, Union
|
|
||||||
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
revision: str = '36380377b0e6'
|
|
||||||
down_revision: Union[str, None] = '700275128e27'
|
|
||||||
branch_labels: Union[str, Sequence[str], None] = None
|
|
||||||
depends_on: Union[str, Sequence[str], None] = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade() -> None:
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
with op.batch_alter_table('storage_settings', schema=None) as batch_op:
|
|
||||||
batch_op.add_column(sa.Column('misc_method_prod', sa.String(length=16), server_default=sa.text("'skip'"), nullable=False))
|
|
||||||
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade() -> None:
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
with op.batch_alter_table('storage_settings', schema=None) as batch_op:
|
|
||||||
batch_op.drop_column('misc_method_prod')
|
|
||||||
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
@@ -28,4 +28,3 @@ dependencies = [
|
|||||||
|
|
||||||
[tool.setuptools.packages.find]
|
[tool.setuptools.packages.find]
|
||||||
include = ["tgbot*"]
|
include = ["tgbot*"]
|
||||||
exclude = ["migrations*"]
|
|
||||||
|
|||||||
+35
-10
@@ -28,16 +28,31 @@ class Settings(BaseSettings):
|
|||||||
default=True,
|
default=True,
|
||||||
validation_alias="BOT_DATABASE_EXPORT",
|
validation_alias="BOT_DATABASE_EXPORT",
|
||||||
)
|
)
|
||||||
status_notification: bool = Field(default=True, validation_alias="BOT_STATUS_NOTIFICATION")
|
status_notification: bool = Field(
|
||||||
|
default=True, validation_alias="BOT_STATUS_NOTIFICATION"
|
||||||
|
)
|
||||||
timezone: str = Field(default="Europe/Moscow", validation_alias="BOT_TIMEZONE")
|
timezone: str = Field(default="Europe/Moscow", validation_alias="BOT_TIMEZONE")
|
||||||
database_path: str = Field(default="tgbot/data/database.db", validation_alias="PATH_DATABASE")
|
database_path: str = Field(
|
||||||
|
default="tgbot/data/database.db", validation_alias="PATH_DATABASE"
|
||||||
|
)
|
||||||
logs_path: str = Field(default="tgbot/data/logs.log", validation_alias="PATH_LOGS")
|
logs_path: str = Field(default="tgbot/data/logs.log", validation_alias="PATH_LOGS")
|
||||||
user_cache_ttl: int = Field(default=300, ge=0, validation_alias="BOT_USER_CACHE_TTL")
|
user_cache_ttl: int = Field(
|
||||||
throttle_rate: float = Field(default=0.5, ge=0, validation_alias="BOT_THROTTLE_RATE")
|
default=300, ge=0, validation_alias="BOT_USER_CACHE_TTL"
|
||||||
|
)
|
||||||
|
throttle_rate: float = Field(
|
||||||
|
default=0.5, ge=0, validation_alias="BOT_THROTTLE_RATE"
|
||||||
|
)
|
||||||
yoomoney_client_id: str = Field(default="", validation_alias="YOOMONEY_CLIENT_ID")
|
yoomoney_client_id: str = Field(default="", validation_alias="YOOMONEY_CLIENT_ID")
|
||||||
|
|
||||||
# Очистка строковых значений из окружения
|
# Очистка строковых значений из окружения
|
||||||
@field_validator("bot_token", "timezone", "database_path", "logs_path", "yoomoney_client_id", mode="before")
|
@field_validator(
|
||||||
|
"bot_token",
|
||||||
|
"timezone",
|
||||||
|
"database_path",
|
||||||
|
"logs_path",
|
||||||
|
"yoomoney_client_id",
|
||||||
|
mode="before",
|
||||||
|
)
|
||||||
@classmethod
|
@classmethod
|
||||||
def _strip_string(cls, value: object) -> str:
|
def _strip_string(cls, value: object) -> str:
|
||||||
return str(value or "").strip()
|
return str(value or "").strip()
|
||||||
@@ -52,11 +67,15 @@ class Settings(BaseSettings):
|
|||||||
if isinstance(value, int):
|
if isinstance(value, int):
|
||||||
values = [value]
|
values = [value]
|
||||||
elif isinstance(value, str):
|
elif isinstance(value, str):
|
||||||
values = [admin_id for admin_id in value.replace(" ", "").split(",") if admin_id]
|
values = [
|
||||||
|
admin_id for admin_id in value.replace(" ", "").split(",") if admin_id
|
||||||
|
]
|
||||||
elif isinstance(value, (list, tuple, set)):
|
elif isinstance(value, (list, tuple, set)):
|
||||||
values = list(value)
|
values = list(value)
|
||||||
else:
|
else:
|
||||||
raise ValueError("BOT_ADMIN_IDS должен быть числом или списком чисел через запятую")
|
raise ValueError(
|
||||||
|
"BOT_ADMIN_IDS должен быть числом или списком чисел через запятую"
|
||||||
|
)
|
||||||
|
|
||||||
admin_ids = []
|
admin_ids = []
|
||||||
|
|
||||||
@@ -64,10 +83,14 @@ class Settings(BaseSettings):
|
|||||||
try:
|
try:
|
||||||
parsed_id = int(admin_id)
|
parsed_id = int(admin_id)
|
||||||
except (TypeError, ValueError) as error:
|
except (TypeError, ValueError) as error:
|
||||||
raise ValueError("BOT_ADMIN_IDS должен содержать только Телеграм ID через запятую") from error
|
raise ValueError(
|
||||||
|
"BOT_ADMIN_IDS должен содержать только Телеграм ID через запятую"
|
||||||
|
) from error
|
||||||
|
|
||||||
if parsed_id <= 0:
|
if parsed_id <= 0:
|
||||||
raise ValueError("BOT_ADMIN_IDS должен содержать Телеграм ID больше нуля")
|
raise ValueError(
|
||||||
|
"BOT_ADMIN_IDS должен содержать Телеграм ID больше нуля"
|
||||||
|
)
|
||||||
|
|
||||||
admin_ids.append(parsed_id)
|
admin_ids.append(parsed_id)
|
||||||
|
|
||||||
@@ -80,7 +103,9 @@ class Settings(BaseSettings):
|
|||||||
try:
|
try:
|
||||||
timezone(value)
|
timezone(value)
|
||||||
except UnknownTimeZoneError as error:
|
except UnknownTimeZoneError as error:
|
||||||
raise ValueError("BOT_TIMEZONE должен быть корректной временной зоной, например Europe/Moscow") from error
|
raise ValueError(
|
||||||
|
"BOT_TIMEZONE должен быть корректной временной зоной, например Europe/Moscow"
|
||||||
|
) from error
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|||||||
@@ -13,14 +13,17 @@ from tgbot.utils.const_functions import get_unix
|
|||||||
class PositionModel(Base):
|
class PositionModel(Base):
|
||||||
__tablename__ = "storage_position"
|
__tablename__ = "storage_position"
|
||||||
|
|
||||||
increment: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
increment: Mapped[int] = mapped_column(
|
||||||
|
Integer, primary_key=True, autoincrement=True
|
||||||
|
)
|
||||||
category_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True)
|
category_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True)
|
||||||
position_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True)
|
position_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True)
|
||||||
position_name: Mapped[str] = mapped_column(String(255), nullable=False)
|
position_name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||||
position_price: Mapped[float] = mapped_column(Float, nullable=False, default=0)
|
position_price: Mapped[float] = mapped_column(Float, nullable=False, default=0)
|
||||||
position_desc: Mapped[str] = mapped_column(Text, nullable=False, default="None")
|
position_desc: Mapped[str] = mapped_column(Text, nullable=False, default="None")
|
||||||
position_photo: Mapped[str] = mapped_column(Text, nullable=False, default="None")
|
position_unix: Mapped[int] = mapped_column(
|
||||||
position_unix: Mapped[int] = mapped_column(Integer, nullable=False, default=get_unix)
|
Integer, nullable=False, default=get_unix
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
ModelBase = Position
|
ModelBase = Position
|
||||||
@@ -37,13 +40,12 @@ class Positionx(BaseRepository[PositionModel, Position]):
|
|||||||
|
|
||||||
# Добавление позиции товара
|
# Добавление позиции товара
|
||||||
async def add(
|
async def add(
|
||||||
self,
|
self,
|
||||||
category_id: int,
|
category_id: int,
|
||||||
position_id: int,
|
position_id: int,
|
||||||
position_name: str,
|
position_name: str,
|
||||||
position_price: float,
|
position_price: float,
|
||||||
position_desc: str,
|
position_desc: str,
|
||||||
position_photo: str,
|
|
||||||
) -> Position:
|
) -> Position:
|
||||||
return await self._insert(
|
return await self._insert(
|
||||||
category_id=category_id,
|
category_id=category_id,
|
||||||
@@ -51,12 +53,13 @@ class Positionx(BaseRepository[PositionModel, Position]):
|
|||||||
position_name=position_name,
|
position_name=position_name,
|
||||||
position_price=position_price,
|
position_price=position_price,
|
||||||
position_desc=position_desc,
|
position_desc=position_desc,
|
||||||
position_photo=position_photo,
|
|
||||||
position_unix=get_unix(),
|
position_unix=get_unix(),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Обновление позиции по ID или фильтру
|
# Обновление позиции по ID или фильтру
|
||||||
async def update(self, where: Optional[Union[Dict[str, Any], int]] = None, **kwargs) -> int:
|
async def update(
|
||||||
|
self, where: Optional[Union[Dict[str, Any], int]] = None, **kwargs
|
||||||
|
) -> int:
|
||||||
if isinstance(where, int):
|
if isinstance(where, int):
|
||||||
where = {"position_id": where}
|
where = {"position_id": where}
|
||||||
|
|
||||||
@@ -68,12 +71,15 @@ class Positionx(BaseRepository[PositionModel, Position]):
|
|||||||
from tgbot.database.db_item import ItemModel
|
from tgbot.database.db_item import ItemModel
|
||||||
|
|
||||||
item_table = ItemModel.__table__
|
item_table = ItemModel.__table__
|
||||||
statement = (
|
statement = select(
|
||||||
select(item_table.c.position_id, func.count(item_table.c.increment).label("item_count"))
|
item_table.c.position_id,
|
||||||
.group_by(item_table.c.position_id)
|
func.count(item_table.c.increment).label("item_count"),
|
||||||
)
|
).group_by(item_table.c.position_id)
|
||||||
|
|
||||||
async with session_scope() as session:
|
async with session_scope() as session:
|
||||||
rows = await session.execute(statement)
|
rows = await session.execute(statement)
|
||||||
|
|
||||||
return {int(position_id): int(item_count) for position_id, item_count in rows.all()}
|
return {
|
||||||
|
int(position_id): int(item_count)
|
||||||
|
for position_id, item_count in rows.all()
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,20 +14,34 @@ class SettingsModel(Base):
|
|||||||
|
|
||||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, default=1)
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, default=1)
|
||||||
status_work: Mapped[str] = mapped_column(String(16), nullable=False, default="True")
|
status_work: Mapped[str] = mapped_column(String(16), nullable=False, default="True")
|
||||||
status_refill: Mapped[str] = mapped_column(String(16), nullable=False, default="False")
|
status_refill: Mapped[str] = mapped_column(
|
||||||
|
String(16), nullable=False, default="False"
|
||||||
|
)
|
||||||
status_buy: Mapped[str] = mapped_column(String(16), nullable=False, default="False")
|
status_buy: Mapped[str] = mapped_column(String(16), nullable=False, default="False")
|
||||||
notification_refill: Mapped[str] = mapped_column(String(16), nullable=False, default="True")
|
notification_refill: Mapped[str] = mapped_column(
|
||||||
notification_buy: Mapped[str] = mapped_column(String(16), nullable=False, default="False")
|
String(16), nullable=False, default="True"
|
||||||
|
)
|
||||||
|
notification_buy: Mapped[str] = mapped_column(
|
||||||
|
String(16), nullable=False, default="False"
|
||||||
|
)
|
||||||
misc_faq: Mapped[str] = mapped_column(String, nullable=False, default="None")
|
misc_faq: Mapped[str] = mapped_column(String, nullable=False, default="None")
|
||||||
misc_support: Mapped[str] = mapped_column(String, nullable=False, default="None")
|
misc_support: Mapped[str] = mapped_column(String, nullable=False, default="None")
|
||||||
misc_bot: Mapped[str] = mapped_column(String(255), nullable=False, default="None")
|
misc_bot: Mapped[str] = mapped_column(String(255), nullable=False, default="None")
|
||||||
misc_hosting_text: Mapped[str] = mapped_column(String(64), nullable=False, default="telegraph")
|
misc_hosting_text: Mapped[str] = mapped_column(
|
||||||
misc_token_telegraph: Mapped[str] = mapped_column(String, nullable=False, default="None")
|
String(64), nullable=False, default="telegraph"
|
||||||
misc_discord_webhook_url: Mapped[str] = mapped_column(String, nullable=False, default="None")
|
)
|
||||||
misc_discord_webhook_name: Mapped[str] = mapped_column(String(255), nullable=False, default="None")
|
misc_token_telegraph: Mapped[str] = mapped_column(
|
||||||
misc_hide_category: Mapped[str] = mapped_column(String(16), nullable=False, default="False")
|
String, nullable=False, default="None"
|
||||||
misc_hide_position: Mapped[str] = mapped_column(String(16), nullable=False, default="False")
|
)
|
||||||
misc_method_prod: Mapped[str] = mapped_column(String(16), nullable=False, default="skip")
|
misc_hide_category: Mapped[str] = mapped_column(
|
||||||
|
String(16), nullable=False, default="False"
|
||||||
|
)
|
||||||
|
misc_hide_position: Mapped[str] = mapped_column(
|
||||||
|
String(16), nullable=False, default="False"
|
||||||
|
)
|
||||||
|
misc_method_prod: Mapped[str] = mapped_column(
|
||||||
|
String(16), nullable=False, default="skip"
|
||||||
|
)
|
||||||
misc_profit_day: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
misc_profit_day: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||||
misc_profit_week: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
misc_profit_week: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||||
misc_profit_month: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
misc_profit_month: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ class Position:
|
|||||||
position_name: str
|
position_name: str
|
||||||
position_price: float
|
position_price: float
|
||||||
position_desc: str
|
position_desc: str
|
||||||
position_photo: str
|
|
||||||
position_unix: int
|
position_unix: int
|
||||||
|
|
||||||
|
|
||||||
@@ -86,8 +85,6 @@ class Settings:
|
|||||||
misc_bot: str
|
misc_bot: str
|
||||||
misc_hosting_text: str
|
misc_hosting_text: str
|
||||||
misc_token_telegraph: str
|
misc_token_telegraph: str
|
||||||
misc_discord_webhook_url: str
|
|
||||||
misc_discord_webhook_name: str
|
|
||||||
misc_hide_category: str
|
misc_hide_category: str
|
||||||
misc_hide_position: str
|
misc_hide_position: str
|
||||||
misc_method_prod: str
|
misc_method_prod: str
|
||||||
|
|||||||
@@ -12,13 +12,11 @@ from tgbot.database.core import database_url
|
|||||||
|
|
||||||
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
||||||
ALEMBIC_INI = PROJECT_ROOT / "alembic.ini"
|
ALEMBIC_INI = PROJECT_ROOT / "alembic.ini"
|
||||||
MIGRATIONS_DIR = PROJECT_ROOT / "migrations"
|
|
||||||
|
|
||||||
|
|
||||||
# Сбор Alembic-конфига от корня проекта
|
# Сбор Alembic-конфига от корня проекта
|
||||||
def get_alembic_config(url: str = database_url) -> Config:
|
def get_alembic_config(url: str = database_url) -> Config:
|
||||||
config = Config(str(ALEMBIC_INI))
|
config = Config(str(ALEMBIC_INI))
|
||||||
config.set_main_option("script_location", str(MIGRATIONS_DIR))
|
|
||||||
config.set_main_option("sqlalchemy.url", url)
|
config.set_main_option("sqlalchemy.url", url)
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ from sqlalchemy import delete as sqlalchemy_delete
|
|||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from sqlalchemy import update as sqlalchemy_update
|
from sqlalchemy import update as sqlalchemy_update
|
||||||
from tgbot.database.core import Base, database_path, session_scope
|
from tgbot.database.core import Base, database_path, session_scope
|
||||||
from tgbot.database.migration_runner import run_migrations
|
|
||||||
from tgbot.utils.misc.bot_logging import bot_logger
|
from tgbot.utils.misc.bot_logging import bot_logger
|
||||||
|
|
||||||
ModelTranslator = TypeVar("ModelTranslator", bound=Base)
|
ModelTranslator = TypeVar("ModelTranslator", bound=Base)
|
||||||
@@ -151,7 +150,7 @@ class BaseRepository(Generic[ModelTranslator, EntityTranslator]):
|
|||||||
# Применение миграций и создание дефолтных строк
|
# Применение миграций и создание дефолтных строк
|
||||||
async def prepare_database() -> None:
|
async def prepare_database() -> None:
|
||||||
database_path.parent.mkdir(parents=True, exist_ok=True)
|
database_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
await run_migrations()
|
# await run_migrations()
|
||||||
|
|
||||||
from tgbot.database.db_payments import Paymentsx
|
from tgbot.database.db_payments import Paymentsx
|
||||||
from tgbot.database.db_settings import Settingsx
|
from tgbot.database.db_settings import Settingsx
|
||||||
|
|||||||
@@ -73,9 +73,15 @@ async def payment_cryptobot_finl() -> InlineKeyboardMarkup:
|
|||||||
assets_symbol = "➕"
|
assets_symbol = "➕"
|
||||||
|
|
||||||
if get_payments.status_cryptobot == "True":
|
if get_payments.status_cryptobot == "True":
|
||||||
status_kb = ikb(f"{assets_symbol} | Статус: Включено ✅", data="payment_cryptobot_status:False")
|
status_kb = ikb(
|
||||||
|
f"{assets_symbol} | Статус: Включено ✅",
|
||||||
|
data="payment_cryptobot_status:False",
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
status_kb = ikb(f"{assets_symbol} | Статус: Выключено ❌", data="payment_cryptobot_status:True")
|
status_kb = ikb(
|
||||||
|
f"{assets_symbol} | Статус: Выключено ❌",
|
||||||
|
data="payment_cryptobot_status:True",
|
||||||
|
)
|
||||||
|
|
||||||
keyboard.row(
|
keyboard.row(
|
||||||
ikb("Информация ♻️", data="payment_cryptobot_check"),
|
ikb("Информация ♻️", data="payment_cryptobot_check"),
|
||||||
@@ -104,9 +110,15 @@ async def payment_yoomoney_finl() -> InlineKeyboardMarkup:
|
|||||||
assets_symbol = "➕"
|
assets_symbol = "➕"
|
||||||
|
|
||||||
if get_payments.status_yoomoney == "True":
|
if get_payments.status_yoomoney == "True":
|
||||||
status_kb = ikb(f"{assets_symbol} | Статус: Включено ✅", data="payment_yoomoney_status:False")
|
status_kb = ikb(
|
||||||
|
f"{assets_symbol} | Статус: Включено ✅",
|
||||||
|
data="payment_yoomoney_status:False",
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
status_kb = ikb(f"{assets_symbol} | Статус: Выключено ❌", data="payment_yoomoney_status:True")
|
status_kb = ikb(
|
||||||
|
f"{assets_symbol} | Статус: Выключено ❌",
|
||||||
|
data="payment_yoomoney_status:True",
|
||||||
|
)
|
||||||
|
|
||||||
keyboard.row(
|
keyboard.row(
|
||||||
ikb("Информация ♻️", data="payment_yoomoney_check"),
|
ikb("Информация ♻️", data="payment_yoomoney_check"),
|
||||||
@@ -132,9 +144,13 @@ async def payment_stars_finl() -> InlineKeyboardMarkup:
|
|||||||
assets_symbol = "➕"
|
assets_symbol = "➕"
|
||||||
|
|
||||||
if get_payments.status_stars == "True":
|
if get_payments.status_stars == "True":
|
||||||
status_kb = ikb(f"{assets_symbol} | Статус: Включено ✅", data="payment_stars_status:False")
|
status_kb = ikb(
|
||||||
|
f"{assets_symbol} | Статус: Включено ✅", data="payment_stars_status:False"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
status_kb = ikb(f"{assets_symbol} | Статус: Выключено ❌", data="payment_stars_status:True")
|
status_kb = ikb(
|
||||||
|
f"{assets_symbol} | Статус: Выключено ❌", data="payment_stars_status:True"
|
||||||
|
)
|
||||||
|
|
||||||
keyboard.row(
|
keyboard.row(
|
||||||
ikb("Информация ♻️", data="payment_stars_check"),
|
ikb("Информация ♻️", data="payment_stars_check"),
|
||||||
@@ -169,16 +185,9 @@ async def settings_finl() -> InlineKeyboardMarkup:
|
|||||||
if get_settings.misc_support == "None":
|
if get_settings.misc_support == "None":
|
||||||
support_kb = ikb("Не установлена ❌", data="settings_edit_support")
|
support_kb = ikb("Не установлена ❌", data="settings_edit_support")
|
||||||
else:
|
else:
|
||||||
support_kb = ikb(f"@{get_settings.misc_support} ✅", data="settings_edit_support")
|
support_kb = ikb(
|
||||||
|
f"@{get_settings.misc_support} ✅", data="settings_edit_support"
|
||||||
# Вебхук дискорда
|
)
|
||||||
if get_settings.misc_discord_webhook_url == "None":
|
|
||||||
discord_webhook_kb = ikb("Отсутствует ❌", data="settings_edit_discord_webhook")
|
|
||||||
else:
|
|
||||||
discord_webhook_kb = ikb(f"{get_settings.misc_discord_webhook_name} ✅", data="settings_edit_discord_webhook")
|
|
||||||
|
|
||||||
# Текстовый хостинг по умолчанию
|
|
||||||
hosting_text_default_kb = ikb(get_settings.misc_hosting_text.title(), data="settings_edit_hosting_text")
|
|
||||||
|
|
||||||
# Скрытие категорий без товаров
|
# Скрытие категорий без товаров
|
||||||
if get_settings.misc_hide_category == "True":
|
if get_settings.misc_hide_category == "True":
|
||||||
@@ -199,19 +208,20 @@ async def settings_finl() -> InlineKeyboardMarkup:
|
|||||||
method_prod_kb = ikb("На каждой строке", data="settings_edit_method_prod:skip")
|
method_prod_kb = ikb("На каждой строке", data="settings_edit_method_prod:skip")
|
||||||
|
|
||||||
keyboard.row(
|
keyboard.row(
|
||||||
ikb("❔ FAQ", data="..."), faq_kb,
|
ikb("❔ FAQ", data="..."),
|
||||||
|
faq_kb,
|
||||||
).row(
|
).row(
|
||||||
ikb("☎️ Поддержка", data="..."), support_kb,
|
ikb("☎️ Поддержка", data="..."),
|
||||||
|
support_kb,
|
||||||
).row(
|
).row(
|
||||||
ikb("🧿 Дискорд Webhook", url="https://teletype.in/@djimbox/djimboshop-discord"), discord_webhook_kb,
|
ikb("🎁 Категории без товаров", data="..."),
|
||||||
|
hide_category_kb,
|
||||||
).row(
|
).row(
|
||||||
ikb("🗯 Текстовый хостинг", data="..."), hosting_text_default_kb,
|
ikb("🎁 Позиции без товаров", data="..."),
|
||||||
|
hide_position_kb,
|
||||||
).row(
|
).row(
|
||||||
ikb("🎁 Категории без товаров", data="..."), hide_category_kb,
|
ikb("🎁 Метод добавления", data="..."),
|
||||||
).row(
|
method_prod_kb,
|
||||||
ikb("🎁 Позиции без товаров", data="..."), hide_position_kb,
|
|
||||||
).row(
|
|
||||||
ikb("🎁 Метод добавления", data="..."), method_prod_kb,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return keyboard.as_markup()
|
return keyboard.as_markup()
|
||||||
@@ -227,7 +237,9 @@ async def settings_status_finl() -> InlineKeyboardMarkup:
|
|||||||
status_buy_kb = ikb("Включены ✅", data="settings_status_buy:False")
|
status_buy_kb = ikb("Включены ✅", data="settings_status_buy:False")
|
||||||
status_refill_kb = ikb("Включены ✅", data="settings_status_refill:False")
|
status_refill_kb = ikb("Включены ✅", data="settings_status_refill:False")
|
||||||
notification_buy_kb = ikb("Включены 🔔", data="settings_notification_buy:False")
|
notification_buy_kb = ikb("Включены 🔔", data="settings_notification_buy:False")
|
||||||
notification_refill_kb = ikb("Включены 🔔", data="settings_notification_refill:False")
|
notification_refill_kb = ikb(
|
||||||
|
"Включены 🔔", data="settings_notification_refill:False"
|
||||||
|
)
|
||||||
|
|
||||||
if get_settings.status_buy == "False":
|
if get_settings.status_buy == "False":
|
||||||
status_buy_kb = ikb("Выключены ❌", data="settings_status_buy:True")
|
status_buy_kb = ikb("Выключены ❌", data="settings_status_buy:True")
|
||||||
@@ -238,18 +250,25 @@ async def settings_status_finl() -> InlineKeyboardMarkup:
|
|||||||
if get_settings.notification_buy == "False":
|
if get_settings.notification_buy == "False":
|
||||||
notification_buy_kb = ikb("Выключены 🔕", data="settings_notification_buy:True")
|
notification_buy_kb = ikb("Выключены 🔕", data="settings_notification_buy:True")
|
||||||
if get_settings.notification_refill == "False":
|
if get_settings.notification_refill == "False":
|
||||||
notification_refill_kb = ikb("Выключены 🔕", data="settings_notification_refill:True")
|
notification_refill_kb = ikb(
|
||||||
|
"Выключены 🔕", data="settings_notification_refill:True"
|
||||||
|
)
|
||||||
|
|
||||||
keyboard.row(
|
keyboard.row(
|
||||||
ikb("⛔ Тех. работы", data="..."), status_work_kb,
|
ikb("⛔ Тех. работы", data="..."),
|
||||||
|
status_work_kb,
|
||||||
).row(
|
).row(
|
||||||
ikb("💰 Пополнения", data="..."), status_refill_kb,
|
ikb("💰 Пополнения", data="..."),
|
||||||
|
status_refill_kb,
|
||||||
).row(
|
).row(
|
||||||
ikb("🎁 Покупки", data="..."), status_buy_kb,
|
ikb("🎁 Покупки", data="..."),
|
||||||
|
status_buy_kb,
|
||||||
).row(
|
).row(
|
||||||
ikb("📢 Увед. о покупках", data="..."), notification_buy_kb,
|
ikb("📢 Увед. о покупках", data="..."),
|
||||||
|
notification_buy_kb,
|
||||||
).row(
|
).row(
|
||||||
ikb("📢 Увед. о пополнениях", data="..."), notification_refill_kb,
|
ikb("📢 Увед. о пополнениях", data="..."),
|
||||||
|
notification_refill_kb,
|
||||||
)
|
)
|
||||||
|
|
||||||
return keyboard.as_markup()
|
return keyboard.as_markup()
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ from tgbot.utils.const_functions import ikb
|
|||||||
################################################################################
|
################################################################################
|
||||||
################################### КАТЕГОРИИ ##################################
|
################################### КАТЕГОРИИ ##################################
|
||||||
# Изменение категории
|
# Изменение категории
|
||||||
async def category_edit_open_finl(bot: Bot, category_id: int, remover: int) -> InlineKeyboardMarkup:
|
async def category_edit_open_finl(
|
||||||
|
bot: Bot, category_id: int, remover: int
|
||||||
|
) -> InlineKeyboardMarkup:
|
||||||
keyboard = InlineKeyboardBuilder()
|
keyboard = InlineKeyboardBuilder()
|
||||||
|
|
||||||
get_bot = await bot.get_me()
|
get_bot = await bot.get_me()
|
||||||
@@ -19,7 +21,10 @@ async def category_edit_open_finl(bot: Bot, category_id: int, remover: int) -> I
|
|||||||
ikb("▪️ Изм. Название", data=f"category_edit_name:{category_id}:{remover}"),
|
ikb("▪️ Изм. Название", data=f"category_edit_name:{category_id}:{remover}"),
|
||||||
ikb("▪️ Добавить позицию", data=f"position_add_open:{category_id}"),
|
ikb("▪️ Добавить позицию", data=f"position_add_open:{category_id}"),
|
||||||
).row(
|
).row(
|
||||||
ikb("▪️ Скопировать ссылку", copy=f"t.me/{get_bot.username}?start=c_{category_id}"),
|
ikb(
|
||||||
|
"▪️ Скопировать ссылку",
|
||||||
|
copy=f"t.me/{get_bot.username}?start=c_{category_id}",
|
||||||
|
),
|
||||||
ikb("▪️ Удалить", data=f"category_edit_delete:{category_id}:{remover}"),
|
ikb("▪️ Удалить", data=f"category_edit_delete:{category_id}:{remover}"),
|
||||||
).row(
|
).row(
|
||||||
ikb("🔙 Вернуться", data=f"category_edit_swipe:{remover}"),
|
ikb("🔙 Вернуться", data=f"category_edit_swipe:{remover}"),
|
||||||
@@ -34,8 +39,11 @@ def category_edit_delete_finl(category_id: int, remover: int) -> InlineKeyboardM
|
|||||||
keyboard = InlineKeyboardBuilder()
|
keyboard = InlineKeyboardBuilder()
|
||||||
|
|
||||||
keyboard.row(
|
keyboard.row(
|
||||||
ikb("✅ Да, удалить", data=f"category_edit_delete_confirm:{category_id}:{remover}"),
|
ikb(
|
||||||
ikb("❌ Нет, отменить", data=f"category_edit_open:{category_id}:{remover}")
|
"✅ Да, удалить",
|
||||||
|
data=f"category_edit_delete_confirm:{category_id}:{remover}",
|
||||||
|
),
|
||||||
|
ikb("❌ Нет, отменить", data=f"category_edit_open:{category_id}:{remover}"),
|
||||||
)
|
)
|
||||||
|
|
||||||
return keyboard.as_markup()
|
return keyboard.as_markup()
|
||||||
@@ -55,7 +63,9 @@ def category_edit_cancel_finl(category_id: int, remover: int) -> InlineKeyboardM
|
|||||||
################################################################################
|
################################################################################
|
||||||
#################################### ПОЗИЦИИ ###################################
|
#################################### ПОЗИЦИИ ###################################
|
||||||
# Кнопки при открытии позиции для изменения
|
# Кнопки при открытии позиции для изменения
|
||||||
async def position_edit_open_finl(bot: Bot, position_id: int, remover: int) -> InlineKeyboardMarkup:
|
async def position_edit_open_finl(
|
||||||
|
bot: Bot, position_id: int, remover: int
|
||||||
|
) -> InlineKeyboardMarkup:
|
||||||
keyboard = InlineKeyboardBuilder()
|
keyboard = InlineKeyboardBuilder()
|
||||||
|
|
||||||
get_position = await Positionx().get_required(position_id=position_id)
|
get_position = await Positionx().get_required(position_id=position_id)
|
||||||
@@ -66,7 +76,6 @@ async def position_edit_open_finl(bot: Bot, position_id: int, remover: int) -> I
|
|||||||
ikb("▪️ Изм. Цену", data=f"position_edit_price:{position_id}:{remover}"),
|
ikb("▪️ Изм. Цену", data=f"position_edit_price:{position_id}:{remover}"),
|
||||||
).row(
|
).row(
|
||||||
ikb("▪️ Изм. Описание", data=f"position_edit_desc:{position_id}:{remover}"),
|
ikb("▪️ Изм. Описание", data=f"position_edit_desc:{position_id}:{remover}"),
|
||||||
ikb("▪️ Изм. Фото", data=f"position_edit_photo:{position_id}:{remover}"),
|
|
||||||
).row(
|
).row(
|
||||||
ikb("▪️ Добавить Товары", data=f"item_add_position_open:{position_id}"),
|
ikb("▪️ Добавить Товары", data=f"item_add_position_open:{position_id}"),
|
||||||
ikb("▪️ Выгрузить Товары", data=f"position_edit_items:{position_id}:{remover}"),
|
ikb("▪️ Выгрузить Товары", data=f"position_edit_items:{position_id}:{remover}"),
|
||||||
@@ -74,10 +83,16 @@ async def position_edit_open_finl(bot: Bot, position_id: int, remover: int) -> I
|
|||||||
ikb("▪️ Очистить Товары", data=f"position_edit_clear:{position_id}:{remover}"),
|
ikb("▪️ Очистить Товары", data=f"position_edit_clear:{position_id}:{remover}"),
|
||||||
ikb("▪️ Удалить Товар", data=f"item_delete_swipe:{position_id}:0"),
|
ikb("▪️ Удалить Товар", data=f"item_delete_swipe:{position_id}:0"),
|
||||||
).row(
|
).row(
|
||||||
ikb("▪️ Скопировать ссылку", copy=f"t.me/{get_bot.username}?start=p_{position_id}"),
|
ikb(
|
||||||
|
"▪️ Скопировать ссылку",
|
||||||
|
copy=f"t.me/{get_bot.username}?start=p_{position_id}",
|
||||||
|
),
|
||||||
ikb("▪️ Удалить Позицию", data=f"position_edit_delete:{position_id}:{remover}"),
|
ikb("▪️ Удалить Позицию", data=f"position_edit_delete:{position_id}:{remover}"),
|
||||||
).row(
|
).row(
|
||||||
ikb("🔙 Вернуться", data=f"position_edit_swipe:{get_position.category_id}:{remover}"),
|
ikb(
|
||||||
|
"🔙 Вернуться",
|
||||||
|
data=f"position_edit_swipe:{get_position.category_id}:{remover}",
|
||||||
|
),
|
||||||
ikb("▪️ Обновить", data=f"position_edit_open:{position_id}:{remover}"),
|
ikb("▪️ Обновить", data=f"position_edit_open:{position_id}:{remover}"),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -89,8 +104,11 @@ def position_edit_delete_finl(position_id: int, remover: int) -> InlineKeyboardM
|
|||||||
keyboard = InlineKeyboardBuilder()
|
keyboard = InlineKeyboardBuilder()
|
||||||
|
|
||||||
keyboard.row(
|
keyboard.row(
|
||||||
ikb("✅ Да, удалить", data=f"position_edit_delete_confirm:{position_id}:{remover}"),
|
ikb(
|
||||||
ikb("❌ Нет, отменить", data=f"position_edit_open:{position_id}:{remover}")
|
"✅ Да, удалить",
|
||||||
|
data=f"position_edit_delete_confirm:{position_id}:{remover}",
|
||||||
|
),
|
||||||
|
ikb("❌ Нет, отменить", data=f"position_edit_open:{position_id}:{remover}"),
|
||||||
)
|
)
|
||||||
|
|
||||||
return keyboard.as_markup()
|
return keyboard.as_markup()
|
||||||
@@ -101,8 +119,11 @@ def position_edit_clear_finl(position_id: int, remover: int) -> InlineKeyboardMa
|
|||||||
keyboard = InlineKeyboardBuilder()
|
keyboard = InlineKeyboardBuilder()
|
||||||
|
|
||||||
keyboard.row(
|
keyboard.row(
|
||||||
ikb("✅ Да, очистить", data=f"position_edit_clear_confirm:{position_id}:{remover}"),
|
ikb(
|
||||||
ikb("❌ Нет, отменить", data=f"position_edit_open:{position_id}:{remover}")
|
"✅ Да, очистить",
|
||||||
|
data=f"position_edit_clear_confirm:{position_id}:{remover}",
|
||||||
|
),
|
||||||
|
ikb("❌ Нет, отменить", data=f"position_edit_open:{position_id}:{remover}"),
|
||||||
)
|
)
|
||||||
|
|
||||||
return keyboard.as_markup()
|
return keyboard.as_markup()
|
||||||
@@ -168,7 +189,7 @@ def products_removes_categories_finl() -> InlineKeyboardMarkup:
|
|||||||
|
|
||||||
keyboard.row(
|
keyboard.row(
|
||||||
ikb("✅ Да, удалить все", data="prod_removes_categories_confirm"),
|
ikb("✅ Да, удалить все", data="prod_removes_categories_confirm"),
|
||||||
ikb("❌ Нет, отменить", data="prod_removes_return")
|
ikb("❌ Нет, отменить", data="prod_removes_return"),
|
||||||
)
|
)
|
||||||
|
|
||||||
return keyboard.as_markup()
|
return keyboard.as_markup()
|
||||||
@@ -180,7 +201,7 @@ def products_removes_positions_finl() -> InlineKeyboardMarkup:
|
|||||||
|
|
||||||
keyboard.row(
|
keyboard.row(
|
||||||
ikb("✅ Да, удалить все", data="prod_removes_positions_confirm"),
|
ikb("✅ Да, удалить все", data="prod_removes_positions_confirm"),
|
||||||
ikb("❌ Нет, отменить", data="prod_removes_return")
|
ikb("❌ Нет, отменить", data="prod_removes_return"),
|
||||||
)
|
)
|
||||||
|
|
||||||
return keyboard.as_markup()
|
return keyboard.as_markup()
|
||||||
@@ -192,7 +213,7 @@ def products_removes_items_finl() -> InlineKeyboardMarkup:
|
|||||||
|
|
||||||
keyboard.row(
|
keyboard.row(
|
||||||
ikb("✅ Да, удалить все", data="prod_removes_items_confirm"),
|
ikb("✅ Да, удалить все", data="prod_removes_items_confirm"),
|
||||||
ikb("❌ Нет, отменить", data="prod_removes_return")
|
ikb("❌ Нет, отменить", data="prod_removes_return"),
|
||||||
)
|
)
|
||||||
|
|
||||||
return keyboard.as_markup()
|
return keyboard.as_markup()
|
||||||
|
|||||||
@@ -26,12 +26,23 @@ from tgbot.keyboards.inline_admin_products import (
|
|||||||
products_removes_items_finl,
|
products_removes_items_finl,
|
||||||
item_add_finish_finl,
|
item_add_finish_finl,
|
||||||
)
|
)
|
||||||
from tgbot.services.api_discord import DiscordAPI
|
|
||||||
from tgbot.services.api_hosting_text import HostingAPI
|
from tgbot.services.api_hosting_text import HostingAPI
|
||||||
from tgbot.utils.const_functions import clear_list, is_number, to_number, del_message, ded, clear_html, gen_id
|
from tgbot.utils.const_functions import (
|
||||||
|
clear_list,
|
||||||
|
is_number,
|
||||||
|
to_number,
|
||||||
|
del_message,
|
||||||
|
ded,
|
||||||
|
clear_html,
|
||||||
|
gen_id,
|
||||||
|
)
|
||||||
from tgbot.utils.misc.bot_logging import bot_logger
|
from tgbot.utils.misc.bot_logging import bot_logger
|
||||||
from tgbot.utils.misc.bot_models import FSM, ARS
|
from tgbot.utils.misc.bot_models import FSM, ARS
|
||||||
from tgbot.utils.text_functions import category_open_admin, position_open_admin, item_open_admin
|
from tgbot.utils.text_functions import (
|
||||||
|
category_open_admin,
|
||||||
|
position_open_admin,
|
||||||
|
item_open_admin,
|
||||||
|
)
|
||||||
|
|
||||||
router = Router(name=__name__)
|
router = Router(name=__name__)
|
||||||
|
|
||||||
@@ -123,8 +134,10 @@ async def prod_removes(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
|||||||
################################################################################
|
################################################################################
|
||||||
############################### СОЗДАНИЕ КАТЕГОРИИ #############################
|
############################### СОЗДАНИЕ КАТЕГОРИИ #############################
|
||||||
# Принятие названия категории для её создания
|
# Принятие названия категории для её создания
|
||||||
@router.message(F.text, StateFilter('here_category_name'))
|
@router.message(F.text, StateFilter("here_category_name"))
|
||||||
async def prod_category_add_name_get(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_category_add_name_get(
|
||||||
|
message: Message, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
if len(message.text) > 50:
|
if len(message.text) > 50:
|
||||||
return await message.answer(
|
return await message.answer(
|
||||||
"<b>❌ Название не может превышать 50 символов</b>\n"
|
"<b>❌ Название не может превышать 50 символов</b>\n"
|
||||||
@@ -143,7 +156,9 @@ async def prod_category_add_name_get(message: Message, bot: Bot, state: FSM, arS
|
|||||||
############################### ИЗМЕНЕНИЕ КАТЕГОРИИ ############################
|
############################### ИЗМЕНЕНИЕ КАТЕГОРИИ ############################
|
||||||
# Страница выбора категорий для редактирования
|
# Страница выбора категорий для редактирования
|
||||||
@router.callback_query(F.data.startswith("category_edit_swipe:"))
|
@router.callback_query(F.data.startswith("category_edit_swipe:"))
|
||||||
async def prod_category_edit_swipe(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_category_edit_swipe(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
remover = int(call.data.split(":")[1])
|
remover = int(call.data.split(":")[1])
|
||||||
|
|
||||||
await call.message.edit_text(
|
await call.message.edit_text(
|
||||||
@@ -154,7 +169,9 @@ async def prod_category_edit_swipe(call: CallbackQuery, bot: Bot, state: FSM, ar
|
|||||||
|
|
||||||
# Выбор текущей категории для редактирования
|
# Выбор текущей категории для редактирования
|
||||||
@router.callback_query(F.data.startswith("category_edit_open:"))
|
@router.callback_query(F.data.startswith("category_edit_open:"))
|
||||||
async def prod_category_edit_open(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_category_edit_open(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
category_id = int(call.data.split(":")[1])
|
category_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -167,7 +184,9 @@ async def prod_category_edit_open(call: CallbackQuery, bot: Bot, state: FSM, arS
|
|||||||
############################ САМО ИЗМЕНЕНИЕ КАТЕГОРИИ ##########################
|
############################ САМО ИЗМЕНЕНИЕ КАТЕГОРИИ ##########################
|
||||||
# Изменение названия категории
|
# Изменение названия категории
|
||||||
@router.callback_query(F.data.startswith("category_edit_name:"))
|
@router.callback_query(F.data.startswith("category_edit_name:"))
|
||||||
async def prod_category_edit_name(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_category_edit_name(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
category_id = int(call.data.split(":")[1])
|
category_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -184,10 +203,12 @@ async def prod_category_edit_name(call: CallbackQuery, bot: Bot, state: FSM, arS
|
|||||||
|
|
||||||
|
|
||||||
# Принятие нового названия для категории
|
# Принятие нового названия для категории
|
||||||
@router.message(F.text, StateFilter('here_category_edit_name'))
|
@router.message(F.text, StateFilter("here_category_edit_name"))
|
||||||
async def prod_category_edit_name_get(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_category_edit_name_get(
|
||||||
category_id = (await state.get_data())['here_category_id']
|
message: Message, bot: Bot, state: FSM, arSession: ARS
|
||||||
remover = (await state.get_data())['here_remover']
|
):
|
||||||
|
category_id = (await state.get_data())["here_category_id"]
|
||||||
|
remover = (await state.get_data())["here_remover"]
|
||||||
|
|
||||||
if len(message.text) > 50:
|
if len(message.text) > 50:
|
||||||
return await message.answer(
|
return await message.answer(
|
||||||
@@ -204,7 +225,9 @@ async def prod_category_edit_name_get(message: Message, bot: Bot, state: FSM, ar
|
|||||||
|
|
||||||
# Удаление категории
|
# Удаление категории
|
||||||
@router.callback_query(F.data.startswith("category_edit_delete:"))
|
@router.callback_query(F.data.startswith("category_edit_delete:"))
|
||||||
async def prod_category_edit_delete(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_category_edit_delete(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
category_id = int(call.data.split(":")[1])
|
category_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -216,7 +239,9 @@ async def prod_category_edit_delete(call: CallbackQuery, bot: Bot, state: FSM, a
|
|||||||
|
|
||||||
# Подтверждение удаления категории
|
# Подтверждение удаления категории
|
||||||
@router.callback_query(F.data.startswith("category_edit_delete_confirm:"))
|
@router.callback_query(F.data.startswith("category_edit_delete_confirm:"))
|
||||||
async def prod_category_edit_delete_confirm(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_category_edit_delete_confirm(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
category_id = int(call.data.split(":")[1])
|
category_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -241,7 +266,9 @@ async def prod_category_edit_delete_confirm(call: CallbackQuery, bot: Bot, state
|
|||||||
############################### ДОБАВЛЕНИЕ ПОЗИЦИИ #############################
|
############################### ДОБАВЛЕНИЕ ПОЗИЦИИ #############################
|
||||||
# Cтраницы выбора категорий для расположения позиции
|
# Cтраницы выбора категорий для расположения позиции
|
||||||
@router.callback_query(F.data.startswith("position_add_swipe:"))
|
@router.callback_query(F.data.startswith("position_add_swipe:"))
|
||||||
async def prod_position_add_swipe(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_add_swipe(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
remover = int(call.data.split(":")[1])
|
remover = int(call.data.split(":")[1])
|
||||||
|
|
||||||
await call.message.edit_text(
|
await call.message.edit_text(
|
||||||
@@ -252,7 +279,9 @@ async def prod_position_add_swipe(call: CallbackQuery, bot: Bot, state: FSM, arS
|
|||||||
|
|
||||||
# Выбор категории для создания позиции
|
# Выбор категории для создания позиции
|
||||||
@router.callback_query(F.data.startswith("position_add_open:"))
|
@router.callback_query(F.data.startswith("position_add_open:"))
|
||||||
async def prod_position_add_open(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_add_open(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
category_id = int(call.data.split(":")[1])
|
category_id = int(call.data.split(":")[1])
|
||||||
|
|
||||||
await state.update_data(here_category_id=category_id)
|
await state.update_data(here_category_id=category_id)
|
||||||
@@ -262,8 +291,10 @@ async def prod_position_add_open(call: CallbackQuery, bot: Bot, state: FSM, arSe
|
|||||||
|
|
||||||
|
|
||||||
# Принятие названия для создания позиции
|
# Принятие названия для создания позиции
|
||||||
@router.message(F.text, StateFilter('here_position_name'))
|
@router.message(F.text, StateFilter("here_position_name"))
|
||||||
async def prod_position_add_name_get(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_add_name_get(
|
||||||
|
message: Message, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
if len(message.text) > 50:
|
if len(message.text) > 50:
|
||||||
return await message.answer(
|
return await message.answer(
|
||||||
"<b>❌ Название не может превышать 50 символов</b>\n"
|
"<b>❌ Название не может превышать 50 символов</b>\n"
|
||||||
@@ -277,12 +308,13 @@ async def prod_position_add_name_get(message: Message, bot: Bot, state: FSM, arS
|
|||||||
|
|
||||||
|
|
||||||
# Принятие цены позиции для её создания
|
# Принятие цены позиции для её создания
|
||||||
@router.message(F.text, StateFilter('here_position_price'))
|
@router.message(F.text, StateFilter("here_position_price"))
|
||||||
async def prod_position_add_price_get(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_add_price_get(
|
||||||
|
message: Message, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
if not is_number(message.text):
|
if not is_number(message.text):
|
||||||
return await message.answer(
|
return await message.answer(
|
||||||
"<b>❌ Данные были введены неверно</b>\n"
|
"<b>❌ Данные были введены неверно</b>\n" "📁 Введите цену для позиции",
|
||||||
"📁 Введите цену для позиции",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if to_number(message.text) > 10_000_000 or to_number(message.text) < 0:
|
if to_number(message.text) > 10_000_000 or to_number(message.text) < 0:
|
||||||
@@ -291,11 +323,10 @@ async def prod_position_add_price_get(message: Message, bot: Bot, state: FSM, ar
|
|||||||
"📁 Введите цену для позиции",
|
"📁 Введите цену для позиции",
|
||||||
)
|
)
|
||||||
|
|
||||||
category_id = (await state.get_data())['here_category_id']
|
category_id = (await state.get_data())["here_category_id"]
|
||||||
position_name = (await state.get_data())['here_position_name']
|
position_name = (await state.get_data())["here_position_name"]
|
||||||
position_price = to_number(message.text)
|
position_price = to_number(message.text)
|
||||||
position_desc = "None"
|
position_desc = "None"
|
||||||
position_photo = "None"
|
|
||||||
position_id = gen_id(12)
|
position_id = gen_id(12)
|
||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
@@ -305,7 +336,6 @@ async def prod_position_add_price_get(message: Message, bot: Bot, state: FSM, ar
|
|||||||
position_name=position_name,
|
position_name=position_name,
|
||||||
position_price=position_price,
|
position_price=position_price,
|
||||||
position_desc=position_desc,
|
position_desc=position_desc,
|
||||||
position_photo=position_photo,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await position_open_admin(bot, position_id, message.from_user.id)
|
await position_open_admin(bot, position_id, message.from_user.id)
|
||||||
@@ -315,7 +345,9 @@ async def prod_position_add_price_get(message: Message, bot: Bot, state: FSM, ar
|
|||||||
############################ РЕДАКТИРОВАНИЕ ПОЗИЦИИ ############################
|
############################ РЕДАКТИРОВАНИЕ ПОЗИЦИИ ############################
|
||||||
# Страницы выбора категории для редактирования позиции
|
# Страницы выбора категории для редактирования позиции
|
||||||
@router.callback_query(F.data.startswith("position_edit_category_swipe:"))
|
@router.callback_query(F.data.startswith("position_edit_category_swipe:"))
|
||||||
async def prod_position_edit_category_swipe(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_category_swipe(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
remover = int(call.data.split(":")[1])
|
remover = int(call.data.split(":")[1])
|
||||||
|
|
||||||
await call.message.edit_text(
|
await call.message.edit_text(
|
||||||
@@ -326,7 +358,9 @@ async def prod_position_edit_category_swipe(call: CallbackQuery, bot: Bot, state
|
|||||||
|
|
||||||
# Открытие категории для выбора позиции
|
# Открытие категории для выбора позиции
|
||||||
@router.callback_query(F.data.startswith("position_edit_category_open:"))
|
@router.callback_query(F.data.startswith("position_edit_category_open:"))
|
||||||
async def prod_position_edit_category_open(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_category_open(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
category_id = int(call.data.split(":")[1])
|
category_id = int(call.data.split(":")[1])
|
||||||
|
|
||||||
get_category = await Categoryx().get_required(category_id=category_id)
|
get_category = await Categoryx().get_required(category_id=category_id)
|
||||||
@@ -338,12 +372,16 @@ async def prod_position_edit_category_open(call: CallbackQuery, bot: Bot, state:
|
|||||||
reply_markup=await position_edit_swipe_fp(0, category_id),
|
reply_markup=await position_edit_swipe_fp(0, category_id),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await call.answer(f"📁 Позиции в категории {get_category.category_name} отсутствуют")
|
await call.answer(
|
||||||
|
f"📁 Позиции в категории {get_category.category_name} отсутствуют"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Страницы выбора позиции для редактирования
|
# Страницы выбора позиции для редактирования
|
||||||
@router.callback_query(F.data.startswith("position_edit_swipe:"))
|
@router.callback_query(F.data.startswith("position_edit_swipe:"))
|
||||||
async def prod_position_edit_swipe(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_swipe(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
category_id = int(call.data.split(":")[1])
|
category_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -357,7 +395,9 @@ async def prod_position_edit_swipe(call: CallbackQuery, bot: Bot, state: FSM, ar
|
|||||||
|
|
||||||
# Выбор позиции для редактирования
|
# Выбор позиции для редактирования
|
||||||
@router.callback_query(F.data.startswith("position_edit_open:"))
|
@router.callback_query(F.data.startswith("position_edit_open:"))
|
||||||
async def prod_position_edit_open(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_open(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
position_id = int(call.data.split(":")[1])
|
position_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -370,7 +410,9 @@ async def prod_position_edit_open(call: CallbackQuery, bot: Bot, state: FSM, arS
|
|||||||
############################ САМО ИЗМЕНЕНИЕ ПОЗИЦИИ ############################
|
############################ САМО ИЗМЕНЕНИЕ ПОЗИЦИИ ############################
|
||||||
# Изменение названия позиции
|
# Изменение названия позиции
|
||||||
@router.callback_query(F.data.startswith("position_edit_name:"))
|
@router.callback_query(F.data.startswith("position_edit_name:"))
|
||||||
async def prod_position_edit_name(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_name(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
position_id = int(call.data.split(":")[1])
|
position_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -386,10 +428,12 @@ async def prod_position_edit_name(call: CallbackQuery, bot: Bot, state: FSM, arS
|
|||||||
|
|
||||||
|
|
||||||
# Принятие названия позиции для её изменения
|
# Принятие названия позиции для её изменения
|
||||||
@router.message(F.text, StateFilter('here_position_edit_name'))
|
@router.message(F.text, StateFilter("here_position_edit_name"))
|
||||||
async def prod_position_edit_name_get(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_name_get(
|
||||||
position_id = (await state.get_data())['here_position_id']
|
message: Message, bot: Bot, state: FSM, arSession: ARS
|
||||||
remover = (await state.get_data())['here_remover']
|
):
|
||||||
|
position_id = (await state.get_data())["here_position_id"]
|
||||||
|
remover = (await state.get_data())["here_remover"]
|
||||||
|
|
||||||
if len(message.text) > 50:
|
if len(message.text) > 50:
|
||||||
return await message.answer(
|
return await message.answer(
|
||||||
@@ -406,7 +450,9 @@ async def prod_position_edit_name_get(message: Message, bot: Bot, state: FSM, ar
|
|||||||
|
|
||||||
# Изменение цены позиции
|
# Изменение цены позиции
|
||||||
@router.callback_query(F.data.startswith("position_edit_price:"))
|
@router.callback_query(F.data.startswith("position_edit_price:"))
|
||||||
async def prod_position_edit_price(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_price(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
position_id = int(call.data.split(":")[1])
|
position_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -422,10 +468,12 @@ async def prod_position_edit_price(call: CallbackQuery, bot: Bot, state: FSM, ar
|
|||||||
|
|
||||||
|
|
||||||
# Принятие цены позиции для её изменения
|
# Принятие цены позиции для её изменения
|
||||||
@router.message(F.text, StateFilter('here_position_edit_price'))
|
@router.message(F.text, StateFilter("here_position_edit_price"))
|
||||||
async def prod_position_edit_price_get(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_price_get(
|
||||||
position_id = (await state.get_data())['here_position_id']
|
message: Message, bot: Bot, state: FSM, arSession: ARS
|
||||||
remover = (await state.get_data())['here_remover']
|
):
|
||||||
|
position_id = (await state.get_data())["here_position_id"]
|
||||||
|
remover = (await state.get_data())["here_remover"]
|
||||||
|
|
||||||
if not is_number(message.text):
|
if not is_number(message.text):
|
||||||
return await message.answer(
|
return await message.answer(
|
||||||
@@ -449,7 +497,9 @@ async def prod_position_edit_price_get(message: Message, bot: Bot, state: FSM, a
|
|||||||
|
|
||||||
# Изменение описания позиции
|
# Изменение описания позиции
|
||||||
@router.callback_query(F.data.startswith("position_edit_desc:"))
|
@router.callback_query(F.data.startswith("position_edit_desc:"))
|
||||||
async def prod_position_edit_desc(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_desc(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
position_id = int(call.data.split(":")[1])
|
position_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -469,10 +519,12 @@ async def prod_position_edit_desc(call: CallbackQuery, bot: Bot, state: FSM, arS
|
|||||||
|
|
||||||
|
|
||||||
# Принятие описания позиции для её изменения
|
# Принятие описания позиции для её изменения
|
||||||
@router.message(F.text, StateFilter('here_position_edit_desc'))
|
@router.message(F.text, StateFilter("here_position_edit_desc"))
|
||||||
async def prod_position_edit_desc_get(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_desc_get(
|
||||||
position_id = (await state.get_data())['here_position_id']
|
message: Message, bot: Bot, state: FSM, arSession: ARS
|
||||||
remover = (await state.get_data())['here_remover']
|
):
|
||||||
|
position_id = (await state.get_data())["here_position_id"]
|
||||||
|
remover = (await state.get_data())["here_remover"]
|
||||||
|
|
||||||
if len(message.text) > 1200:
|
if len(message.text) > 1200:
|
||||||
return await message.answer(
|
return await message.answer(
|
||||||
@@ -510,74 +562,11 @@ async def prod_position_edit_desc_get(message: Message, bot: Bot, state: FSM, ar
|
|||||||
await position_open_admin(bot, position_id, message.from_user.id)
|
await position_open_admin(bot, position_id, message.from_user.id)
|
||||||
|
|
||||||
|
|
||||||
# Изменение изображения позиции
|
|
||||||
@router.callback_query(F.data.startswith("position_edit_photo:"))
|
|
||||||
async def prod_position_edit_photo(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
|
||||||
position_id = int(call.data.split(":")[1])
|
|
||||||
remover = int(call.data.split(":")[2])
|
|
||||||
|
|
||||||
get_settings = await Settingsx().get()
|
|
||||||
|
|
||||||
if get_settings.misc_discord_webhook_url == "None":
|
|
||||||
return await call.answer("🧿 Отсутствует Дискорд вебхук, добавьте его в настройках", True)
|
|
||||||
|
|
||||||
await state.update_data(here_position_id=position_id)
|
|
||||||
await state.update_data(here_remover=remover)
|
|
||||||
await state.set_state("here_position_edit_photo")
|
|
||||||
|
|
||||||
await del_message(call.message)
|
|
||||||
await call.message.answer(
|
|
||||||
"<b>📁 Отправьте новое изображение для позиции</b>\n"
|
|
||||||
"❕ Отправьте <code>0</code> чтобы пропустить.",
|
|
||||||
reply_markup=position_edit_cancel_finl(position_id, remover),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Принятие нового фото для позиции
|
|
||||||
@router.message((F.text == "0") | F.photo, StateFilter('here_position_edit_photo'))
|
|
||||||
async def prod_position_edit_photo_get(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
|
||||||
position_id = (await state.get_data())['here_position_id']
|
|
||||||
remover = (await state.get_data())['here_remover']
|
|
||||||
|
|
||||||
get_settings = await Settingsx().get()
|
|
||||||
|
|
||||||
if get_settings.misc_discord_webhook_url == "None":
|
|
||||||
return await message.answer(
|
|
||||||
"<b>🧿 Отсутствует Дискорд вебхук, добавьте его в настройках</b>"
|
|
||||||
)
|
|
||||||
|
|
||||||
position_photo = "None"
|
|
||||||
|
|
||||||
if message.photo is not None:
|
|
||||||
cache_message = await message.answer(
|
|
||||||
"<b>♻️ Подождите, фотография загружается...</b>"
|
|
||||||
)
|
|
||||||
|
|
||||||
file_path = (await bot.get_file(message.photo[-1].file_id)).file_path
|
|
||||||
photo_path = await bot.download_file(file_path)
|
|
||||||
|
|
||||||
pay_image_status, pay_image_url = await (
|
|
||||||
await DiscordAPI.connect(
|
|
||||||
bot=bot,
|
|
||||||
arSession=arSession,
|
|
||||||
update=message,
|
|
||||||
)
|
|
||||||
).upload_photo(photo_path.read())
|
|
||||||
|
|
||||||
if pay_image_status:
|
|
||||||
position_photo = pay_image_url
|
|
||||||
|
|
||||||
await del_message(cache_message)
|
|
||||||
|
|
||||||
await state.clear()
|
|
||||||
|
|
||||||
await Positionx().update(position_id, position_photo=position_photo)
|
|
||||||
await position_open_admin(bot, position_id, message.from_user.id)
|
|
||||||
|
|
||||||
|
|
||||||
# Выгрузка товаров
|
# Выгрузка товаров
|
||||||
@router.callback_query(F.data.startswith("position_edit_items:"))
|
@router.callback_query(F.data.startswith("position_edit_items:"))
|
||||||
async def prod_position_edit_items(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_items(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
position_id = int(call.data.split(":")[1])
|
position_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -607,7 +596,9 @@ async def prod_position_edit_items(call: CallbackQuery, bot: Bot, state: FSM, ar
|
|||||||
|
|
||||||
# Удаление позиции
|
# Удаление позиции
|
||||||
@router.callback_query(F.data.startswith("position_edit_delete:"))
|
@router.callback_query(F.data.startswith("position_edit_delete:"))
|
||||||
async def prod_position_edit_delete(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_delete(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
position_id = int(call.data.split(":")[1])
|
position_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -621,7 +612,9 @@ async def prod_position_edit_delete(call: CallbackQuery, bot: Bot, state: FSM, a
|
|||||||
|
|
||||||
# Подтверждение удаления позиции
|
# Подтверждение удаления позиции
|
||||||
@router.callback_query(F.data.startswith("position_edit_delete_confirm:"))
|
@router.callback_query(F.data.startswith("position_edit_delete_confirm:"))
|
||||||
async def prod_position_edit_delete_confirm(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_delete_confirm(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
position_id = int(call.data.split(":")[1])
|
position_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -636,7 +629,9 @@ async def prod_position_edit_delete_confirm(call: CallbackQuery, bot: Bot, state
|
|||||||
if len(get_positions) >= 1:
|
if len(get_positions) >= 1:
|
||||||
await call.message.edit_text(
|
await call.message.edit_text(
|
||||||
"<b>📁 Выберите позицию для изменения 🖍</b>",
|
"<b>📁 Выберите позицию для изменения 🖍</b>",
|
||||||
reply_markup=await position_edit_swipe_fp(remover, get_position.category_id),
|
reply_markup=await position_edit_swipe_fp(
|
||||||
|
remover, get_position.category_id
|
||||||
|
),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await del_message(call.message)
|
await del_message(call.message)
|
||||||
@@ -644,7 +639,9 @@ async def prod_position_edit_delete_confirm(call: CallbackQuery, bot: Bot, state
|
|||||||
|
|
||||||
# Очистка позиции
|
# Очистка позиции
|
||||||
@router.callback_query(F.data.startswith("position_edit_clear:"))
|
@router.callback_query(F.data.startswith("position_edit_clear:"))
|
||||||
async def prod_position_edit_clear(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_clear(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
position_id = int(call.data.split(":")[1])
|
position_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -657,7 +654,9 @@ async def prod_position_edit_clear(call: CallbackQuery, bot: Bot, state: FSM, ar
|
|||||||
|
|
||||||
# Согласие на очистку позиции
|
# Согласие на очистку позиции
|
||||||
@router.callback_query(F.data.startswith("position_edit_clear_confirm:"))
|
@router.callback_query(F.data.startswith("position_edit_clear_confirm:"))
|
||||||
async def prod_position_edit_clear_confirm(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_edit_clear_confirm(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
position_id = int(call.data.split(":")[1])
|
position_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -672,7 +671,9 @@ async def prod_position_edit_clear_confirm(call: CallbackQuery, bot: Bot, state:
|
|||||||
############################### ДОБАВЛЕНИЕ ТОВАРОВ #############################
|
############################### ДОБАВЛЕНИЕ ТОВАРОВ #############################
|
||||||
# Страницы выбора категории для добавления товара
|
# Страницы выбора категории для добавления товара
|
||||||
@router.callback_query(F.data.startswith("item_add_category_swipe:"))
|
@router.callback_query(F.data.startswith("item_add_category_swipe:"))
|
||||||
async def prod_item_add_category_swipe(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_item_add_category_swipe(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
remover = int(call.data.split(":")[1])
|
remover = int(call.data.split(":")[1])
|
||||||
|
|
||||||
await call.message.edit_text(
|
await call.message.edit_text(
|
||||||
@@ -683,7 +684,9 @@ async def prod_item_add_category_swipe(call: CallbackQuery, bot: Bot, state: FSM
|
|||||||
|
|
||||||
# Открытие категории для выбора позиции
|
# Открытие категории для выбора позиции
|
||||||
@router.callback_query(F.data.startswith("item_add_category_open:"))
|
@router.callback_query(F.data.startswith("item_add_category_open:"))
|
||||||
async def prod_item_add_category_open(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_item_add_category_open(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
category_id = int(call.data.split(":")[1])
|
category_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -698,12 +701,16 @@ async def prod_item_add_category_open(call: CallbackQuery, bot: Bot, state: FSM,
|
|||||||
reply_markup=await item_add_position_swipe_fp(0, category_id),
|
reply_markup=await item_add_position_swipe_fp(0, category_id),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await call.answer(f"🎁 Позиции в категории {get_category.category_name} отсутствуют")
|
await call.answer(
|
||||||
|
f"🎁 Позиции в категории {get_category.category_name} отсутствуют"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Страницы выбора позиции для добавления товара
|
# Страницы выбора позиции для добавления товара
|
||||||
@router.callback_query(F.data.startswith("item_add_position_swipe:"))
|
@router.callback_query(F.data.startswith("item_add_position_swipe:"))
|
||||||
async def prod_item_add_position_swipe(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_item_add_position_swipe(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
category_id = int(call.data.split(":")[1])
|
category_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -714,8 +721,10 @@ async def prod_item_add_position_swipe(call: CallbackQuery, bot: Bot, state: FSM
|
|||||||
|
|
||||||
|
|
||||||
# Выбор позиции для добавления товаров
|
# Выбор позиции для добавления товаров
|
||||||
@router.callback_query(F.data.startswith("item_add_position_open:"), flags={'rate': 0})
|
@router.callback_query(F.data.startswith("item_add_position_open:"), flags={"rate": 0})
|
||||||
async def prod_item_add_position_open(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_item_add_position_open(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
position_id = int(call.data.split(":")[1])
|
position_id = int(call.data.split(":")[1])
|
||||||
|
|
||||||
get_position = await Positionx().get_required(position_id=position_id)
|
get_position = await Positionx().get_required(position_id=position_id)
|
||||||
@@ -755,12 +764,16 @@ async def prod_item_add_position_open(call: CallbackQuery, bot: Bot, state: FSM,
|
|||||||
|
|
||||||
|
|
||||||
# Завершение загрузки товаров
|
# Завершение загрузки товаров
|
||||||
@router.callback_query(F.data.startswith('item_add_position_finish:'), flags={'rate': 0})
|
@router.callback_query(
|
||||||
async def prod_item_add_finish(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
F.data.startswith("item_add_position_finish:"), flags={"rate": 0}
|
||||||
|
)
|
||||||
|
async def prod_item_add_finish(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
position_id = int(call.data.split(":")[1])
|
position_id = int(call.data.split(":")[1])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
count_items = (await state.get_data())['here_add_item_count']
|
count_items = (await state.get_data())["here_add_item_count"]
|
||||||
except Exception:
|
except Exception:
|
||||||
bot_logger.debug("В state нет счетчика добавленных товаров", exc_info=True)
|
bot_logger.debug("В state нет счетчика добавленных товаров", exc_info=True)
|
||||||
count_items = 0
|
count_items = 0
|
||||||
@@ -777,7 +790,7 @@ async def prod_item_add_finish(call: CallbackQuery, bot: Bot, state: FSM, arSess
|
|||||||
|
|
||||||
|
|
||||||
# Принятие данных товара
|
# Принятие данных товара
|
||||||
@router.message(F.text, StateFilter('here_add_items'), flags={'rate': 0})
|
@router.message(F.text, StateFilter("here_add_items"), flags={"rate": 0})
|
||||||
async def prod_item_add_get(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_item_add_get(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
||||||
cache_message = await message.answer("<b>⌛ Ждите, товары добавляются..</b>")
|
cache_message = await message.answer("<b>⌛ Ждите, товары добавляются..</b>")
|
||||||
|
|
||||||
@@ -788,9 +801,9 @@ async def prod_item_add_get(message: Message, bot: Bot, state: FSM, arSession: A
|
|||||||
else:
|
else:
|
||||||
get_items = clear_list(message.text.split("\n"))
|
get_items = clear_list(message.text.split("\n"))
|
||||||
|
|
||||||
item_count = (await state.get_data())['here_add_item_count']
|
item_count = (await state.get_data())["here_add_item_count"]
|
||||||
category_id = (await state.get_data())['here_add_item_category_id']
|
category_id = (await state.get_data())["here_add_item_category_id"]
|
||||||
position_id = (await state.get_data())['here_add_item_position_id']
|
position_id = (await state.get_data())["here_add_item_position_id"]
|
||||||
|
|
||||||
await state.update_data(here_add_item_count=item_count + len(get_items))
|
await state.update_data(here_add_item_count=item_count + len(get_items))
|
||||||
|
|
||||||
@@ -811,7 +824,9 @@ async def prod_item_add_get(message: Message, bot: Bot, state: FSM, arSession: A
|
|||||||
############################### УДАЛЕНИЕ ТОВАРОВ ###############################
|
############################### УДАЛЕНИЕ ТОВАРОВ ###############################
|
||||||
# Страницы удаления товаров
|
# Страницы удаления товаров
|
||||||
@router.callback_query(F.data.startswith("item_delete_swipe:"))
|
@router.callback_query(F.data.startswith("item_delete_swipe:"))
|
||||||
async def prod_item_delete_swipe(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_item_delete_swipe(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
position_id = int(call.data.split(":")[1])
|
position_id = int(call.data.split(":")[1])
|
||||||
remover = int(call.data.split(":")[2])
|
remover = int(call.data.split(":")[2])
|
||||||
|
|
||||||
@@ -826,12 +841,16 @@ async def prod_item_delete_swipe(call: CallbackQuery, bot: Bot, state: FSM, arSe
|
|||||||
reply_markup=await item_delete_swipe_fp(remover, position_id),
|
reply_markup=await item_delete_swipe_fp(remover, position_id),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await call.answer(f"🎁 Товары в позиции {get_position.position_name} отсутствуют", True)
|
await call.answer(
|
||||||
|
f"🎁 Товары в позиции {get_position.position_name} отсутствуют", True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Удаление товара
|
# Удаление товара
|
||||||
@router.callback_query(F.data.startswith("item_delete_open:"))
|
@router.callback_query(F.data.startswith("item_delete_open:"))
|
||||||
async def prod_item_delete_open(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_item_delete_open(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
item_id = int(call.data.split(":")[1])
|
item_id = int(call.data.split(":")[1])
|
||||||
|
|
||||||
await del_message(call.message)
|
await del_message(call.message)
|
||||||
@@ -840,7 +859,9 @@ async def prod_item_delete_open(call: CallbackQuery, bot: Bot, state: FSM, arSes
|
|||||||
|
|
||||||
# Подтверждение удаления товара
|
# Подтверждение удаления товара
|
||||||
@router.callback_query(F.data.startswith("item_delete_confirm:"))
|
@router.callback_query(F.data.startswith("item_delete_confirm:"))
|
||||||
async def prod_item_delete_confirm_open(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_item_delete_confirm_open(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
item_id = int(call.data.split(":")[1])
|
item_id = int(call.data.split(":")[1])
|
||||||
|
|
||||||
get_item = await Itemx().get_required(item_id=item_id)
|
get_item = await Itemx().get_required(item_id=item_id)
|
||||||
@@ -862,7 +883,9 @@ async def prod_item_delete_confirm_open(call: CallbackQuery, bot: Bot, state: FS
|
|||||||
############################### УДАЛЕНИЕ РАЗДЕЛОВ ##############################
|
############################### УДАЛЕНИЕ РАЗДЕЛОВ ##############################
|
||||||
# Возвращение к меню удаления разделов
|
# Возвращение к меню удаления разделов
|
||||||
@router.callback_query(F.data == "prod_removes_return")
|
@router.callback_query(F.data == "prod_removes_return")
|
||||||
async def prod_removes_return(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_removes_return(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
await call.message.edit_text(
|
await call.message.edit_text(
|
||||||
@@ -873,7 +896,9 @@ async def prod_removes_return(call: CallbackQuery, bot: Bot, state: FSM, arSessi
|
|||||||
|
|
||||||
# Удаление всех категорий
|
# Удаление всех категорий
|
||||||
@router.callback_query(F.data == "prod_removes_categories")
|
@router.callback_query(F.data == "prod_removes_categories")
|
||||||
async def prod_removes_categories(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_removes_categories(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
get_categories = len(await Categoryx().get_all())
|
get_categories = len(await Categoryx().get_all())
|
||||||
get_positions = len(await Positionx().get_all())
|
get_positions = len(await Positionx().get_all())
|
||||||
get_items = len(await Itemx().get_all())
|
get_items = len(await Itemx().get_all())
|
||||||
@@ -891,7 +916,9 @@ async def prod_removes_categories(call: CallbackQuery, bot: Bot, state: FSM, arS
|
|||||||
|
|
||||||
# Подтверждение удаления всех категорий (позиций и товаров включительно)
|
# Подтверждение удаления всех категорий (позиций и товаров включительно)
|
||||||
@router.callback_query(F.data == "prod_removes_categories_confirm")
|
@router.callback_query(F.data == "prod_removes_categories_confirm")
|
||||||
async def prod_removes_categories_confirm(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_removes_categories_confirm(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
get_categories = len(await Categoryx().get_all())
|
get_categories = len(await Categoryx().get_all())
|
||||||
get_positions = len(await Positionx().get_all())
|
get_positions = len(await Positionx().get_all())
|
||||||
get_items = len(await Itemx().get_all())
|
get_items = len(await Itemx().get_all())
|
||||||
@@ -900,19 +927,19 @@ async def prod_removes_categories_confirm(call: CallbackQuery, bot: Bot, state:
|
|||||||
await Positionx().clear()
|
await Positionx().clear()
|
||||||
await Itemx().clear()
|
await Itemx().clear()
|
||||||
|
|
||||||
await call.message.edit_text(
|
await call.message.edit_text(ded(f"""
|
||||||
ded(f"""
|
|
||||||
<b>✅ Вы успешно удалили все категории</b>
|
<b>✅ Вы успешно удалили все категории</b>
|
||||||
🗃 Категорий: <code>{get_categories}шт</code>
|
🗃 Категорий: <code>{get_categories}шт</code>
|
||||||
📁 Позиций: <code>{get_positions}шт</code>
|
📁 Позиций: <code>{get_positions}шт</code>
|
||||||
🎁 Товаров: <code>{get_items}шт</code>
|
🎁 Товаров: <code>{get_items}шт</code>
|
||||||
""")
|
"""))
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Удаление всех позиций
|
# Удаление всех позиций
|
||||||
@router.callback_query(F.data == "prod_removes_positions")
|
@router.callback_query(F.data == "prod_removes_positions")
|
||||||
async def prod_removes_positions(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_removes_positions(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
get_positions = len(await Positionx().get_all())
|
get_positions = len(await Positionx().get_all())
|
||||||
get_items = len(await Itemx().get_all())
|
get_items = len(await Itemx().get_all())
|
||||||
|
|
||||||
@@ -928,20 +955,20 @@ async def prod_removes_positions(call: CallbackQuery, bot: Bot, state: FSM, arSe
|
|||||||
|
|
||||||
# Подтверждение удаления всех позиций (товаров включительно)
|
# Подтверждение удаления всех позиций (товаров включительно)
|
||||||
@router.callback_query(F.data == "prod_removes_positions_confirm")
|
@router.callback_query(F.data == "prod_removes_positions_confirm")
|
||||||
async def prod_position_remove(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def prod_position_remove(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
get_positions = len(await Positionx().get_all())
|
get_positions = len(await Positionx().get_all())
|
||||||
get_items = len(await Itemx().get_all())
|
get_items = len(await Itemx().get_all())
|
||||||
|
|
||||||
await Positionx().clear()
|
await Positionx().clear()
|
||||||
await Itemx().clear()
|
await Itemx().clear()
|
||||||
|
|
||||||
await call.message.edit_text(
|
await call.message.edit_text(ded(f"""
|
||||||
ded(f"""
|
|
||||||
<b>✅ Вы успешно удалили все позиции</b>
|
<b>✅ Вы успешно удалили все позиции</b>
|
||||||
📁 Позиций: <code>{get_positions}шт</code>
|
📁 Позиций: <code>{get_positions}шт</code>
|
||||||
🎁 Товаров: <code>{get_items}шт</code>
|
🎁 Товаров: <code>{get_items}шт</code>
|
||||||
""")
|
"""))
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Удаление всех товаров
|
# Удаление всех товаров
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from aiogram.types import CallbackQuery, Message
|
|||||||
|
|
||||||
from tgbot.database import Settingsx, Userx
|
from tgbot.database import Settingsx, Userx
|
||||||
from tgbot.keyboards.inline_admin import settings_status_finl, settings_finl
|
from tgbot.keyboards.inline_admin import settings_status_finl, settings_finl
|
||||||
from tgbot.services.api_discord import DiscordDJ, DiscordAPI
|
|
||||||
from tgbot.utils.const_functions import ded
|
from tgbot.utils.const_functions import ded
|
||||||
from tgbot.utils.misc.bot_logging import bot_logger
|
from tgbot.utils.misc.bot_logging import bot_logger
|
||||||
from tgbot.utils.misc.bot_models import FSM, ARS
|
from tgbot.utils.misc.bot_models import FSM, ARS
|
||||||
@@ -40,7 +39,9 @@ async def settings_status_edit(message: Message, bot: Bot, state: FSM, arSession
|
|||||||
################################## ВЫКЛЮЧАТЕЛИ #################################
|
################################## ВЫКЛЮЧАТЕЛИ #################################
|
||||||
# Включение/выключение тех работ
|
# Включение/выключение тех работ
|
||||||
@router.callback_query(F.data.startswith("settings_status_work:"))
|
@router.callback_query(F.data.startswith("settings_status_work:"))
|
||||||
async def settings_status_work(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def settings_status_work(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
get_status = call.data.split(":")[1]
|
get_status = call.data.split(":")[1]
|
||||||
|
|
||||||
get_user = await Userx().get_required(user_id=call.from_user.id)
|
get_user = await Userx().get_required(user_id=call.from_user.id)
|
||||||
@@ -65,7 +66,9 @@ async def settings_status_work(call: CallbackQuery, bot: Bot, state: FSM, arSess
|
|||||||
|
|
||||||
# Включение/выключение покупок
|
# Включение/выключение покупок
|
||||||
@router.callback_query(F.data.startswith("settings_status_buy:"))
|
@router.callback_query(F.data.startswith("settings_status_buy:"))
|
||||||
async def settings_status_buy(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def settings_status_buy(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
get_status = call.data.split(":")[1]
|
get_status = call.data.split(":")[1]
|
||||||
|
|
||||||
get_user = await Userx().get_required(user_id=call.from_user.id)
|
get_user = await Userx().get_required(user_id=call.from_user.id)
|
||||||
@@ -90,7 +93,9 @@ async def settings_status_buy(call: CallbackQuery, bot: Bot, state: FSM, arSessi
|
|||||||
|
|
||||||
# Включение/выключение пополнений
|
# Включение/выключение пополнений
|
||||||
@router.callback_query(F.data.startswith("settings_status_refill:"))
|
@router.callback_query(F.data.startswith("settings_status_refill:"))
|
||||||
async def settings_status_refill(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def settings_status_refill(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
get_status = call.data.split(":")[1]
|
get_status = call.data.split(":")[1]
|
||||||
|
|
||||||
get_user = await Userx().get_required(user_id=call.from_user.id)
|
get_user = await Userx().get_required(user_id=call.from_user.id)
|
||||||
@@ -113,7 +118,9 @@ async def settings_status_refill(call: CallbackQuery, bot: Bot, state: FSM, arSe
|
|||||||
|
|
||||||
# Включение/выключение уведомлений о покупках
|
# Включение/выключение уведомлений о покупках
|
||||||
@router.callback_query(F.data.startswith("settings_notification_buy:"))
|
@router.callback_query(F.data.startswith("settings_notification_buy:"))
|
||||||
async def settings_notification_buy(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def settings_notification_buy(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
get_status = call.data.split(":")[1]
|
get_status = call.data.split(":")[1]
|
||||||
|
|
||||||
get_user = await Userx().get_required(user_id=call.from_user.id)
|
get_user = await Userx().get_required(user_id=call.from_user.id)
|
||||||
@@ -136,7 +143,9 @@ async def settings_notification_buy(call: CallbackQuery, bot: Bot, state: FSM, a
|
|||||||
|
|
||||||
# Включение/выключение уведомлений о пополнениях
|
# Включение/выключение уведомлений о пополнениях
|
||||||
@router.callback_query(F.data.startswith("settings_notification_refill:"))
|
@router.callback_query(F.data.startswith("settings_notification_refill:"))
|
||||||
async def settings_notification_refill(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def settings_notification_refill(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
get_status = call.data.split(":")[1]
|
get_status = call.data.split(":")[1]
|
||||||
|
|
||||||
get_user = await Userx().get_required(user_id=call.from_user.id)
|
get_user = await Userx().get_required(user_id=call.from_user.id)
|
||||||
@@ -165,20 +174,20 @@ async def settings_faq_edit(call: CallbackQuery, bot: Bot, state: FSM, arSession
|
|||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
await state.set_state("here_settings_faq")
|
await state.set_state("here_settings_faq")
|
||||||
await call.message.edit_text(
|
await call.message.edit_text(ded("""
|
||||||
ded("""
|
|
||||||
<b>❔ Введите новый текст для FAQ</b>
|
<b>❔ Введите новый текст для FAQ</b>
|
||||||
❕ Вы можете использовать заготовленный синтаксис и HTML разметку:
|
❕ Вы можете использовать заготовленный синтаксис и HTML разметку:
|
||||||
▪️ <code>{username}</code> - логин пользоваля
|
▪️ <code>{username}</code> - логин пользоваля
|
||||||
▪️ <code>{user_id}</code> - айди пользователя
|
▪️ <code>{user_id}</code> - айди пользователя
|
||||||
▪️ <code>{firstname}</code> - имя пользователя
|
▪️ <code>{firstname}</code> - имя пользователя
|
||||||
""")
|
"""))
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Изменение поддержки
|
# Изменение поддержки
|
||||||
@router.callback_query(F.data == "settings_edit_support")
|
@router.callback_query(F.data == "settings_edit_support")
|
||||||
async def settings_support_edit(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def settings_support_edit(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
await state.set_state("here_settings_support")
|
await state.set_state("here_settings_support")
|
||||||
@@ -190,7 +199,9 @@ async def settings_support_edit(call: CallbackQuery, bot: Bot, state: FSM, arSes
|
|||||||
|
|
||||||
# Изменение отображения/скрытия категорий без товаров
|
# Изменение отображения/скрытия категорий без товаров
|
||||||
@router.callback_query(F.data.startswith("settings_edit_hide_category:"))
|
@router.callback_query(F.data.startswith("settings_edit_hide_category:"))
|
||||||
async def settings_edit_hide_category(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def settings_edit_hide_category(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
status = call.data.split(":")[1]
|
status = call.data.split(":")[1]
|
||||||
|
|
||||||
await Settingsx().update(misc_hide_category=status)
|
await Settingsx().update(misc_hide_category=status)
|
||||||
@@ -203,7 +214,9 @@ async def settings_edit_hide_category(call: CallbackQuery, bot: Bot, state: FSM,
|
|||||||
|
|
||||||
# Изменение отображения/скрытия позиций без товаров
|
# Изменение отображения/скрытия позиций без товаров
|
||||||
@router.callback_query(F.data.startswith("settings_edit_hide_position:"))
|
@router.callback_query(F.data.startswith("settings_edit_hide_position:"))
|
||||||
async def settings_edit_hide_position(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def settings_edit_hide_position(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
status = call.data.split(":")[1]
|
status = call.data.split(":")[1]
|
||||||
|
|
||||||
await Settingsx().update(misc_hide_position=status)
|
await Settingsx().update(misc_hide_position=status)
|
||||||
@@ -216,7 +229,9 @@ async def settings_edit_hide_position(call: CallbackQuery, bot: Bot, state: FSM,
|
|||||||
|
|
||||||
# Изменение метода добавления товаров
|
# Изменение метода добавления товаров
|
||||||
@router.callback_query(F.data.startswith("settings_edit_method_prod:"))
|
@router.callback_query(F.data.startswith("settings_edit_method_prod:"))
|
||||||
async def settings_edit_method_prod(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def settings_edit_method_prod(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
method = call.data.split(":")[1]
|
method = call.data.split(":")[1]
|
||||||
|
|
||||||
await Settingsx().update(misc_method_prod=method)
|
await Settingsx().update(misc_method_prod=method)
|
||||||
@@ -227,32 +242,11 @@ async def settings_edit_method_prod(call: CallbackQuery, bot: Bot, state: FSM, a
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Изменение дискорд вебхука
|
|
||||||
@router.callback_query(F.data == "settings_edit_discord_webhook")
|
|
||||||
async def settings_discord_edit(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
|
||||||
await state.clear()
|
|
||||||
|
|
||||||
get_discord_public_webhook = await (
|
|
||||||
DiscordDJ(
|
|
||||||
arSession=arSession,
|
|
||||||
bot=bot,
|
|
||||||
)
|
|
||||||
).export_webhook()
|
|
||||||
|
|
||||||
await state.set_state("here_settings_discord_webhook")
|
|
||||||
await call.message.edit_text(
|
|
||||||
ded(f"""
|
|
||||||
<b>🧿 Отправьте новый вебхук дискорда</b>
|
|
||||||
❕ Для удаления вебхука введите <code>0</code>
|
|
||||||
❕ Вы можете использовать публичный вебхук, но ответственность за его использование лежит только на вас
|
|
||||||
▪️ Публичный вебхук: <code>{get_discord_public_webhook}</code>
|
|
||||||
""")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Изменение текстового хостинга по умолчанию
|
# Изменение текстового хостинга по умолчанию
|
||||||
@router.callback_query(F.data == "settings_edit_hosting_text")
|
@router.callback_query(F.data == "settings_edit_hosting_text")
|
||||||
async def settings_edit_hosting_text(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def settings_edit_hosting_text(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
get_settings = await Settingsx().get()
|
get_settings = await Settingsx().get()
|
||||||
|
|
||||||
if get_settings.misc_hosting_text == "telegraph":
|
if get_settings.misc_hosting_text == "telegraph":
|
||||||
@@ -282,8 +276,7 @@ async def settings_faq_get(message: Message, bot: Bot, state: FSM, arSession: AR
|
|||||||
except Exception:
|
except Exception:
|
||||||
bot_logger.debug("Некорректная HTML-разметка FAQ", exc_info=True)
|
bot_logger.debug("Некорректная HTML-разметка FAQ", exc_info=True)
|
||||||
return await message.answer(
|
return await message.answer(
|
||||||
"<b>❌ Ошибка синтаксиса HTML</b>\n"
|
"<b>❌ Ошибка синтаксиса HTML</b>\n" "❔ Введите новый текст для FAQ",
|
||||||
"❔ Введите новый текст для FAQ",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await state.clear()
|
await state.clear()
|
||||||
@@ -310,67 +303,3 @@ async def settings_support_get(message: Message, bot: Bot, state: FSM, arSession
|
|||||||
"<b>🖍 Изменение данных бота</b>",
|
"<b>🖍 Изменение данных бота</b>",
|
||||||
reply_markup=await settings_finl(),
|
reply_markup=await settings_finl(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Принятие дискорд вебхука
|
|
||||||
@router.message(F.text, StateFilter("here_settings_discord_webhook"))
|
|
||||||
async def settings_discord_get(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
|
||||||
get_discord_webhook = message.text
|
|
||||||
|
|
||||||
# Удаление вебхука
|
|
||||||
if get_discord_webhook == "0":
|
|
||||||
await Settingsx().update(
|
|
||||||
misc_discord_webhook_url="None",
|
|
||||||
misc_discord_webhook_name="None",
|
|
||||||
)
|
|
||||||
|
|
||||||
return await message.answer(
|
|
||||||
"<b>⚙️ Настройки бота</b>",
|
|
||||||
reply_markup=await settings_finl(),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Добавление нового вебхука
|
|
||||||
cache_message = await message.answer("<b>♻️ Проверка дискорд вебхука..</b>")
|
|
||||||
|
|
||||||
if "api" in get_discord_webhook and "webhooks" in get_discord_webhook:
|
|
||||||
discord_webhook_status, discord_webhook_name = await (
|
|
||||||
await DiscordAPI.connect(
|
|
||||||
bot=bot,
|
|
||||||
arSession=arSession,
|
|
||||||
update=message,
|
|
||||||
webhook_url=get_discord_webhook,
|
|
||||||
skipping_error=True,
|
|
||||||
)
|
|
||||||
).check()
|
|
||||||
|
|
||||||
if discord_webhook_status:
|
|
||||||
await state.clear()
|
|
||||||
|
|
||||||
await Settingsx().update(
|
|
||||||
misc_discord_webhook_url=message.text,
|
|
||||||
misc_discord_webhook_name=discord_webhook_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
return await cache_message.edit_text(
|
|
||||||
"<b>⚙️ Настройки бота</b>",
|
|
||||||
reply_markup=await settings_finl(),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Обработка ошибки добавления вебхука
|
|
||||||
get_discord_public_webhook = await (
|
|
||||||
DiscordDJ(
|
|
||||||
arSession=arSession,
|
|
||||||
bot=bot,
|
|
||||||
)
|
|
||||||
).export_webhook()
|
|
||||||
|
|
||||||
await cache_message.edit_text(
|
|
||||||
ded(f"""
|
|
||||||
<b>❌ Указан некорректный вебхук</b>
|
|
||||||
➖➖➖➖➖➖➖➖➖➖
|
|
||||||
🧿 Отправьте новый вебхук дискорда
|
|
||||||
❕ Для удаления вебхука введите <code>0</code>
|
|
||||||
❕ Вы можете использовать публичный вебхук, но ответственность за его использование лежит только на вас
|
|
||||||
▪️ Публичный вебхук: <code>{get_discord_public_webhook}</code>
|
|
||||||
""")
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from aiogram import Router, Bot, F
|
|||||||
from aiogram.filters import Command
|
from aiogram.filters import Command
|
||||||
from aiogram.types import CallbackQuery, Message
|
from aiogram.types import CallbackQuery, Message
|
||||||
|
|
||||||
from tgbot.data.config import BOT_VERSION, get_text_desc, get_text_warning
|
from tgbot.data.config import BOT_VERSION, get_text_desc
|
||||||
from tgbot.database import Purchasesx, Settingsx
|
from tgbot.database import Purchasesx, Settingsx
|
||||||
from tgbot.keyboards.inline_user import user_support_finl
|
from tgbot.keyboards.inline_user import user_support_finl
|
||||||
from tgbot.keyboards.inline_user_page import *
|
from tgbot.keyboards.inline_user_page import *
|
||||||
@@ -60,7 +60,7 @@ async def user_available(message: Message, bot: Bot, state: FSM, arSession: ARS)
|
|||||||
|
|
||||||
|
|
||||||
# Открытие FAQ
|
# Открытие FAQ
|
||||||
@router.message(F.text.in_(('❔ FAQ', '/faq')))
|
@router.message(F.text.in_(("❔ FAQ", "/faq")))
|
||||||
async def user_faq(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
async def user_faq(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
@@ -68,15 +68,7 @@ async def user_faq(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
|||||||
|
|
||||||
if get_settings.misc_faq == "None":
|
if get_settings.misc_faq == "None":
|
||||||
return await message.answer(
|
return await message.answer(
|
||||||
ded(f"""
|
ded(f"""❔ Текст FAQ не указан."""),
|
||||||
❔ Текст FAQ не указан. Измените его в настройках бота.
|
|
||||||
|
|
||||||
➖➖➖➖➖➖➖➖➖➖
|
|
||||||
{get_text_desc()}
|
|
||||||
|
|
||||||
➖➖➖➖➖➖➖➖➖➖
|
|
||||||
{get_text_warning()}
|
|
||||||
"""),
|
|
||||||
disable_web_page_preview=True,
|
disable_web_page_preview=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -87,7 +79,7 @@ async def user_faq(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
|||||||
|
|
||||||
|
|
||||||
# Открытие сообщения с ссылкой на поддержку
|
# Открытие сообщения с ссылкой на поддержку
|
||||||
@router.message(F.text.in_(('☎️ Поддержка', '/support')))
|
@router.message(F.text.in_(("☎️ Поддержка", "/support")))
|
||||||
async def user_support(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
async def user_support(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
@@ -95,15 +87,7 @@ async def user_support(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
|||||||
|
|
||||||
if get_settings.misc_support == "None":
|
if get_settings.misc_support == "None":
|
||||||
return await message.answer(
|
return await message.answer(
|
||||||
ded(f"""
|
ded(f"""☎️ Контакты поддержки не указаны."""),
|
||||||
☎️ Контакты поддержки не указаны. Измените их в настройках бота.
|
|
||||||
|
|
||||||
➖➖➖➖➖➖➖➖➖➖
|
|
||||||
{get_text_desc()}
|
|
||||||
|
|
||||||
➖➖➖➖➖➖➖➖➖➖
|
|
||||||
{get_text_warning()}
|
|
||||||
"""),
|
|
||||||
disable_web_page_preview=True,
|
disable_web_page_preview=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -114,7 +98,7 @@ async def user_support(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
|||||||
|
|
||||||
|
|
||||||
# Получение версии бота
|
# Получение версии бота
|
||||||
@router.message(Command(commands=['version']))
|
@router.message(Command(commands=["version"]))
|
||||||
async def admin_version(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
async def admin_version(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
@@ -122,7 +106,7 @@ async def admin_version(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
|||||||
|
|
||||||
|
|
||||||
# Получение информации о боте
|
# Получение информации о боте
|
||||||
@router.message(Command(commands=['dj_desc']))
|
@router.message(Command(commands=["dj_desc"]))
|
||||||
async def admin_desc(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
async def admin_desc(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
@@ -132,7 +116,9 @@ async def admin_desc(message: Message, bot: Bot, state: FSM, arSession: ARS):
|
|||||||
################################################################################
|
################################################################################
|
||||||
# Переход к профилю
|
# Переход к профилю
|
||||||
@router.callback_query(F.data == "user_profile")
|
@router.callback_query(F.data == "user_profile")
|
||||||
async def user_profile_return(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def user_profile_return(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
await del_message(call.message)
|
await del_message(call.message)
|
||||||
@@ -176,7 +162,9 @@ async def user_purchases(call: CallbackQuery, bot: Bot, state: FSM, arSession: A
|
|||||||
|
|
||||||
# Страницы наличия товаров
|
# Страницы наличия товаров
|
||||||
@router.callback_query(F.data.startswith("user_available_swipe:"))
|
@router.callback_query(F.data.startswith("user_available_swipe:"))
|
||||||
async def user_available_swipe(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS):
|
async def user_available_swipe(
|
||||||
|
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS
|
||||||
|
):
|
||||||
remover = int(call.data.split(":")[1])
|
remover = int(call.data.split(":")[1])
|
||||||
|
|
||||||
items_available, remover_max, remover_now = await get_items_available(remover)
|
items_available, remover_max, remover_now = await get_items_available(remover)
|
||||||
|
|||||||
@@ -1,239 +0,0 @@
|
|||||||
# - *- coding: utf- 8 - *-
|
|
||||||
import asyncio
|
|
||||||
import json
|
|
||||||
from io import BytesIO
|
|
||||||
from typing import Any, Dict, Optional, Tuple, Union
|
|
||||||
|
|
||||||
import ujson
|
|
||||||
from aiogram import Bot
|
|
||||||
from aiogram.types import CallbackQuery, Message
|
|
||||||
from aiohttp import ClientConnectorCertificateError, FormData
|
|
||||||
|
|
||||||
from tgbot.database import Settingsx
|
|
||||||
from tgbot.utils.const_functions import gen_id, send_errors
|
|
||||||
from tgbot.utils.misc.bot_logging import bot_logger
|
|
||||||
from tgbot.utils.misc.bot_models import ARS
|
|
||||||
from tgbot.utils.misc_functions import send_admins
|
|
||||||
|
|
||||||
|
|
||||||
class DiscordAPI:
|
|
||||||
# Настройка клиента Discord webhook
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
bot: Bot,
|
|
||||||
arSession: ARS,
|
|
||||||
update: Optional[Union[Message, CallbackQuery]] = None,
|
|
||||||
webhook_url: str = "None",
|
|
||||||
adding: bool = False,
|
|
||||||
skipping_error: bool = False,
|
|
||||||
):
|
|
||||||
self.bot = bot
|
|
||||||
self.arSession = arSession
|
|
||||||
self.update = update
|
|
||||||
self.adding = adding
|
|
||||||
self.skipping_error = skipping_error
|
|
||||||
|
|
||||||
self.webhook_username = "Djimbo Shop | Free Bot"
|
|
||||||
self.base_url = "https://djimbo.dev/dsapi"
|
|
||||||
|
|
||||||
webhook_url = self._normalize_webhook_url(webhook_url)
|
|
||||||
|
|
||||||
if "/" in webhook_url:
|
|
||||||
self.webhook_id = webhook_url.split("/")[0]
|
|
||||||
self.webhook_token = webhook_url.split("/")[1]
|
|
||||||
else:
|
|
||||||
self.webhook_id = ""
|
|
||||||
self.webhook_token = ""
|
|
||||||
|
|
||||||
# Нормализация Discord webhook URL
|
|
||||||
@staticmethod
|
|
||||||
def _normalize_webhook_url(webhook_url: str) -> str:
|
|
||||||
if webhook_url is None:
|
|
||||||
return "None"
|
|
||||||
|
|
||||||
if webhook_url.startswith("https://discord.com/api/"):
|
|
||||||
webhook_url = webhook_url[33:]
|
|
||||||
if webhook_url.startswith("discord.com/api/webhooks/"):
|
|
||||||
webhook_url = webhook_url[25:]
|
|
||||||
|
|
||||||
return webhook_url
|
|
||||||
|
|
||||||
# Инициализация данных
|
|
||||||
@classmethod
|
|
||||||
async def connect(
|
|
||||||
cls,
|
|
||||||
bot: Bot,
|
|
||||||
arSession: ARS,
|
|
||||||
update: Optional[Union[Message, CallbackQuery]] = None,
|
|
||||||
webhook_url: Optional[str] = None,
|
|
||||||
skipping_error: bool = False,
|
|
||||||
) -> "DiscordAPI":
|
|
||||||
adding = webhook_url is not None
|
|
||||||
|
|
||||||
if webhook_url is None:
|
|
||||||
settings = await Settingsx().get()
|
|
||||||
webhook_url = settings.misc_discord_webhook_url
|
|
||||||
adding = False
|
|
||||||
|
|
||||||
return cls(
|
|
||||||
bot=bot,
|
|
||||||
arSession=arSession,
|
|
||||||
update=update,
|
|
||||||
webhook_url=webhook_url,
|
|
||||||
adding=adding,
|
|
||||||
skipping_error=skipping_error,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Рассылка админам о нерабочем вебхуке
|
|
||||||
async def error_account_admin(self, error_code: str = "Unknown"):
|
|
||||||
bot_logger.warning("Discord webhook недоступен: %s", error_code)
|
|
||||||
|
|
||||||
if not self.skipping_error:
|
|
||||||
await send_admins(
|
|
||||||
self.bot,
|
|
||||||
f"<b>🧿 Дискорд вебхук недоступен. Как можно быстрее его замените</b>\n"
|
|
||||||
f"❗️ Ошибка: <code>{error_code}</code>"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Проверка вебхука
|
|
||||||
async def check(self) -> Tuple[bool, str]:
|
|
||||||
request_url = f"{self.base_url}/webhooks/{self.webhook_id}/{self.webhook_token}"
|
|
||||||
|
|
||||||
status, response = await self._request(
|
|
||||||
request_url=request_url,
|
|
||||||
request_method="GET",
|
|
||||||
)
|
|
||||||
|
|
||||||
if status and "channel_id" in response:
|
|
||||||
discord_channel_id = response['channel_id']
|
|
||||||
discord_hook_name = response['name']
|
|
||||||
|
|
||||||
return True, discord_hook_name
|
|
||||||
|
|
||||||
return False, ""
|
|
||||||
|
|
||||||
# Загрузка фотографий
|
|
||||||
async def upload_photo(self, photo_data: Union[BytesIO, bytes], photo_name: Optional[str] = None) -> Tuple[
|
|
||||||
bool, str]:
|
|
||||||
request_url = f"{self.base_url}/webhooks/{self.webhook_id}/{self.webhook_token}"
|
|
||||||
|
|
||||||
if photo_name is None:
|
|
||||||
photo_name = str(gen_id(24))
|
|
||||||
|
|
||||||
if not photo_name.endswith(".png") and not photo_name.endswith(".jpg"):
|
|
||||||
photo_name = f"{photo_name}.png"
|
|
||||||
|
|
||||||
send_json = {
|
|
||||||
'username': self.webhook_username,
|
|
||||||
'content': '',
|
|
||||||
}
|
|
||||||
|
|
||||||
data = FormData()
|
|
||||||
data.add_field('file', photo_data, filename=photo_name)
|
|
||||||
data.add_field('payload_json', ujson.dumps(send_json))
|
|
||||||
|
|
||||||
await asyncio.sleep(1)
|
|
||||||
status, response = await self._request(
|
|
||||||
request_url=request_url,
|
|
||||||
request_method="POST",
|
|
||||||
request_data=data,
|
|
||||||
)
|
|
||||||
|
|
||||||
if "id" in response:
|
|
||||||
channel_id = response['channel_id']
|
|
||||||
message_id = response['id']
|
|
||||||
|
|
||||||
get_discord_forevercdn = await (
|
|
||||||
DiscordDJ(
|
|
||||||
arSession=self.arSession,
|
|
||||||
bot=self.bot,
|
|
||||||
)
|
|
||||||
).export_forevercdn()
|
|
||||||
|
|
||||||
photo_url = f"{get_discord_forevercdn}/attachments/{channel_id}/{message_id}"
|
|
||||||
|
|
||||||
return True, photo_url
|
|
||||||
|
|
||||||
return False, "None"
|
|
||||||
|
|
||||||
# Запрос
|
|
||||||
async def _request(
|
|
||||||
self,
|
|
||||||
request_url: str,
|
|
||||||
request_method: str,
|
|
||||||
request_data: Optional[Union[Dict[str, Any], FormData]] = None,
|
|
||||||
) -> Tuple[bool, Any]:
|
|
||||||
session = await self.arSession.get_session()
|
|
||||||
|
|
||||||
await asyncio.sleep(1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
response = await session.request(
|
|
||||||
method=request_method,
|
|
||||||
url=request_url,
|
|
||||||
data=request_data,
|
|
||||||
headers={"Accept-Encoding": "gzip, deflate"},
|
|
||||||
)
|
|
||||||
|
|
||||||
response_data = json.loads((await response.read()).decode())
|
|
||||||
|
|
||||||
if response.status == 200:
|
|
||||||
return True, response_data
|
|
||||||
else:
|
|
||||||
await self.error_account_admin(f"{response.status} - {str(response_data)}")
|
|
||||||
|
|
||||||
return False, response_data
|
|
||||||
except ClientConnectorCertificateError:
|
|
||||||
bot_logger.warning("Ошибка SSL при запросе Discord webhook", exc_info=True)
|
|
||||||
await self.error_account_admin("CERTIFICATE_VERIFY_FAILED")
|
|
||||||
|
|
||||||
return False, "CERTIFICATE_VERIFY_FAILED"
|
|
||||||
except Exception as ex:
|
|
||||||
bot_logger.warning("Ошибка запроса Discord webhook", exc_info=True)
|
|
||||||
await self.error_account_admin(str(ex))
|
|
||||||
|
|
||||||
return False, str(ex)
|
|
||||||
|
|
||||||
|
|
||||||
# Извлечение ссылок для работы с локальным АПИ дискорда
|
|
||||||
class DiscordDJ:
|
|
||||||
# Настройка клиента сервисных ссылок Discord
|
|
||||||
def __init__(self, arSession: ARS, bot: Bot):
|
|
||||||
self.arSession = arSession
|
|
||||||
self.bot = bot
|
|
||||||
|
|
||||||
self.const_url = "https://djimbo.dev/autoshop_discord.json"
|
|
||||||
|
|
||||||
# Экспорт публичного дискорд вебхука
|
|
||||||
async def export_webhook(self) -> str:
|
|
||||||
session = await self.arSession.get_session()
|
|
||||||
|
|
||||||
try:
|
|
||||||
response = await session.get(
|
|
||||||
self.const_url,
|
|
||||||
headers={"Accept-Encoding": "gzip, deflate"},
|
|
||||||
)
|
|
||||||
|
|
||||||
response_data = json.loads((await response.read()).decode())
|
|
||||||
except Exception as ex:
|
|
||||||
await send_errors(self.bot, 7729051, f"Error getting Discord Webhook - {ex}")
|
|
||||||
return "None"
|
|
||||||
else:
|
|
||||||
return response_data['webhook']
|
|
||||||
|
|
||||||
# Экспорт ссылки на постоянный CDN
|
|
||||||
async def export_forevercdn(self) -> str:
|
|
||||||
session = await self.arSession.get_session()
|
|
||||||
|
|
||||||
try:
|
|
||||||
response = await session.get(
|
|
||||||
self.const_url,
|
|
||||||
headers={"Accept-Encoding": "gzip, deflate"},
|
|
||||||
)
|
|
||||||
|
|
||||||
response_data = json.loads((await response.read()).decode())
|
|
||||||
except Exception as ex:
|
|
||||||
await send_errors(self.bot, 7729051, f"Error getting Discord ForeverCDN - {ex}")
|
|
||||||
return "None"
|
|
||||||
else:
|
|
||||||
return response_data['forevercdn']
|
|
||||||
@@ -29,13 +29,13 @@ def rkb(text: str) -> KeyboardButton:
|
|||||||
|
|
||||||
# Быстрая сборка inline-кнопки
|
# Быстрая сборка inline-кнопки
|
||||||
def ikb(
|
def ikb(
|
||||||
text: str,
|
text: str,
|
||||||
data: Optional[str] = None,
|
data: Optional[str] = None,
|
||||||
url: Optional[str] = None,
|
url: Optional[str] = None,
|
||||||
switch: Optional[str] = None,
|
switch: Optional[str] = None,
|
||||||
web: Optional[str] = None,
|
web: Optional[str] = None,
|
||||||
copy: Optional[str] = None,
|
copy: Optional[str] = None,
|
||||||
login: Optional[str] = None,
|
login: Optional[str] = None,
|
||||||
) -> InlineKeyboardButton:
|
) -> InlineKeyboardButton:
|
||||||
if data is not None:
|
if data is not None:
|
||||||
return InlineKeyboardButton(text=text, callback_data=data)
|
return InlineKeyboardButton(text=text, callback_data=data)
|
||||||
@@ -61,36 +61,27 @@ async def del_message(message: Message) -> None:
|
|||||||
bot_logger.debug("Не удалось удалить сообщение", exc_info=True)
|
bot_logger.debug("Не удалось удалить сообщение", exc_info=True)
|
||||||
|
|
||||||
|
|
||||||
# Отправка фото или обычного сообщения
|
# Отправка обычного сообщения
|
||||||
async def smart_message(
|
async def smart_message(
|
||||||
bot: Bot,
|
bot: Bot,
|
||||||
user_id: int,
|
user_id: int,
|
||||||
text: str,
|
text: str,
|
||||||
keyboard: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
keyboard: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
||||||
photo: Optional[str] = None,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
if photo is not None and photo.title() != "None":
|
await bot.send_message(
|
||||||
await bot.send_photo(
|
chat_id=user_id,
|
||||||
chat_id=user_id,
|
text=text,
|
||||||
photo=photo,
|
reply_markup=keyboard,
|
||||||
caption=text,
|
)
|
||||||
reply_markup=keyboard,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
await bot.send_message(
|
|
||||||
chat_id=user_id,
|
|
||||||
text=text,
|
|
||||||
reply_markup=keyboard,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Отправка сообщения всем админам
|
# Отправка сообщения всем админам
|
||||||
async def send_admins(
|
async def send_admins(
|
||||||
bot: Bot,
|
bot: Bot,
|
||||||
text: str,
|
text: str,
|
||||||
keyboard: Optional[InlineKeyboardMarkup] = None,
|
keyboard: Optional[InlineKeyboardMarkup] = None,
|
||||||
markup: Optional[InlineKeyboardMarkup] = None,
|
markup: Optional[InlineKeyboardMarkup] = None,
|
||||||
not_me: int = 0,
|
not_me: int = 0,
|
||||||
) -> None:
|
) -> None:
|
||||||
reply_markup = markup or keyboard
|
reply_markup = markup or keyboard
|
||||||
|
|
||||||
@@ -104,7 +95,9 @@ async def send_admins(
|
|||||||
disable_web_page_preview=True,
|
disable_web_page_preview=True,
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
bot_logger.warning("Не удалось отправить сообщение админу %s", admin, exc_info=True)
|
bot_logger.warning(
|
||||||
|
"Не удалось отправить сообщение админу %s", admin, exc_info=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Логирование ошибки и отправка админам
|
# Логирование ошибки и отправка админам
|
||||||
@@ -120,8 +113,10 @@ def ded(get_text: str) -> str:
|
|||||||
if get_text is not None:
|
if get_text is not None:
|
||||||
split_text = get_text.split("\n")
|
split_text = get_text.split("\n")
|
||||||
|
|
||||||
if split_text[0] == "": split_text.pop(0)
|
if split_text[0] == "":
|
||||||
if split_text[-1] == "": split_text.pop()
|
split_text.pop(0)
|
||||||
|
if split_text[-1] == "":
|
||||||
|
split_text.pop()
|
||||||
save_text = []
|
save_text = []
|
||||||
|
|
||||||
for text in split_text:
|
for text in split_text:
|
||||||
@@ -163,7 +158,7 @@ def convert_list(get_lists: List[list]) -> list:
|
|||||||
|
|
||||||
# Разделение списка на части нужного размера
|
# Разделение списка на части нужного размера
|
||||||
def split_list(get_list: list, count: int) -> List[list]:
|
def split_list(get_list: list, count: int) -> List[list]:
|
||||||
return [get_list[i:i + count] for i in range(0, len(get_list), count)]
|
return [get_list[i : i + count] for i in range(0, len(get_list), count)]
|
||||||
|
|
||||||
|
|
||||||
# Старое имя для разделения сообщений
|
# Старое имя для разделения сообщений
|
||||||
@@ -198,9 +193,13 @@ def convert_date(from_time, full=True, second=True) -> Union[str, int]:
|
|||||||
from_timestamp = int(from_time)
|
from_timestamp = int(from_time)
|
||||||
|
|
||||||
if full:
|
if full:
|
||||||
return datetime.fromtimestamp(from_timestamp, bot_timezone).strftime("%d.%m.%Y %H:%M:%S")
|
return datetime.fromtimestamp(from_timestamp, bot_timezone).strftime(
|
||||||
|
"%d.%m.%Y %H:%M:%S"
|
||||||
|
)
|
||||||
if second:
|
if second:
|
||||||
return datetime.fromtimestamp(from_timestamp, bot_timezone).strftime("%d.%m.%Y %H:%M")
|
return datetime.fromtimestamp(from_timestamp, bot_timezone).strftime(
|
||||||
|
"%d.%m.%Y %H:%M"
|
||||||
|
)
|
||||||
|
|
||||||
return datetime.fromtimestamp(from_timestamp, bot_timezone).strftime("%d.%m.%Y")
|
return datetime.fromtimestamp(from_timestamp, bot_timezone).strftime("%d.%m.%Y")
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,13 @@ from typing import Union
|
|||||||
from aiogram import Bot
|
from aiogram import Bot
|
||||||
from aiogram.types import FSInputFile, CallbackQuery, Message
|
from aiogram.types import FSInputFile, CallbackQuery, Message
|
||||||
|
|
||||||
from tgbot.data.config import BOT_DATABASE_EXPORT, BOT_STATUS_NOTIFICATION, BOT_VERSION, PATH_DATABASE, get_admins, \
|
from tgbot.data.config import (
|
||||||
get_text_desc
|
BOT_DATABASE_EXPORT,
|
||||||
|
BOT_STATUS_NOTIFICATION,
|
||||||
|
BOT_VERSION,
|
||||||
|
PATH_DATABASE,
|
||||||
|
get_admins,
|
||||||
|
)
|
||||||
from tgbot.database import Userx, Settingsx
|
from tgbot.database import Userx, Settingsx
|
||||||
from tgbot.utils.const_functions import get_unix, get_date, ded, send_admins
|
from tgbot.utils.const_functions import get_unix, get_date, ded, send_admins
|
||||||
from tgbot.utils.misc.bot_logging import bot_logger
|
from tgbot.utils.misc.bot_logging import bot_logger
|
||||||
@@ -40,9 +45,17 @@ async def autosettings_unix():
|
|||||||
now_month = datetime.now().month
|
now_month = datetime.now().month
|
||||||
now_year = datetime.now().year
|
now_year = datetime.now().year
|
||||||
|
|
||||||
unix_day = int(datetime.strptime(f"{now_day}.{now_month}.{now_year} 0:0:0", "%d.%m.%Y %H:%M:%S").timestamp())
|
unix_day = int(
|
||||||
|
datetime.strptime(
|
||||||
|
f"{now_day}.{now_month}.{now_year} 0:0:0", "%d.%m.%Y %H:%M:%S"
|
||||||
|
).timestamp()
|
||||||
|
)
|
||||||
unix_week = unix_day - (now_week * 86400)
|
unix_week = unix_day - (now_week * 86400)
|
||||||
unix_month = int(datetime.strptime(f"1.{now_month}.{now_year} 0:0:0", "%d.%m.%Y %H:%M:%S").timestamp())
|
unix_month = int(
|
||||||
|
datetime.strptime(
|
||||||
|
f"1.{now_month}.{now_year} 0:0:0", "%d.%m.%Y %H:%M:%S"
|
||||||
|
).timestamp()
|
||||||
|
)
|
||||||
|
|
||||||
await Settingsx().update(
|
await Settingsx().update(
|
||||||
misc_profit_day=unix_day,
|
misc_profit_day=unix_day,
|
||||||
@@ -68,8 +81,6 @@ async def startup_notify(bot: Bot, arSession: ARS):
|
|||||||
ded(f"""
|
ded(f"""
|
||||||
<b>✅ Бот был успешно запущен</b>
|
<b>✅ Бот был успешно запущен</b>
|
||||||
➖➖➖➖➖➖➖➖➖➖
|
➖➖➖➖➖➖➖➖➖➖
|
||||||
{get_text_desc()}
|
|
||||||
➖➖➖➖➖➖➖➖➖➖
|
|
||||||
<code>❗ Данное сообщение видят только администраторы бота.</code>
|
<code>❗ Данное сообщение видят только администраторы бота.</code>
|
||||||
"""),
|
"""),
|
||||||
)
|
)
|
||||||
@@ -91,7 +102,9 @@ async def autobackup_admin(bot: Bot):
|
|||||||
disable_notification=True,
|
disable_notification=True,
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
bot_logger.warning("Не удалось отправить автобэкап админу %s", admin, exc_info=True)
|
bot_logger.warning(
|
||||||
|
"Не удалось отправить автобэкап админу %s", admin, exc_info=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Проверка наличия обновлений бота
|
# Проверка наличия обновлений бота
|
||||||
@@ -106,7 +119,7 @@ async def check_update(bot: Bot, arSession: ARS):
|
|||||||
|
|
||||||
response_data = json.loads((await response.read()).decode())
|
response_data = json.loads((await response.read()).decode())
|
||||||
|
|
||||||
if float(response_data['version']) > float(BOT_VERSION):
|
if float(response_data["version"]) > float(BOT_VERSION):
|
||||||
await send_admins(
|
await send_admins(
|
||||||
bot,
|
bot,
|
||||||
ded(f"""
|
ded(f"""
|
||||||
@@ -132,7 +145,7 @@ async def check_mail(bot: Bot, arSession: ARS):
|
|||||||
)
|
)
|
||||||
response_data = json.loads((await response.read()).decode())
|
response_data = json.loads((await response.read()).decode())
|
||||||
|
|
||||||
if response_data['status']:
|
if response_data["status"]:
|
||||||
await send_admins(
|
await send_admins(
|
||||||
bot,
|
bot,
|
||||||
ded(f"""
|
ded(f"""
|
||||||
@@ -176,21 +189,23 @@ async def functions_mail_make(bot: Bot, message: Message, call: CallbackQuery):
|
|||||||
users_receive += 1
|
users_receive += 1
|
||||||
except Exception:
|
except Exception:
|
||||||
users_block += 1
|
users_block += 1
|
||||||
bot_logger.debug("Пользователь %s не получил рассылку", user.user_id, exc_info=True)
|
bot_logger.debug(
|
||||||
|
"Пользователь %s не получил рассылку", user.user_id, exc_info=True
|
||||||
|
)
|
||||||
|
|
||||||
users_count += 1
|
users_count += 1
|
||||||
|
|
||||||
if users_count % 10 == 0:
|
if users_count % 10 == 0:
|
||||||
await call.message.edit_text(f"<b>📢 Рассылка началась... ({users_count}/{len(get_users)})</b>")
|
await call.message.edit_text(
|
||||||
|
f"<b>📢 Рассылка началась... ({users_count}/{len(get_users)})</b>"
|
||||||
|
)
|
||||||
|
|
||||||
await asyncio.sleep(0.07)
|
await asyncio.sleep(0.07)
|
||||||
|
|
||||||
await call.message.edit_text(
|
await call.message.edit_text(ded(f"""
|
||||||
ded(f"""
|
|
||||||
<b>📢 Рассылка была завершена за <code>{get_unix() - get_time}сек</code></b>
|
<b>📢 Рассылка была завершена за <code>{get_unix() - get_time}сек</code></b>
|
||||||
➖➖➖➖➖➖➖➖➖➖
|
➖➖➖➖➖➖➖➖➖➖
|
||||||
👤 Всего пользователей: <code>{len(get_users)}</code>
|
👤 Всего пользователей: <code>{len(get_users)}</code>
|
||||||
✅ Пользователей получило сообщение: <code>{users_receive}</code>
|
✅ Пользователей получило сообщение: <code>{users_receive}</code>
|
||||||
❌ Пользователей не получило сообщение: <code>{users_block}</code>
|
❌ Пользователей не получило сообщение: <code>{users_block}</code>
|
||||||
""")
|
"""))
|
||||||
)
|
|
||||||
|
|||||||
+100
-30
@@ -21,7 +21,11 @@ from tgbot.database import (
|
|||||||
ModelUser,
|
ModelUser,
|
||||||
)
|
)
|
||||||
from tgbot.keyboards.inline_admin import profile_edit_finl
|
from tgbot.keyboards.inline_admin import profile_edit_finl
|
||||||
from tgbot.keyboards.inline_admin_products import position_edit_open_finl, category_edit_open_finl, item_delete_finl
|
from tgbot.keyboards.inline_admin_products import (
|
||||||
|
position_edit_open_finl,
|
||||||
|
category_edit_open_finl,
|
||||||
|
item_delete_finl,
|
||||||
|
)
|
||||||
from tgbot.keyboards.inline_user import user_profile_finl
|
from tgbot.keyboards.inline_user import user_profile_finl
|
||||||
from tgbot.keyboards.inline_user_products import products_open_finl
|
from tgbot.keyboards.inline_user_products import products_open_finl
|
||||||
from tgbot.services.api_hosting_text import HostingAPI
|
from tgbot.services.api_hosting_text import HostingAPI
|
||||||
@@ -68,7 +72,7 @@ async def position_open_user(bot: Bot, user_id: int, position_id: int, remover:
|
|||||||
await bot.send_message(
|
await bot.send_message(
|
||||||
chat_id=user_id,
|
chat_id=user_id,
|
||||||
text=ded(f"""
|
text=ded(f"""
|
||||||
<b>🎁 Покупка товара</b>{hide_link(get_position.position_photo)}
|
<b>🎁 Покупка товара</b>
|
||||||
➖➖➖➖➖➖➖➖➖➖
|
➖➖➖➖➖➖➖➖➖➖
|
||||||
▪️ Название: <code>{get_position.position_name}</code>
|
▪️ Название: <code>{get_position.position_name}</code>
|
||||||
▪️ Категория: <code>{get_category.category_name}</code>
|
▪️ Категория: <code>{get_category.category_name}</code>
|
||||||
@@ -78,7 +82,6 @@ async def position_open_user(bot: Bot, user_id: int, position_id: int, remover:
|
|||||||
"""),
|
"""),
|
||||||
link_preview_options=LinkPreviewOptions(show_above_text=True),
|
link_preview_options=LinkPreviewOptions(show_above_text=True),
|
||||||
reply_markup=products_open_finl(position_id, get_position.category_id, remover),
|
reply_markup=products_open_finl(position_id, get_position.category_id, remover),
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -114,7 +117,7 @@ async def open_profile_admin(bot: Bot, user_id: int, get_user: ModelUser):
|
|||||||
async def refill_open_admin(bot: Bot, user_id: int, get_refill: ModelRefill):
|
async def refill_open_admin(bot: Bot, user_id: int, get_refill: ModelRefill):
|
||||||
get_user = await Userx().get_required(user_id=get_refill.user_id)
|
get_user = await Userx().get_required(user_id=get_refill.user_id)
|
||||||
|
|
||||||
if get_refill.refill_method in ['Form', 'Nickname', 'Number', 'QIWI']:
|
if get_refill.refill_method in ["Form", "Nickname", "Number", "QIWI"]:
|
||||||
pay_method = "QIWI 🥝"
|
pay_method = "QIWI 🥝"
|
||||||
elif get_refill.refill_method == "Yoomoney":
|
elif get_refill.refill_method == "Yoomoney":
|
||||||
pay_method = "ЮMoney 🔮"
|
pay_method = "ЮMoney 🔮"
|
||||||
@@ -138,7 +141,9 @@ async def refill_open_admin(bot: Bot, user_id: int, get_refill: ModelRefill):
|
|||||||
|
|
||||||
|
|
||||||
# Открытие покупки админом
|
# Открытие покупки админом
|
||||||
async def purchase_open_admin(bot: Bot, arSession: ARS, user_id: int, get_purchase: ModelPurchases):
|
async def purchase_open_admin(
|
||||||
|
bot: Bot, arSession: ARS, user_id: int, get_purchase: ModelPurchases
|
||||||
|
):
|
||||||
get_user = await Userx().get_required(user_id=get_purchase.user_id)
|
get_user = await Userx().get_required(user_id=get_purchase.user_id)
|
||||||
|
|
||||||
link_items = await (
|
link_items = await (
|
||||||
@@ -172,8 +177,18 @@ async def purchase_open_admin(bot: Bot, arSession: ARS, user_id: int, get_purcha
|
|||||||
|
|
||||||
# Открытие категории админом
|
# Открытие категории админом
|
||||||
async def category_open_admin(bot: Bot, user_id: int, category_id: int, remover: int):
|
async def category_open_admin(bot: Bot, user_id: int, category_id: int, remover: int):
|
||||||
profit_amount_all, profit_amount_day, profit_amount_week, profit_amount_month = 0, 0, 0, 0
|
profit_amount_all, profit_amount_day, profit_amount_week, profit_amount_month = (
|
||||||
profit_count_all, profit_count_day, profit_count_week, profit_count_month = 0, 0, 0, 0
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
profit_count_all, profit_count_day, profit_count_week, profit_count_month = (
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
|
||||||
get_items = await Itemx().gets(category_id=category_id)
|
get_items = await Itemx().gets(category_id=category_id)
|
||||||
get_category = await Categoryx().get_required(category_id=category_id)
|
get_category = await Categoryx().get_required(category_id=category_id)
|
||||||
@@ -217,8 +232,18 @@ async def category_open_admin(bot: Bot, user_id: int, category_id: int, remover:
|
|||||||
|
|
||||||
# Открытие позиции админом
|
# Открытие позиции админом
|
||||||
async def position_open_admin(bot: Bot, position_id: int, user_id: int):
|
async def position_open_admin(bot: Bot, position_id: int, user_id: int):
|
||||||
profit_amount_all, profit_amount_day, profit_amount_week, profit_amount_month = 0, 0, 0, 0
|
profit_amount_all, profit_amount_day, profit_amount_week, profit_amount_month = (
|
||||||
profit_count_all, profit_count_day, profit_count_week, profit_count_month = 0, 0, 0, 0
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
profit_count_all, profit_count_day, profit_count_week, profit_count_month = (
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
|
||||||
get_items = await Itemx().gets(position_id=position_id)
|
get_items = await Itemx().gets(position_id=position_id)
|
||||||
get_position = await Positionx().get_required(position_id=position_id)
|
get_position = await Positionx().get_required(position_id=position_id)
|
||||||
@@ -227,12 +252,6 @@ async def position_open_admin(bot: Bot, position_id: int, user_id: int):
|
|||||||
get_settings = await Settingsx().get()
|
get_settings = await Settingsx().get()
|
||||||
get_purchases = await Purchasesx().gets(purchase_position_id=position_id)
|
get_purchases = await Purchasesx().gets(purchase_position_id=position_id)
|
||||||
|
|
||||||
# Наличие фото
|
|
||||||
if get_position.position_photo != "None":
|
|
||||||
position_photo_text = "<code>Присутствует ✅</code>"
|
|
||||||
else:
|
|
||||||
position_photo_text = "<code>Отсутствует ❌</code>"
|
|
||||||
|
|
||||||
# Наличие описания
|
# Наличие описания
|
||||||
if get_position.position_desc != "None":
|
if get_position.position_desc != "None":
|
||||||
position_desc = f"{get_position.position_desc}"
|
position_desc = f"{get_position.position_desc}"
|
||||||
@@ -257,14 +276,13 @@ async def position_open_admin(bot: Bot, position_id: int, user_id: int):
|
|||||||
await bot.send_message(
|
await bot.send_message(
|
||||||
chat_id=user_id,
|
chat_id=user_id,
|
||||||
text=ded(f"""
|
text=ded(f"""
|
||||||
<b>📁 Редактирование позиции</b>{hide_link(get_position.position_photo)}
|
<b>📁 Редактирование позиции</b>
|
||||||
➖➖➖➖➖➖➖➖➖➖
|
➖➖➖➖➖➖➖➖➖➖
|
||||||
▪️ Категория: <code>{get_category.category_name}</code>
|
▪️ Категория: <code>{get_category.category_name}</code>
|
||||||
▪️ Позиция: <code>{get_position.position_name}</code>
|
▪️ Позиция: <code>{get_position.position_name}</code>
|
||||||
▪️ Стоимость: <code>{get_position.position_price}₽</code>
|
▪️ Стоимость: <code>{get_position.position_price}₽</code>
|
||||||
▪️ Количество: <code>{len(get_items)}шт</code>
|
▪️ Количество: <code>{len(get_items)}шт</code>
|
||||||
▪️ Дата создания: <code>{convert_date(get_category.category_unix)}</code>
|
▪️ Дата создания: <code>{convert_date(get_category.category_unix)}</code>
|
||||||
▪️ Изображение: {position_photo_text}
|
|
||||||
▪️ Описание: {position_desc}
|
▪️ Описание: {position_desc}
|
||||||
|
|
||||||
💸 Продаж за День: <code>{profit_count_day}шт</code> - <code>{round(profit_amount_day, 2)}₽</code>
|
💸 Продаж за День: <code>{profit_count_day}шт</code> - <code>{round(profit_amount_day, 2)}₽</code>
|
||||||
@@ -274,7 +292,6 @@ async def position_open_admin(bot: Bot, position_id: int, user_id: int):
|
|||||||
"""),
|
"""),
|
||||||
link_preview_options=LinkPreviewOptions(show_above_text=True),
|
link_preview_options=LinkPreviewOptions(show_above_text=True),
|
||||||
reply_markup=await position_edit_open_finl(bot, position_id, 0),
|
reply_markup=await position_edit_open_finl(bot, position_id, 0),
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -303,11 +320,38 @@ async def item_open_admin(bot: Bot, item_id: int, user_id: int):
|
|||||||
################################################################################
|
################################################################################
|
||||||
# Статистика бота
|
# Статистика бота
|
||||||
async def get_statistics() -> str:
|
async def get_statistics() -> str:
|
||||||
refill_amount_all, refill_amount_day, refill_amount_week, refill_amount_month = 0, 0, 0, 0
|
refill_amount_all, refill_amount_day, refill_amount_week, refill_amount_month = (
|
||||||
refill_count_all, refill_count_day, refill_count_week, refill_count_month = 0, 0, 0, 0
|
0,
|
||||||
profit_amount_all, profit_amount_day, profit_amount_week, profit_amount_month = 0, 0, 0, 0
|
0,
|
||||||
profit_count_all, profit_count_day, profit_count_week, profit_count_month = 0, 0, 0, 0
|
0,
|
||||||
users_all, users_day, users_week, users_month, users_money_have, users_money_give = 0, 0, 0, 0, 0, 0
|
0,
|
||||||
|
)
|
||||||
|
refill_count_all, refill_count_day, refill_count_week, refill_count_month = (
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
profit_amount_all, profit_amount_day, profit_amount_week, profit_amount_month = (
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
profit_count_all, profit_count_day, profit_count_week, profit_count_month = (
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
(
|
||||||
|
users_all,
|
||||||
|
users_day,
|
||||||
|
users_week,
|
||||||
|
users_month,
|
||||||
|
users_money_have,
|
||||||
|
users_money_give,
|
||||||
|
) = (0, 0, 0, 0, 0, 0)
|
||||||
refill_cryptobot_count, refill_cryptobot_amount = 0, 0
|
refill_cryptobot_count, refill_cryptobot_amount = 0, 0
|
||||||
refill_yoomoney_count, refill_yoomoney_amount = 0, 0
|
refill_yoomoney_count, refill_yoomoney_amount = 0, 0
|
||||||
refill_stars_count, refill_stars_amount = 0, 0
|
refill_stars_count, refill_stars_amount = 0, 0
|
||||||
@@ -375,12 +419,28 @@ async def get_statistics() -> str:
|
|||||||
|
|
||||||
# Даты обновления статистики
|
# Даты обновления статистики
|
||||||
all_days = [
|
all_days = [
|
||||||
'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье',
|
"Понедельник",
|
||||||
|
"Вторник",
|
||||||
|
"Среда",
|
||||||
|
"Четверг",
|
||||||
|
"Пятница",
|
||||||
|
"Суббота",
|
||||||
|
"Воскресенье",
|
||||||
]
|
]
|
||||||
|
|
||||||
all_months = [
|
all_months = [
|
||||||
'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь',
|
"Январь",
|
||||||
'Октябрь', 'Ноябрь', 'Декабрь'
|
"Февраль",
|
||||||
|
"Март",
|
||||||
|
"Апрель",
|
||||||
|
"Май",
|
||||||
|
"Июнь",
|
||||||
|
"Июль",
|
||||||
|
"Август",
|
||||||
|
"Сентябрь",
|
||||||
|
"Октябрь",
|
||||||
|
"Ноябрь",
|
||||||
|
"Декабрь",
|
||||||
]
|
]
|
||||||
|
|
||||||
now_day = datetime.now().day
|
now_day = datetime.now().day
|
||||||
@@ -388,12 +448,22 @@ async def get_statistics() -> str:
|
|||||||
now_month = datetime.now().month
|
now_month = datetime.now().month
|
||||||
now_year = datetime.now().year
|
now_year = datetime.now().year
|
||||||
|
|
||||||
unix_day = int(datetime.strptime(f"{now_day}.{now_month}.{now_year} 0:0:0", "%d.%m.%Y %H:%M:%S").timestamp())
|
unix_day = int(
|
||||||
|
datetime.strptime(
|
||||||
|
f"{now_day}.{now_month}.{now_year} 0:0:0", "%d.%m.%Y %H:%M:%S"
|
||||||
|
).timestamp()
|
||||||
|
)
|
||||||
unix_week = unix_day - (now_week * 86400)
|
unix_week = unix_day - (now_week * 86400)
|
||||||
|
|
||||||
week_day = int(datetime.fromtimestamp(unix_week, pytz.timezone(BOT_TIMEZONE)).strftime("%d"))
|
week_day = int(
|
||||||
week_month = int(datetime.fromtimestamp(unix_week, pytz.timezone(BOT_TIMEZONE)).strftime("%m"))
|
datetime.fromtimestamp(unix_week, pytz.timezone(BOT_TIMEZONE)).strftime("%d")
|
||||||
week_week = int(datetime.fromtimestamp(unix_week, pytz.timezone(BOT_TIMEZONE)).weekday())
|
)
|
||||||
|
week_month = int(
|
||||||
|
datetime.fromtimestamp(unix_week, pytz.timezone(BOT_TIMEZONE)).strftime("%m")
|
||||||
|
)
|
||||||
|
week_week = int(
|
||||||
|
datetime.fromtimestamp(unix_week, pytz.timezone(BOT_TIMEZONE)).weekday()
|
||||||
|
)
|
||||||
|
|
||||||
return ded(f"""
|
return ded(f"""
|
||||||
<b>📊 СТАТИСТИКА БОТА</b>
|
<b>📊 СТАТИСТИКА БОТА</b>
|
||||||
|
|||||||
Reference in New Issue
Block a user